@sorvah wrote:
Hello. I have a D3 chart that re-renders data when a model is refreshed an although I have the chart working I am having a lot of trouble adding it as an Ember component. Here is what I have so far:
(note that the appropriate d3 modules are imported before the component object is extended)
export default Component.extend({ data: [], didInsertElement() { this.buildChart() }, didUpdateAttrs() { this.buildChart() }, buildChart() { var data = this.get('data') var margin = {top: 35, right: 145, bottom: 35, left: 45}, width = 650 - margin.left - margin.right, height = 450 - margin.top - margin.bottom; var svg = select("#chart") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform","translate(" + margin.left + "," + margin.top + ")"); var x = scaleBand() .rangeRound([0, width]) .padding(0.1); var y = scaleLinear() .rangeRound([height, 0]); var z = scaleOrdinal() .range(["steelblue","darkorange", "red"]); svg.append("g") .attr("class","x-axis"); svg.append("g") .attr("class", "y-axis"); var input = selectAll(".opt").property("value"); selectAll(".opt").on("change", function() { update(data, this.value) }) update(data); function update(data) { var keys = ["count1", "count2", "count3"]; var series = stack() .keys(keys) .offset(stackOffsetDiverging) (data); x.domain(data.map(d => d.label)); y.domain([ min(series, stackMin), max(series, stackMax) ]).nice(); var barGroups = svg.selectAll("g.layer") .data(series); barGroups.exit().remove(); barGroups.enter().insert("g", ".x-axis") .classed('layer', true); svg.selectAll("g.layer") .transition().duration(750) .attr("fill", d => z(d.key)); var bars = svg.selectAll("g.layer").selectAll("rect") .data(function(d) { return d; }); bars.exit().remove() bars = bars .enter() .append("rect") .attr("width", x.bandwidth()) .attr("x", d => x(d.data.label)) .merge(bars) bars.transition().duration(750) .attr("y", d => y(d[1])) .attr("height", d => Math.abs(y(d[0])) - y(d[1])); svg.selectAll(".x-axis").transition().duration(750) .attr("transform", "translate(0," + y(0) + ")") .call(axisBottom(x)); svg.selectAll(".y-axis").transition().duration(750) .call(axisLeft(y)); function stackMin(serie) { return min(serie, function(d) { return d[0]; }); } function stackMax(serie) { return max(serie, function(d) { return d[1]; }); } } } });
In the first instance the chart renders correctly. The problem occurs when the model refreshes.
Rather than simply transition the bars, the whole chart is re-rendered and is placed ‘on top’ of the existing chart.
I know that this is because when the attrs update I am redrawing the whole chart but I am struggling to divide my code between the insertElement hook and the buildChart function. I tried to move all of the standard elements (such as svg, x, y etc) to insertElement and use setters/getters to reference them in buildChart but I constantly run into ‘is undefined’ errors.
Does anyone have any experience in similar problems?
Posts: 1
Participants: 1