javascript - D3: Zooming/Panning Line Graph in SVG is not working in Canvas -




i created zooming/panning graph d3 using svg. i'm trying create same exact graph canvas. issue is, when comes zooming , panning of canvas graph, graph disappearing , cannot figure out why. created 2 jsbin's show code of both. can assist me.

svg - jsbin

canvas - jsbin

my svg zoom code looks this:

// zoom components zoom = d3.zoom()         .scaleextent([1, daydiff*12])         .translateextent([[0, 0], [width, height]])         .extent([[0, 0], [width, height]])         .on("zoom", zoomed);  function zoomed(){     t = d3.event.transform;     xscale.domain(t.rescalex(x2).domain());     xaxis = d3.axisbottom(xscale).ticksize(0).tickformat(d3.timeformat('%b'));     focus.select(".axis--x").call(xaxis); //xaxis changes     usagelinepath.attr('d',line); //line path reference, regenerate } 

my canvas zoom code looks this:

// zoom components zoom = d3.zoom()         .scaleextent([1, daydiff*12])         .translateextent([[0, 0], [width, height]])         .extent([[0, 0], [width, height]])         .on("zoom", zoomed);  function zoomed() {     t = d3.event.transform;     x.domain(t.rescalex(x2).domain());     context.save();     context.clearrect(0, 0, width, height);     draw();     context.restore(); }  function draw() {     xaxis();     yaxis();      context.beginpath();     line(data);     context.linewidth = 1.5;     context.strokestyle = "steelblue";     context.stroke(); } 

there 1 major source of grief causes line disappear, , triggered on zoom:

