Reputation: 141
My objective is to draw a graph which has line and dots.
I was able to draw line and dots with zoom and brush but the problem is, when i zoom in or zoom out, the dots are not moving according to zoom.
I am relatively new to D3 graph. Below is the code i have used to plot dots:
g.selectAll(".dot")
.data(dots)
.enter()
.append("circle")
.attr("class", "dot")
.attr("r", 3.5)
.attr("cx", function(d) { return x(new Date(d.date)); })
.attr("cy", function(d) { return y(d.price); })
.on("mouseover", function(d){
return tooltip.style("visibility", "visible").html("Expected value is: "+d.expected_value + "<br/>" + "value : "+d.close +"<br/>" + "deviation is: "+d.deviation_expected)
})
.on("mousemove", function(){return tooltip.style("top", (event.pageY-10)+"px").style("left",(event.pageX+10)+"px");})
.on("mouseout", function(){return tooltip.style("visibility", "hidden");});
I have created jsfiddle
Please help.
Upvotes: 0
Views: 1031
Reputation: 3195
I will describe few basic features you must understand before approaching visualization. As per the fiddle, you have two sets of data that must be plotted across X & Y axis.(Ex: data, dots). Domain for this data sets are different though you need to understand the concept of Domain and range.
d3.scaleLinear() <>
Constructs a new continuous scale with the unit domain [0, 1], the unit range [0, 1], the default interpolator and clamping disabled. Linear scales are a good default choice for continuous quantitative data because they preserve proportional differences. Each range value y can be expressed as a function of the domain value x: y = mx + b.
d3.scaleTime() <>
Constructs a new time scale with the domain [2000-01-01, 2000-01-02], the unit range [0, 1], the default interpolator and clamping disabled.
** Below code snippet is just to explain the brush implementation with out considering the scale for dots. Try it your self to map the logic by reading the documentation Brush Event Example
var data = [{
"date": "2017-04-22T11:45:00.000Z",
"total": 731.6047915220261,
"min": 1.8769680261611938,
"key_field": "1492861500000",
"max": 2.7165653705596924,
"price": 1.8769680261611938,
"total_count": 315,
"mean": 2.3225548937207177,
"count": 315
},
{
"date": "2017-04-01T05:30:00.000Z",
"total": 708.6527144908905,
"min": 1.779407262802124,
"key_field": "1491024600000",
"max": 2.6382412910461426,
"price": 1.779407262802124,
"total_count": 315,
"mean": 2.249691157113938,
"count": 315
},
{
"date": "2017-03-31T02:45:00.000Z",
"total": 700.1026722192764,
"min": 1.8156663179397583,
"key_field": "1490928300000",
"max": 2.587003469467163,
"price": 1.8156663179397583,
"total_count": 315,
"mean": 2.2225481657754806,
"count": 315
},
{
"date": "2017-03-31T02:30:00.000Z",
"total": 699.6637561321259,
"min": 1.8294581174850464,
"key_field": "1490927400000",
"max": 2.57082200050354,
"price": 1.8294581174850464,
"total_count": 315,
"mean": 2.221154781371828,
"count": 315
},
{
"date": "2017-03-31T02:15:00.000Z",
"total": 702.4780179262161,
"min": 1.8524492979049683,
"key_field": "1490926500000",
"max": 2.628413677215576,
"price": 1.8524492979049683,
"total_count": 315,
"mean": 2.2300889457975117,
"count": 315
},
{
"date": "2017-03-31T02:00:00.000Z",
"total": 705.038315653801,
"min": 1.8353750705718994,
"key_field": "1490925600000",
"max": 2.604921340942383,
"price": 1.8353750705718994,
"total_count": 315,
"mean": 2.2382168750914317,
"count": 315
},
{
"date": "2017-03-31T01:45:00.000Z",
"total": 701.7422981262207,
"min": 1.8062856197357178,
"key_field": "1490924700000",
"max": 2.5804450511932373,
"price": 1.8062856197357178,
"total_count": 315,
"mean": 2.2277533273848276,
"count": 315
},
{
"date": "2017-03-31T01:30:00.000Z",
"total": 706.3951338529587,
"min": 1.8176854848861694,
"key_field": "1490923800000",
"max": 2.584993600845337,
"price": 1.8176854848861694,
"total_count": 315,
"mean": 2.242524234453837,
"count": 315
},
{
"date": "2017-03-31T01:15:00.000Z",
"total": 704.2638461589813,
"min": 1.7730687856674194,
"key_field": "1490922900000",
"max": 2.6350574493408203,
"price": 1.7730687856674194,
"total_count": 315,
"mean": 2.235758241774544,
"count": 315
},
{
"date": "2017-03-31T01:00:00.000Z",
"total": 703.4522807598114,
"min": 1.8147484064102173,
"key_field": "1490922000000",
"max": 2.5720791816711426,
"price": 1.8147484064102173,
"total_count": 315,
"mean": 2.233181843681941,
"count": 315
},
{
"date": "2017-03-31T00:45:00.000Z",
"total": 706.2918384075165,
"min": 1.7760894298553467,
"key_field": "1490921100000",
"max": 2.596073627471924,
"price": 1.7760894298553467,
"total_count": 315,
"mean": 2.2421963124048143,
"count": 315
},
{
"date": "2017-03-31T00:30:00.000Z",
"total": 707.0961575508118,
"min": 1.7756011486053467,
"key_field": "1490920200000",
"max": 2.6146974563598633,
"price": 1.7756011486053467,
"total_count": 315,
"mean": 2.2447497065105138,
"count": 315
},
{
"date": "2017-03-31T00:15:00.000Z",
"total": 706.1140650510788,
"min": 1.7976468801498413,
"key_field": "1490919300000",
"max": 2.6084225177764893,
"price": 1.7976468801498413,
"total_count": 315,
"mean": 2.2416319525431074,
"count": 315
},
{
"date": "2017-03-31T00:00:00.000Z",
"total": 707.5575115680695,
"min": 1.8497636318206787,
"key_field": "1490918400000",
"max": 2.5975091457366943,
"price": 1.8497636318206787,
"total_count": 315,
"mean": 2.2462143224383158,
"count": 315
},
{
"date": "2017-03-30T23:45:00.000Z",
"total": 707.9171552658081,
"min": 1.8517450094223022,
"key_field": "1490917500000",
"max": 2.5352094173431396,
"price": 1.8517450094223022,
"total_count": 315,
"mean": 2.247356048462883,
"count": 315
},
{
"date": "2017-03-30T23:30:00.000Z",
"total": 707.09266269207,
"min": 1.8389506340026855,
"key_field": "1490916600000",
"max": 2.593708038330078,
"price": 1.8389506340026855,
"total_count": 315,
"mean": 2.244738611720857,
"count": 315
},
{
"date": "2017-03-30T23:15:00.000Z",
"total": 708.3666490316391,
"min": 1.861556053161621,
"key_field": "1490915700000",
"max": 2.6234216690063477,
"price": 1.861556053161621,
"total_count": 315,
"mean": 2.2487830127988544,
"count": 315
}
]
var dots =
[
{
"date": "2017-04-22T11:45:00.000Z",
"total": 731.6047915220261,
"min": 1.8769680261611938,
"key_field": "1492861500000",
"max": 2.7165653705596924,
"price": 1.8769680261611938,
"total_count": 315,
"mean": 2.3225548937207177,
"count": 315
},
{
"date": "2017-03-31T01:45:00.000Z",
"total": 701.7422981262207,
"min": 1.8062856197357178,
"key_field": "1490924700000",
"max": 2.5804450511932373,
"price": 1.7062856197357178,
"total_count": 315,
"mean": 2.2277533273848276,
"count": 315
},
{
"date": "2017-03-31T01:30:00.000Z",
"total": 706.3951338529587,
"min": 1.8176854848861694,
"key_field": "1490923800000",
"max": 2.584993600845337,
"price": 1.8176854848861694,
"total_count": 315,
"mean": 2.242524234453837,
"count": 315
},
{
"date": "2017-03-28T18:00:00.000Z",
"total": 728.67049741745,
"min": 1.2837289810180664,
"key_field": "1490724000000",
"max": 2.706052541732788,
"price": 1.3837289810180664,
"total_count": 315,
"mean": 2.3132396743411108,
"count": 315
},
{
"date": "2017-03-26T20:00:00.000Z",
"total": 721.6712145805359,
"min": 1.8257900476455688,
"key_field": "1490558400000",
"max": 2.762291669845581,
"price": 1.4257900476455688,
"total_count": 315,
"mean": 2.291019728827098,
"count": 315
},
{
"date": "2017-03-28T17:45:00.000Z",
"total": 726.2018908262253,
"min": 1.8992395401000977,
"key_field": "1490723100000",
"max": 2.7374281883239746,
"price": 1.8992395401000977,
"total_count": 315,
"mean": 2.305402828019763,
"count": 315
},
{
"date": "2017-03-28T17:30:00.000Z",
"total": 730.83118724823,
"min": 1.8232735395431519,
"key_field": "1490722200000",
"max": 2.696560859680176,
"price": 1.3232735395431519,
"total_count": 315,
"mean": 2.320099007137238,
"count": 315
},
{
"date": "2017-03-28T17:15:00.000Z",
"total": 728.1204907894135,
"min": 1.8851990699768066,
"key_field": "1490721300000",
"max": 2.654668092727661,
"price": 1.8851990699768066,
"total_count": 315,
"mean": 2.3114936215536934,
"count": 315
},
{
"date": "2017-03-27T02:45:00.000Z",
"total": 702.2468013763428,
"min": 1.7651863098144531,
"key_field": "1490582700000",
"max": 2.6390604972839355,
"price": 1.373651863098144531,
"total_count": 315,
"mean": 2.229354925004263,
"count": 315
},
{
"date": "2017-03-27T02:30:00.000Z",
"total": 700.9137979745865,
"min": 1.8334004878997803,
"key_field": "1490581800000",
"max": 2.620957136154175,
"price": 1.8334004878997803,
"total_count": 315,
"mean": 2.2251231681732904,
"count": 315
},
{
"date": "2017-03-27T02:15:00.000Z",
"total": 700.9274371862411,
"min": 1.8098258972167969,
"key_field": "1490580900000",
"max": 2.6065454483032227,
"price": 1.8098258972167969,
"total_count": 315,
"mean": 2.2251664672579086,
"count": 315
},
{
"date": "2017-03-27T02:00:00.000Z",
"total": 703.2963272333145,
"min": 1.7948274354934692,
"key_field": "1490580000000",
"max": 2.549198865890503,
"price": 1.7968274354934692,
"total_count": 315,
"mean": 2.2326867531216332,
"count": 315
},
{
"date": "2017-03-27T01:45:00.000Z",
"total": 700.4703311920166,
"min": 1.8429771661758423,
"key_field": "1490579100000",
"max": 2.518679141998291,
"price": 1.348429771661758423,
"total_count": 315,
"mean": 2.223715337117513,
"count": 315
},
{
"date": "2017-03-27T01:30:00.000Z",
"total": 701.4555011987686,
"min": 1.7773451805114746,
"key_field": "1490578200000",
"max": 2.635554790496826,
"price": 1.27773451805114746,
"total_count": 315,
"mean": 2.2268428609484716,
"count": 315
},
{
"date": "2017-03-26T20:00:00.000Z",
"total": 721.6712145805359,
"min": 1.8257900476455688,
"key_field": "1490558400000",
"max": 2.762291669845581,
"price": 1.48257900476455688,
"total_count": 315,
"mean": 2.291019728827098,
"count": 315
},
{
"date": "2017-03-26T19:45:00.000Z",
"total": 724.9882735013962,
"min": 1.80784010887146,
"key_field": "1490557500000",
"max": 2.6430490016937256,
"price": 0.40784010887146,
"total_count": 315,
"mean": 2.301550074607607,
"count": 315
},
]
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 110, left: 40},
margin2 = {top: 430, right: 20, bottom: 30, left: 40},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
height2 = +svg.attr("height") - margin2.top - margin2.bottom;
var parseDate = d3.timeParse("%m/%d/%Y %H:%M");
var g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleTime().range([0, width]),
x2 = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
y2 = d3.scaleLinear().range([height2, 0]),
dotXScale = d3.scaleTime().range([0, width]),
dotYScale = d3.scaleLinear().range([height, 0]);
var xAxis = d3.axisBottom(x),
xAxis2 = d3.axisBottom(x2),
yAxis = d3.axisLeft(y);
var brush = d3.brushX()
.extent([[0, 0], [width, height2]])
.on("brush end", brushed);
var zoom = d3.zoom()
.scaleExtent([1, Infinity])
.translateExtent([[0, 0], [width, height]])
.extent([[0, 0], [width, height]])
.on("zoom", zoomed);
var line = d3.line()
.x(function (d) { return x(new Date(d.date)); })
.y(function (d) { return y(d.price); });
var line2 = d3.line()
.x(function (d) { return x2(new Date(d.date)); })
.y(function (d) { return y2(d.price); });
var clip = svg.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("width", width)
.attr("height", height)
.attr("x", 0)
.attr("y", 0);
var Line_chart = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("clip-path", "url(#clip)");
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
x.domain(d3.extent(data, function(d) { return new Date(d.date); }));
dotXScale.domain(d3.extent(dots, function(d) { return new Date(d.date); }));
y.domain([0, d3.max(data, function (d) { return d.price; })]);
dotYScale.domain([0, d3.max(dots, function (d) { return d.price; })]);
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "axis axis--y")
.call(yAxis);
Line_chart.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
context.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line2);
context.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "brush")
.call(brush)
.call(brush.move, x.range());
svg.append("rect")
.attr("class", "zoom")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
var tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.text("a simple tooltip");
g.selectAll(".dot")
.data(dots)
.enter()
.append("circle")
.attr("class", "dot")
.attr("r", 3.5)
.attr("cx", function(d) {
//console.log('---',x(new Date(d.date)))
return dotXScale(new Date(d.date));
})
.attr("cy", function(d) {
//console.log(y(d.price));
return dotYScale(d.price);
})
.on("mouseover", function(d){
console.log(d);
return tooltip.style("visibility", "visible").html("Expected value is: "+d.expected_value + "<br/>" + "value : "+d.close +"<br/>" + "deviation is: "+d.deviation_expected)
})
.on("mousemove", function(){return tooltip.style("top", (event.pageY-10)+"px").style("left",(event.pageX+10)+"px");})
.on("mouseout", function(){return tooltip.style("visibility", "hidden");});
function brushed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom
var s = d3.event.selection || x2.range();
x.domain(s.map(x2.invert, x2));
dotXScale.domain(s.map(x2.invert), x2);
Line_chart.select(".line").attr("d", line);
focus.select(".axis--x").call(xAxis);
svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
.scale(width / (s[1] - s[0]))
.translate(-s[0], 0));
g.selectAll(".dot").transition(1000)
.attr("cx", function (d) {
return dotXScale(new Date(d.date)) })
.attr("cy", function (d) {
//console.log(y(d.price));
return dotYScale(d.price) });
}
function zoomed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; // ignore zoom-by-brush
var t = d3.event.transform;
x.domain(t.rescaleX(x2).domain());
Line_chart.select(".line").attr("d", line);
focus.select(".axis--x").call(xAxis);
context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
}
function type(d) {
d.date = new Date(d.date);
d.price = +d.price;
return d;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 2px;
}
.heading {
padding-top: 30px;
}
.buttonWidth {
height: 34px;
width: 50px;
}
.actiontable {
width: 36rem;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
.zoom {
cursor: move;
fill: none;
pointer-events: all;
}
.area {
fill: none;
stroke: #a2dced;
stroke-width: 2;
clip-path: url(#clip);
}
.zoom {
cursor: move;
fill: none;
pointer-events: all;
}
rect.selection
{
fill:green;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="960" height="500"></svg>
Upvotes: 1