A Pen by chris-creditdesign on CodePen.
Created
November 11, 2014 13:08
-
-
Save chris-creditdesign/7589b606444cfef15f48 to your computer and use it in GitHub Desktop.
A Pen by chris-creditdesign.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="outer-wrapper" id="graphic"> | |
<div class="chart"></div> | |
<div class="key" id="key"></div> | |
</div> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function buildData () { | |
var myArray = []; | |
for (var i = 0; i < 500; i++) { | |
myObject = {}; | |
myObject.xValue = Math.random() * 100; | |
myObject.yValue = Math.random() * 100; | |
myObject.name = [myObject.xValue, myObject.yValue].toString(); | |
myArray.push(myObject); | |
} | |
return myArray; | |
} | |
function buildParams () { | |
var params = {}; | |
/* Margin, Width and height */ | |
params.margin = {top: 20, right: 20, mid: 30, bottom: 50, left: 50}; | |
params.brushThickness = 60; | |
params.width = $('.outer-wrapper').width() - params.margin.left - params.brushThickness - params.margin.mid - params.margin.right; | |
params.height = $('.outer-wrapper').width() - params.margin.top - params.margin.mid - params.brushThickness - params.margin.bottom; | |
/* Global variable to control the length of D3 transitons */ | |
params.duration = 450; | |
params.delay = 450; | |
return params; | |
} | |
function BuildWidget (target, params, data) { | |
this.target = target; | |
this.params = params; | |
this.data = data; | |
} | |
BuildWidget.prototype.buildGraphic = function () { | |
this.svg = d3.select(this.target + " > .chart").append("svg") | |
.attr("width", this.params.width + this.params.margin.left + this.params.brushThickness + this.params.margin.mid + this.params.margin.right) | |
.attr("height", this.params.height + this.params.margin.top + this.params.brushThickness + this.params.margin.mid + this.params.margin.bottom); | |
var clip = this.svg.append("defs").append("svg:clipPath") | |
.attr("id", "clip") | |
.append("svg:rect") | |
.attr("x", 0) | |
.attr("y", 0) | |
.attr("width", this.params.width) | |
.attr("height", this.params.height); | |
var miniClip = this.svg.append("defs").append("svg:clipPath") | |
.attr("id", "mini-clip") | |
.append("svg:rect") | |
.attr("x", 0) | |
.attr("y", 0) | |
.attr("width", this.params.brushThickness) | |
.attr("height", this.params.brushThickness); | |
this.scatterGroup = this.svg.append("g") | |
.attr("class","scatterGroup") | |
.attr("clip-path", "url(#clip)") | |
.attr("transform","translate(" + (this.params.margin.left + this.params.brushThickness + this.params.margin.mid) + "," + this.params.margin.top + ")"); | |
this.xBrushGroup = this.svg.append("g") | |
.attr("class","xBrushGroup") | |
.attr("transform","translate(" + (this.params.margin.left + this.params.brushThickness + this.params.margin.mid) + "," + (this.params.margin.top + this.params.height + this.params.margin.mid)+ ")"); | |
this.yBrushGroup = this.svg.append("g") | |
.attr("class","yBrushGroup") | |
.attr("transform","translate(" + this.params.margin.left + "," + this.params.margin.top + ")"); | |
this.miniMapGroup = this.svg.append("g") | |
.attr("class","miniMapGroup") | |
.attr("clip-path", "url(#mini-clip)") | |
.attr("transform","translate(" + this.params.margin.left + "," + (this.params.margin.top + this.params.height + this.params.margin.mid) + ")"); | |
this.miniMapGroup.append("rect") | |
.attr("x", 0) | |
.attr("y", 0) | |
.attr("width", this.params.brushThickness) | |
.attr("height", this.params.brushThickness) | |
.attr("fill","#eee") | |
.attr("stroke","none"); | |
this.mapperGroup = this.svg.append("g") | |
.attr("class","miniMapGroup") | |
.attr("transform","translate(" + this.params.margin.left + "," + (this.params.margin.top + this.params.height + this.params.margin.mid) + ")"); | |
}; | |
BuildWidget.prototype.buildScales = function () { | |
this.yScale = d3.scale.linear() | |
.range([this.params.height, 0]) | |
.domain([0,100]); | |
this.yBrushScale = d3.scale.linear() | |
.range([this.params.height, 0]) | |
.domain([0,100]); | |
this.xScale = d3.scale.linear() | |
.range([0, this.params.width]) | |
.domain([0,100]); | |
this.xBrushScale = d3.scale.linear() | |
.range([0, this.params.width]) | |
.domain([0,100]); | |
this.yMiniMapScale = d3.scale.linear() | |
.range([this.params.brushThickness, 0]) | |
.domain([0,100]); | |
this.yMiniMapInvertScale = d3.scale.linear() | |
.range([this.params.brushThickness, 0]) | |
.domain([100,0]); | |
this.xMiniMapScale = d3.scale.linear() | |
.range([0, this.params.brushThickness]) | |
.domain([0,100]); | |
}; | |
BuildWidget.prototype.buildAxes = function () { | |
this.yAxis = d3.svg.axis() | |
.scale(this.yScale) | |
.tickSize(3,0) | |
.orient("left"); | |
this.xAxis = d3.svg.axis() | |
.scale(this.xScale) | |
.tickSize(3,0) | |
.orient("bottom"); | |
/* Prepare the y axis */ | |
this.svg.append("g") | |
.attr("class", "y axis") | |
.attr("transform", "translate(" + (this.params.margin.left + this.params.brushThickness + this.params.margin.mid) + "," + this.params.margin.top + ")") | |
.call(this.yAxis); | |
this.svg.append("g") | |
.attr("class", "y-brush axis") | |
.attr("transform", "translate(" + this.params.margin.left + "," + this.params.margin.top + ")") | |
.call(this.yAxis) | |
.append("g") | |
.attr("class", "axisLabel") | |
.append("text") | |
.attr("transform", "translate(" + -(this.params.margin.left * 0.6) + "," + (this.params.height / 2) + "), rotate(-90)") | |
.style("text-anchor", "middle") | |
.text("Y Axis"); | |
/* Prepare the x axis */ | |
this.svg.append("g") | |
.attr("class", "x axis") | |
.attr("transform", "translate(" + (this.params.margin.left + this.params.brushThickness + this.params.margin.mid) + "," + (this.params.margin.top + this.params.height) + ")") | |
.call(this.xAxis) | |
this.svg.append("g") | |
.attr("class", "x-brush axis") | |
.attr("transform", "translate(" + (this.params.margin.left + this.params.brushThickness + this.params.margin.mid) + "," + (this.params.margin.top + this.params.height + this.params.margin.mid + this.params.brushThickness) + ")") | |
.call(this.xAxis) | |
.append("g") | |
.attr("class","axisLabel") | |
.append("text") | |
.attr("transform", "translate(" + (this.params.width / 2) + "," + (this.params.margin.bottom * 0.7) + ")") | |
.style("text-anchor","middle") | |
.text("X Axis"); | |
}; | |
BuildWidget.prototype.buildBrush = function () { | |
var self = this; | |
var updateView = function () { | |
self.updateScatterPlot(); | |
self.svg.selectAll(".x.axis").call(self.xAxis); | |
self.svg.selectAll(".y.axis").call(self.yAxis); | |
self.updateMiniMap(xBrush.extent(), yBrush.extent()); | |
}; | |
var xDisplay = function () { | |
var extent = xBrush.extent(); | |
self.xScale.domain(extent); | |
updateView(); | |
}; | |
var xBrushend = function () { | |
if (xBrush.extent()[0] === xBrush.extent()[1]) { | |
d3.select(this).call(xBrush.extent([0, 100])); | |
self.xScale.domain([0,100]); | |
updateView(); | |
} | |
}; | |
var yDisplay = function () { | |
var extent = yBrush.extent(); | |
self.yScale.domain(extent); | |
updateView(); | |
}; | |
var yBrushend = function () { | |
if (yBrush.extent()[0] === yBrush.extent()[1]) { | |
d3.select(this).call(yBrush.extent([0, 100])); | |
self.yScale.domain([0,100]); | |
updateView(); | |
} | |
}; | |
var xBrush = d3.svg.brush() | |
.x(this.xBrushScale) | |
.extent([0, 100]) | |
.on("brush", xDisplay) | |
.on("brushend", xBrushend); | |
var yBrush = d3.svg.brush() | |
.y(this.yBrushScale) | |
.extent([0,100]) | |
.on("brush", yDisplay) | |
.on("brushend", yBrushend) | |
this.xBrushGroup.append("g") | |
.attr("class", "brush") | |
.call(xBrush) | |
.selectAll("rect") | |
.attr("fill","#999") | |
.attr("height", this.params.brushThickness ); | |
this.yBrushGroup.append("g") | |
.attr("class", "brush") | |
.call(yBrush) | |
.selectAll("rect") | |
.attr("fill", "#999") | |
.attr("width", this.params.brushThickness) | |
}; | |
BuildWidget.prototype.enterScatterPlot = function (target, main) { | |
var self = this; | |
target.selectAll("circle") | |
.data(this.data, function (d) { | |
return d.name; | |
}) | |
.enter() | |
.append("circle") | |
.attr("cx", function (d) { | |
return main ? self.xScale(d.xValue) : self.xMiniMapScale(d.xValue); | |
}) | |
.attr("cy", function (d) { | |
return main ? self.yScale(d.yValue) : self.yMiniMapScale(d.yValue); | |
}) | |
.attr("r", function () { | |
return main ? (Math.random() * 8) : 0.5; | |
}) | |
.attr("opacity", 1) | |
.attr("fill", function(d,i) { | |
var deg = i * 10; | |
return "hsl(" + deg + ", 50%, 50%)"; | |
}); | |
}; | |
BuildWidget.prototype.updateScatterPlot = function () { | |
var self = this; | |
this.scatterGroup.selectAll("circle") | |
.attr("cx", function (d) { | |
return self.xScale(d.xValue); | |
}) | |
.attr("cy", function (d) { | |
return self.yScale(d.yValue); | |
}); | |
}; | |
BuildWidget.prototype.buildMiniMap = function () { | |
this.mapper = this.mapperGroup.append("rect") | |
.attr("x", 0) | |
.attr("y", 0) | |
.attr("width", this.params.brushThickness) | |
.attr("height", this.params.brushThickness) | |
.attr("fill","none") | |
.attr("stroke","#333") | |
.attr("storke-width","1px"); | |
}; | |
BuildWidget.prototype.updateMiniMap = function(x, y) { | |
var self = this; | |
this.mapper | |
.attr("x", function() { | |
return self.xMiniMapScale(x[0]); | |
}) | |
.attr("y", function() { | |
var top = 100 - y[1] | |
return self.yMiniMapInvertScale(top); | |
}) | |
.attr("width", function () { | |
var width = x[1] - x[0]; | |
return self.xMiniMapScale(width); | |
}) | |
.attr("height", function () { | |
var height = y[1] - y[0]; | |
return self.yMiniMapInvertScale(height); | |
}); | |
}; | |
function init () { | |
var params = buildParams(); | |
var graphicData = buildData(); | |
var graphic = new BuildWidget("#graphic", params, graphicData); | |
graphic.buildGraphic(); | |
graphic.buildScales(); | |
graphic.buildAxes(); | |
graphic.buildBrush(); | |
graphic.enterScatterPlot(graphic.scatterGroup, true); | |
graphic.enterScatterPlot(graphic.miniMapGroup, false); | |
graphic.buildMiniMap(); | |
} | |
$( document ).ready( init ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.outer-wrapper { | |
width: 600px; | |
position: relative; | |
border: 1px solid #c8c7cf; | |
.axis{ | |
path, line { | |
fill: none; | |
stroke: #666; | |
shape-rendering: crispEdges; | |
} | |
text { | |
font-family: sans-serif; | |
fill: #666; | |
font-size: 13px; | |
shape-rendering: crispEdges; | |
} // SVG | |
} | |
.key { | |
margin-left: 30px; | |
} | |
.palette { | |
border-left: 20px solid; | |
padding-left: 4px; | |
display: inline-block; | |
margin: 10px; | |
} | |
} // outerwrapper |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment