d3.js - D3: two x-axis with independent zoom behavior -
i want have 2 independent x-axis in time-comparison chart (timescale) , have problem implement zoom behavior both. d3 calculates x-domain both axis independently - perfect. how can bind (and call) 2 zoom behavior each axis 1 'g'-element (.d3-draw-area) ?
i have listener both axis "master-axis" (logically) being computed:
d3.select(".d3-draw-area").call(d3.behavior.zoom() .on('zoom' + ".x" + self._getxaxismaster().id, function () { self._zoomx(self._getxaxismaster()); }) .on('zoom' + ".x" + self._getxaxisslave().id, function () { self._zoomx(self._getxaxisslave()); }) .x(self._getxaxismaster().d3axis.scale()) );
thx...!
i'm not able make master-slave independent scales work on single domain (x). in code above, have specified masterscale on domain (x), master scale gets triggered. i'm not able understand kind of data plotting, or relation between master/slave scales. check out below code , see if of these work you:
1) 2 independent scales , 2 independent dimension (properties or attributes) in data, can convert y axis secondary x-axis.
var data = []; (var = 0; < 500; i++) { data.push([math.random(), math.random()]); } d3.select('#chart') .append("svg").attr("width", window.innerwidth).attr("height",window.innerheight) .datum(data).call(init()); function init() { var svg, margin = {top: 60,bottom: 80,left: 60,right: 0}, width = 500, height = 400, xaxis1 = d3.svg.axis(), xaxis2 = d3.svg.axis(), scaleone = d3.scale.linear(), scaletwo = d3.scale.linear(), zoomable = true, zoom = d3.behavior.zoom().x(scaleone).y(scaletwo).on("zoom", zoomable ? draw : null); svg = d3.select('svg').data([data]); svg.enter().append('svg'); var g = svg.append('g').attr("transform", "translate(" + margin.left + "," + margin.top + ")"); g.append("defs").append("clippath") .attr("id", "clip") .append("rect") .attr("width", width - margin.left - margin.right) .attr("height", height - margin.top - margin.bottom); g.append("svg:rect") .attr("class", "border") .attr("width", width - margin.left - margin.right) .attr("height", height - margin.top - margin.bottom) .style("stroke", "black") .style("fill", "none"); g.append("g").attr("class", "axis one") .attr("transform", "translate(" + 0 + "," + (height - margin.top - margin.bottom) + ")"); g.append("g").attr("class", "axis two") .attr("transform", "translate(" + 0 + "," + (height - margin.top - margin.bottom + 60) + ")"); g.append("g") .attr("class", "scatter") .attr("clip-path", "url(#clip)"); g.append("svg:rect") .attr("class", "zoom box") .attr("width", width - margin.left - margin.right) .attr("height", height - margin.top - margin.bottom) .style("visibility", "hidden") .attr("pointer-events", "all") .call(zoom); scaleone.domain(d3.extent(data, function(d) { return d[0]; })).range([0, width - margin.left - margin.right]); xaxis1.scale(scaleone).orient('bottom').tickpadding(10); svg.select('g.axis.one').call(xaxis1); scaletwo.domain(d3.extent(data, function(d) { return d[1]; })).range([0, width - margin.left - margin.right]); xaxis2.scale(scaletwo).orient('bottom').tickpadding(10); svg.select('g.axis.two').call(xaxis2); draw(); function update() { var gs = svg.select("g.scatter"); var circle = gs.selectall("circle") .data(function(d) { return d; }); circle.enter().append("svg:circle") .attr("class", "points") .style("fill", "steelblue") .attr("cx", function(d) { return x1(d); }).attr("cy", function(d) { return x2(d); }).attr("r", 4); circle.attr("cx", function(d) { return x1(d); }).attr("cy", function(d) { return x2(d); }); circle.exit().remove(); } function zoom_update() { zoom = d3.behavior.zoom() .x(scaleone) .y(scaletwo) .on("zoom", zoomable ? draw : null); svg.select('rect.zoom.box').call(zoom); } function draw() { svg.select('g.axis.one').call(xaxis1); svg.select('g.axis.two').call(xaxis2); update(); zoom_update(); }; function x1(d) { return scaleone(d[0]); } function x2(d) { return scaletwo(d[1]); } return chart; }
2) incase have connected/dependent scales, can apply same scale on 2 axis , generate offset correction (even logarithmic correction) , have dual axis on same domain. 1 keeps y domain/axis available plot dimension in data.
var data = []; (var = 0; < 500; i++) { data.push([math.random(), math.random()]); } d3.select('#chart') .append("svg").attr("width", window.innerwidth).attr("height",window.innerheight) .datum(data).call(init()); function init() { var svg, margin = {top: 60,bottom: 80,left: 60,right: 0}, width = 500, height = 400, xaxis1 = d3.svg.axis(), xaxis2 = d3.svg.axis(), scaleone = d3.scale.linear(), scaletwo = d3.scale.linear(), zoomable = true, zoom = d3.behavior.zoom().x(scaleone).on("zoom", draw) svg = d3.select('svg').data([data]); svg.enter().append('svg'); var g = svg.append('g').attr("transform", "translate(" + margin.left + "," + margin.top + ")"); g.append("defs").append("clippath") .attr("id", "clip") .append("rect") .attr("width", width - margin.left - margin.right) .attr("height", height - margin.top - margin.bottom); g.append("svg:rect") .attr("class", "border") .attr("width", width - margin.left - margin.right) .attr("height", height - margin.top - margin.bottom) .style("stroke", "black") .style("fill", "none"); g.append("g").attr("class", "axis one") .attr("transform", "translate(" + 0 + "," + (height - margin.top - margin.bottom) + ")"); g.append("g").attr("class", "axis two") .attr("transform", "translate(" + 0 + "," + (height - margin.top - margin.bottom + 60) + ")"); g.append("g") .attr("class", "scatter") .attr("clip-path", "url(#clip)"); g.append("svg:rect") .attr("class", "zoom box") .attr("width", width - margin.left - margin.right) .attr("height", height - margin.top - margin.bottom) .style("visibility", "hidden") .attr("pointer-events", "all") .call(zoom); scaleone.domain(d3.extent(data, function(d) { return d[0]; })).range([0, width - margin.left - margin.right]); xaxis1.scale(scaleone).orient('bottom').tickpadding(10); svg.select('g.axis.one').call(xaxis1); scaletwo.domain(d3.extent(data, function(d) { return d[1]; })).range([0, width - margin.left - margin.right]); xaxis2.scale(scaleone) .orient('bottom').tickpadding(10) .tickformat(function(d) { return d + 5.5; }) svg.select('g.axis.two').call(xaxis2); draw(); function update() { var gs = svg.select("g.scatter"); var circle = gs.selectall("circle") .data(function(d) { return d; }); circle.enter().append("svg:circle") .attr("class", "points") .style("fill", "gray") .attr("cx", function(d) { return x1(d); }) .attr("cy", function(d) { return x2(d); }) .attr("r", 4); circle.attr("cx", function(d) { return x1(d); }) .attr("cy", function(d) { return x2(d); }); circle.exit().remove(); } function zoom_update() { zoom = d3.behavior.zoom() .x(scaleone) .on("zoom", draw) svg.select('rect.zoom.box').call(zoom); } function draw() { svg.select('g.axis.one').call(xaxis1); svg.select('g.axis.two').call(xaxis2); update(); zoom_update(); }; function x1(d) { return scaleone(d[0]); } function x2(d) { return scaletwo(d[1]); } return chart; }
i took base code d3 examples: http://bl.ocks.org/jgbos/9752277
Comments
Post a Comment