d3.js - Convert D3 to Angular component -
i have done now. how can have angular component?? here repo https://github.com/bastiankhalil/line-chart-d3
problem in function tick()
should called recursively.
<!doctype html> <meta charset="utf-8"> <style> .line { fill: none; stroke: #000; stroke-width: 1.5px; } </style> <svg width="960" height="500"></svg> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.js"></script> <script> var n = 40, random = d3.randomnormal(0, .2), data = d3.range(n).map(random); var svg = d3.select("svg"), margin = {top: 20, right: 20, bottom: 20, left: 40}, width = +svg.attr("width") - margin.left - margin.right, height = +svg.attr("height") - margin.top - margin.bottom, g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var x = d3.scalelinear() .domain([0, n - 1]) .range([0, width]); var y = d3.scalelinear() .domain([-1, 1]) .range([height, 0]); var line = d3.line() .x(function(d, i) { return x(i); }) .y(function(d, i) { return y(d); }); g.append("defs").append("clippath") .attr("id", "clip") .append("rect") .attr("width", width) .attr("height", height); g.append("g") .attr("class", "axis axis--y") .call(d3.axisleft(y)); g.append("g") .attr("clip-path", "url(#clip)") .append("path") .datum(data) .attr("class", "line") .transition() .duration(500) .ease(d3.easelinear) .on("start", tick); function tick() { data.push(random()); // redraw line. d3.select(this) .attr("d", line) .attr("transform", null); // slide left. d3.active(this) .attr("transform", "translate(" + x(-1) + ",0)") .transition() .on("start", tick); data.shift(); } </script>
got work, full code available here.
to code working, had different things.
package
install full d3 package , import it. reason, webpack not catch transition
needs bundled
this
, tick
function context
for tick
function work, had jump though few hoops. first, tick function has rebound in component constructor correct context:
constructor() { this.tick = this.tick.bind(this); }
then, in update/transition phase, had capture actual component before handling on
callback:
const self = this; g.append('g') .attr('clip-path', 'url(#clip)') .append('path') .datum(this.data) .attr('class', 'line') .attr('d', this.theline) .transition() .duration(500) .ease(d3.easelinear) .on('start', function (d, i) { self.tick(this); });
notice how introduced self
variable before callback, , use call tick function this
argument, , how use actual function
, not lambda/arrow function. in case, this
refers current selection (i.e. path element).
finally, modified tick
function accept selected/transitioned element argument , apply same trickery example provided. here again, manually capture this
in self
variable, use function
callback,and call self.tick(this)
.
tick(sel: any) { const self = this; this.data.push(this.random()); // redraw line. d3.select(sel) .attr('d', this.theline) .attr('transform', null); // slide left. d3.active(sel) // .select('.line') .attr('transform', 'translate(' + this.x(-1) + ',0)') .transition() .on('start', function () { self.tick(this) }); this.data.shift(); }
in hope helps :-). if unclear, let me know.
Comments
Post a Comment