Reputation: 103
I am new to d3.js and trying to draw multiple graphs that all have time dimension on the -x- axis in one page. I would like to apply the same zoom on all graph when any of the graph in the page is zoomed. How can I achieve this? You can find a working sample here:Multiple Charts example, what changes do I need to make in the zoom event function?
var zoom = d3.behavior.zoom()
.scaleExtent([1, 20])
.x(x)
.on('zoom', function zoomHandler() {
axes.select('.x-axis')
.call(xAxis);
circles.attr("transform", function (d) {
return "translate(" + x(d.date) + "," + y(d.measurement) + ")";
});
svg.selectAll('path.line')
.attr('d', function (d) {
return line(d.values);
});
});
Upvotes: 2
Views: 1569
Reputation: 103
I found the solution to the posted jsfiddle. I defined the zoom behavior outside the chart function and saved the svg,circle, line and axes objects inside the corresponding list global object in order to be accessible outside the scope of the graph creation. Finally I created a setzoom function that is called after all the graphs are created and iterates through the svglist array applying the same transformation in every object saved in the svglist, circlelist and linelist. The final javascript code is :
var timeFormat = d3.time.format('%Y-%m-%d %H:%M:%S');
var customTimeFormat = d3.time.format.multi([
[".%L", function (d) { return d.getMilliseconds(); }],
[":%S", function (d) { return d.getSeconds(); }],
["%H:%M", function (d) { return d.getMinutes(); }],
["%H:%M", function (d) { return d.getHours(); }],
["%d / %m", function (d) { return d.getDay() && d.getDate() != 1; }],
["%d", function (d) { return d.getDate() != 1; }],
["%m - %Y", function (d) { return d.getMonth(); }],
["%Y", function () { return true; }]
]);
var color = d3.scale.category10();
var width = 900,
height = 250,
margin = {
top: 5,
right: 50,
bottom: 20,
left: 80
};
var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;
var x = d3.time.scale().range([margin.left, width - margin.right]);
var xAxis = d3.svg.axis()
.scale(x)
.tickFormat(customTimeFormat)
.innerTickSize(0)
.outerTickSize(0)
.orient("bottom");
var zoom = d3.behavior.zoom();
var circleslist=[];
var svglist=[];
var axeslist=[];
var ylist=[];
var linelist=[];
function setzoom()
{
zoom.scaleExtent([1, 20])
.x(x)
.on('zoom', function zoomHandler() {
//alert(svglist.length);
for(var i=0;i<3;i++)
{
axeslist[i].select('.x-axis')
.call(xAxis);
circleslist[i].attr("transform", function (d) {
return "translate(" + x(d.date) + "," + ylist[i](d.measurement) + ")";
});
svglist[i].selectAll('path.line')
.attr('d', function (d) {
return linelist[i](d.values);
});
}
});
}
var chartValuesList1 = [{ Date: "2018-01-29 11:47:09", Measurement: 225 },
{ Date: "2018-01-29 12:47:09", Measurement: 225 },{ Date: "2018-01-29 13:47:13", Measurement: 224 },{ Date: "2018-01-29 14:47:13", Measurement: 225 },{ Date: "2018-01-29 15:47:10", Measurement: 223 },
{ Date: "2018-01-29 16:47:11", Measurement: 223 }];
var Array1 = [{ name: "Plot1", units: "", chartValuesList:chartValuesList1 }];
var chartValuesList2 = [{ Date: "2018-01-29 11:47:09", Measurement: 225 },
{ Date: "2018-01-29 12:47:09", Measurement: 225 },{ Date: "2018-01-29 13:47:13", Measurement: 224 },{ Date: "2018-01-29 14:47:13", Measurement: 200 },{ Date: "2018-01-29 15:47:10", Measurement: 233 },
{ Date: "2018-01-29 16:47:11", Measurement: 240 }];
var Array2 = [{ name: "Plot2", units: "", chartValuesList:chartValuesList2 }];
var chartValuesList3 = [{ Date: "2018-01-29 11:47:09", Measurement: 225 },
{ Date: "2018-01-29 12:47:09", Measurement: 550 },{ Date: "2018-01-29 13:47:13", Measurement: 600 },{ Date: "2018-01-29 14:47:13", Measurement: 400 },{ Date: "2018-01-29 15:47:10", Measurement: 300 },
{ Date: "2018-01-29 16:47:11", Measurement: 600 }];
var Array3 = [{ name: "Plot3", units: "", chartValuesList:chartValuesList3 }];
chart("chart1", Array1, "Values");
chart("chart2", Array2, "Values");
chart("chart3", Array3, "Values");
setzoom();
function chart(chartID, chartData, heading) {
var y = d3.scale.linear().range([height - margin.bottom, margin.top]);
ylist.push(y);
var yAxis = d3.svg.axis()
.scale(y)
.tickFormat(function (d) { return d; })
.innerTickSize(-(width - margin.left - margin.right))
.outerTickSize(0)
.orient("left");
var data = chartData;
var line = d3.svg.line()
.interpolate("linear")
.x(function (d) { return x(d.date); })
.y(function (d) { return y(d.measurement); });
linelist.push(line);
var container = d3.select("#" + chartID);
var svg = container.append("svg")
.attr('width', width)
.attr('height', height);
svglist.push(svg);
var defs = svg.append('defs');
defs.append('clipPath')
.attr('id', 'plot-area-clip-path')
.append('rect')
.attr({
x: margin.left,
y: margin.top,
width: width - margin.right - margin.left,
height: height - margin.top - margin.bottom
});
var backRect = svg.append('rect')
.style('stroke', 'none')
.style('fill', '#FFF')
.style('fill-opacity', 0)
.attr({
x: margin.left,
y: margin.top,
width: width - margin.right - margin.left,
height: height - margin.top - margin.bottom,
'pointer-events': 'all'
});
axes = svg.append('g')
.attr('pointer-events', 'none')
.style('font-size', '11px');
axeslist.push(axes);
var chart = svg.append('g')
.attr('class', 'plot-area')
.attr('pointer-events', 'none')
.attr('clip-path', 'url(#plot-area-clip-path)');
var dates = [];
var measurements = [];
var dateStrings = [];
var units;
var chartLines = data.map(function (chartLine) {
units = chartLine.units;
return {
name: chartLine.name,
units: chartLine.units,
values: chartLine.chartValuesList.map(function (value) {
dateStrings.push(value.Date);
var date = parseDate(value.Date);
var measurement = value.Measurement;
dates.push(date);
measurements.push(measurement);
return {
date: date,
measurement: measurement
};
})
}
});
x.domain(d3.extent(dates));
if (chartID == "charge-chart" || chartID == "genBattVdc-chart") {
var max = d3.max(measurements);
y.domain([0, max + (0.1 * max)]);
}
// else if (chartID == "powerFact_g-chart") {
// y.domain([-1.2, 1.2]);
// }
//energy-chart
else if (chartID == "energy-chart") {
y.domain(d3.extent(measurements));
}
else {
//y.domain(d3.extent(measurements));
y.domain([d3.min(measurements) - 0.01 * d3.min(measurements), 1.01 * d3.max(measurements)]);
}
var xAxisEl = axes.append('g')
.attr('class', 'x-axis')
.attr('transform', 'translate(' + 0 + ',' + (height - margin.bottom) + ')')
.call(xAxis);
var yAxisEl = axes.append('g')
.attr('class', 'y-axis')
.attr('transform', 'translate(' + margin.left + ',' + 0 + ')')
.call(yAxis);
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 20)
.attr("x", -height / 2)
.attr("dy", "1em")
.style("text-anchor", "middle")
.text((units == "") ? "" : "( " + units + " )");
backRect.call(zoom);
yAxisEl.selectAll('line')
.style('stroke', '#BBB')
.style('stroke-width', '1px')
.style('shape-rendering', 'crispEdges');
var chartLine = chart.selectAll(".chartLine")
.data(chartLines)
.enter().append("g")
.attr("class", "chartLine");
var paths = chart.selectAll(".chartLine").append("g")
.attr("class", "plot")
.attr("id",
function (d, i) {
return 'tag' + d.name.replace(/\s+/g, '');
})
.append("path")
.attr("class", "line")
.attr("d", function (d) {
return line(d.values);
})
.style("stroke", function (d, i) {
return color(i);
});
/* Title and Legends */
var chartInfo = container.append('svg')
.attr("class", "title")
.attr("x", width + 65)
.attr("y", 50)
.attr("height", height)
.attr("width", 200);
var title = chartInfo.append('svg')
.attr("class", "title")
.attr('width', 200)
.attr('height', 40)
.attr("x", 10)
.attr("y", 0)
.append('g')
.append("text")
.attr("x", 0)
.attr("y", 30)
.attr("height", 30)
.attr("width", 200)
.attr("text-anchor", "start")
.style("font-size", "16px")
.style("font-weight", "bold")
.style("fill", "rgb(128,128,128)")
.text(heading);
var legends = chartInfo.append('svg')
.attr("class", "legend")
.attr('width', 200)
.attr('height', height - 40)
.attr("x", 10)
.attr("y", 60);
legends.selectAll('g').data(chartLines)
.enter()
.append('g')
.each(function (d, i) {
var g = d3.select(this);
g.append("rect")
.attr("x", 10)
.attr("y", i * 25)
.attr("width", 10)
.attr("height", 10)
.style("fill", color(i));
g.append("text")
.attr("x", 30)
.attr("y", i * 25 + 10)
.attr("height", 30)
.attr("width", 100)
.style("fill", color(i))
.on("click", function () {
(!d.active) ? $(this).attr("opacity", 0.3) : $(this).attr("opacity", 1);
var active = d.active ? false : true,
newOpacity = active ? 0 : 1;
d3.select('#tag' + d.name.replace(/\s+/g, ''))
.transition().duration(100)
.style('opacity', newOpacity);
d.active = active;
})
.text(d.name);
});
/* Dots */
var circles = chart.selectAll(".chartLine").select('.plot').append('g')
.attr("class", "dots")
.selectAll('circle')
.data(function (d) { return d.values; })
.enter().append('circle')
// .attr('cy', function(d){
// return y(d.measurement);
// })
// .attr('cx', function(d){
// return x(d.date);
// })
.attr("transform", function (d) {
return "translate(" + x(d.date) + "," + y(d.measurement) + ")";
})
.attr('r', 1)
.attr('fill', 'black')
.attr('pointer-events', 'all')
.attr('stroke', 'black')
.attr('stroke-width', 1)
.on("mouseover", mouseover)
.on("mousemove", function (d) {
var aa = new Date(d.date);
var h = aa.getHours();
var m = aa.getMinutes();
var s = aa.getSeconds();
var t = h + ":" + m + ":" + s;
console.log(aa, t)
divToolTip.text(this.parentNode.__data__.units + ": " + d.measurement + ", " + "Time: " + t)
.style("left", (d3.event.pageX + 15) + "px")
.style("top", (d3.event.pageY - 10) + "px");
})
.on("mouseout", mouseout);
circleslist.push(circles);
/* Tooltip */
var divToolTip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 1e-6);
function mouseover() {
divToolTip.transition()
.duration(100)
.style("opacity", 1);
}
function mouseout() {
divToolTip.transition()
.duration(100)
.style("opacity", 1e-6);
}
}
Upvotes: 3