function zoomed() {     t = d3.event.transform;     x.domain(t.rescalex(x2).domain());  // here     ... } 

rescaling won't work on x2 haven't defined domain. x2 reference scale used set x on each zoom, should same x start with. however, default domain d3.timescale() january 1, 2000 january 2, 2000 (see api docs), won't work out data data not overlap period.

you need set domain of x2 x. if after set initial domain x with: x2.domain(x.domain()), should chart updates (jsbin) have domain overlaps data.

however, now, issue need clip line, in svg example not canvas. use like:

function draw() {     xaxis();     yaxis();    // save context without clip apth   context.save();    // create clip path:   context.beginpath()   context.rect(0, 0, width, height);   context.clip();    // draw line in clip path   context.beginpath()   line(data);    context.linewidth = 1.5;   context.strokestyle = "steelblue";   context.stroke();    // restore context without clip path   context.restore(); } 

see jsbin

and shouldn't let axes overwrite themselves: here's jsbin erases previous axes (with commented out code block redefines y domain based on values contained in selected x domain).

for measure, here's snippet of last jsbin (scaled down snippet view):

var data = getdata().map(function (d) {          return d;      });        var canvas = document.queryselector("canvas"),          context = canvas.getcontext("2d");        var margin = { top: 20, right: 20, bottom: 30, left: 50 },          width = canvas.width - margin.left - margin.right,          height = canvas.height - margin.top - margin.bottom;        var parsetime = d3.timeparse("%d-%b-%y");        // setup scales      var x = d3.scaletime()          .range([0, width]);      var x2 = d3.scaletime().range([0, width]);      var y = d3.scalelinear()          .range([height, 0]);        // setup domain      x.domain(d3.extent(data, function (d) { return moment(d.ind, 'yyyymm'); }));      y.domain(d3.extent(data, function (d) { return d.ksum; }));            x2.domain(x.domain());             // day range      var daydiff = daydiff(x.domain()[0],x.domain()[1]);        // line generator      var line = d3.line()          .x(function (d) { return x(moment(d.ind, 'yyyymm')); })          .y(function (d) { return y(d.ksum); })          .curve(d3.curvemonotonex)          .context(context);        // zoom      var zoom = d3.zoom()          .scaleextent([1, daydiff])          .translateextent([[0, 0], [width, height]])          .extent([[0, 0], [width, height]])          .on("zoom", zoomed);            d3.select("canvas").call(zoom)        context.translate(margin.left, margin.top);        draw();  //        function draw() {        // remove everything:        context.clearrect(-margin.left, -margin.top, canvas.width, canvas.height);                /*        // calculate y axis domain across selected x domain:        newydomain = d3.extent(data, function(d) {           if (  (x(moment(d.ind, 'yyyymm')) > 0) && (x(moment(d.ind, 'yyyymm')) < width) ) {             return d.ksum;                      }        });        // don't update y axis if there no points set new domain, keep old domain.        if ((newydomain[0] !== undefined) && (newydomain[0] != newydomain[1])) {          y.domain(newydomain);                }       //*/          // draw axes:        xaxis();        yaxis();                // save context without clip apth        context.save();                // create clip path:        context.beginpath()        context.rect(0, 0, width, height);        context.clip();          // draw line in clip path        context.beginpath()        line(data);                context.linewidth = 1.5;        context.strokestyle = "steelblue";        context.stroke();                // restore context without clip path        context.restore();           }        function zoomed() {          t = d3.event.transform;          x.domain(t.rescalex(x2).domain());                           draw();      }        function xaxis() {          var tickcount = 10,              ticksize = 6,              ticks = x.ticks(tickcount),              tickformat = x.tickformat();            context.beginpath();          ticks.foreach(function (d) {              context.moveto(x(d), height);              context.lineto(x(d), height + ticksize);          });          context.strokestyle = "black";          context.stroke();            context.textalign = "center";          context.textbaseline = "top";          ticks.foreach(function (d) {              context.filltext(tickformat(d), x(d), height + ticksize);          });      }        function yaxis() {          var tickcount = 10,              ticksize = 6,              tickpadding = 3,              ticks = y.ticks(tickcount),              tickformat = y.tickformat(tickcount);            context.beginpath();          ticks.foreach(function (d) {              context.moveto(0, y(d));              context.lineto(-6, y(d));          });          context.strokestyle = "black";          context.stroke();            context.beginpath();          context.moveto(-ticksize, 0);          context.lineto(0.5, 0);          context.lineto(0.5, height);          context.lineto(-ticksize, height);          context.strokestyle = "black";          context.stroke();            context.textalign = "right";          context.textbaseline = "middle";          ticks.foreach(function (d) {              context.filltext(tickformat(d), -ticksize - tickpadding, y(d));          });            context.save();          context.rotate(-math.pi / 2);          context.textalign = "right";          context.textbaseline = "top";          context.font = "bold 10px sans-serif";          context.filltext("price (us$)", -10, 10);          context.restore();      }        function getdate(d) {          return new date(d.ind);      }        function daydiff(first, second) {          return math.round((second - first) / (1000 * 60 * 60 * 24));      }        function getdata() {          return [              {                  "briteid": "bi-43dd32fe-ecbc-48d4-a8dc-e1f66110a542",                  "ind": 201501,                  "tmin": 30.43,                  "tmax": 77.4,                  "kmin": 0.041,                  "kmax": 1.364,                  "ksum": 625.08              },              {                  "briteid": "bi-43dd32fe-ecbc-48d4-a8dc-e1f66110a542",                  "ind": 201502,                  "tmin": 35.3,                  "tmax": 81.34,                  "kmin": 0.036,                  "kmax": 1.401,                  "ksum": 542.57              },              {                  "briteid": "bi-43dd32fe-ecbc-48d4-a8dc-e1f66110a542",                  "ind": 201503,                  "tmin": 32.58,                  "tmax": 81.32,                  "kmin": 0.036,                  "kmax": 1.325,                  "ksum": 577.83              },              {                  "briteid": "bi-43dd32fe-ecbc-48d4-a8dc-e1f66110a542",                  "ind": 201504,                  "tmin": 54.54,                  "tmax": 86.55,                  "kmin": 0.036,                  "kmax": 1.587,                  "ksum": 814.62              },              {                  "briteid": "bi-43dd32fe-ecbc-48d4-a8dc-e1f66110a542",                  "ind": 201505,                  "tmin": 61.35,                  "tmax": 88.61,                  "kmin": 0.036,                  "kmax": 1.988,                  "ksum": 2429.56              },              {                  "briteid": "bi-43dd32fe-ecbc-48d4-a8dc-e1f66110a542",                  "ind": 201506,                  "tmin": 69.5,                  "tmax": 92.42,                  "kmin": 0.037,                  "kmax": 1.995,                  "ksum": 2484.93              },              {                  "briteid": "bi-43dd32fe-ecbc-48d4-a8dc-e1f66110a542",                  "ind": 201507,                  "tmin": 71.95,                  "tmax": 98.62,                  "kmin": 0.037,                  "kmax": 1.864,                  "ksum": 2062.05              },              {                  "briteid": "bi-43dd32fe-ecbc-48d4-a8dc-e1f66110a542",                  "ind": 201508,                  "tmin": 76.13,                  "tmax": 99.59,                  "kmin": 0.045,                  "kmax": 1.977,                  "ksum": 900.05              },              {                  "briteid": "bi-43dd32fe-ecbc-48d4-a8dc-e1f66110a542",                  "ind": 201509,                  "tmin": 70,                  "tmax": 91.8,                  "kmin": 0.034,                  "kmax": 1.458,                  "ksum": 401.39              }];      }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>  <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.js"></script>  <canvas width="500" height="200"></canvas>





wiki

Comments

Popular posts from this blog

Asterisk AGI Python Script to Dialplan does not work -

python - Read npy file directly from S3 StreamingBody -

kotlin - Out-projected type in generic interface prohibits the use of metod with generic parameter -