import './GraphTest.html'; import d3 from 'd3'; let SalesTotals = new Meteor.Collection(null); function changeData() { if(SalesTotals.find({}).count() > 0) { let sales = SalesTotals.find({}).fetch(); for(let sale of sales) { SalesTotals.update(sale._id, {$set: {year: sale.year, total: Math.round(Math.random() * 10000) / 100}}); } } else { let startYear = Math.round(Math.random() * 10) + 2000; let yearCount = 4; for(let i = 0; i < yearCount; i++) //for(let m = 0; m < 12; m++) SalesTotals.insert({year: startYear + i/*, month: m*/, total: Math.round(Math.random() * 10000) / 100}); } } Template.GraphTest.onCreated(function() { let template = Template.instance(); changeData(); }); Template.GraphTest.onRendered(function() { ////Build the SVG Graphs let margin = {top: 20, right: 20, bottom: 30, left: 80}; let width = 960 - margin.left - margin.right; let height = 500 - margin.top - margin.bottom; let x0Scale = d3.scaleBand().range([0, width]).padding(0.1); let yScale = d3.scaleLinear().range([height, 0]); let svg = d3.select('svg.salesGraph') .attr("viewBox", "0 0 960 500") .attr("perserveAspectRatio", "xMidYMid meet") .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); let xLabels = svg.append("g").attr("transform", "translate(0, " + height + ")"); let yLabels = svg.append("g"); Tracker.autorun(function() { let dataset = SalesTotals.find({}).fetch(); //Update scale domains x0Scale.domain([...new Set(dataset.map(item => item.year))]); yScale.domain([0, d3.max(dataset, function(d) {return d.total})]); //Join the data set with the existing data in the svg element. let bars = svg.selectAll('.bar').data(dataset); //Handle existing elements. // bars.[do something here ie: attr('class', 'oldValues')] //Handle the new data elements by adding them to the svg element. bars.enter().append('rect') .attr('class', 'bar') .attr('x', function(d) { return x0Scale(d.year); }) .attr('width', x0Scale.bandwidth()) .attr('y', function(d) { return yScale(d.total); }) .attr('height', function(d) { return height - yScale(d.total); }); bars.transition() // .delay(function(d, i) { // return i / dataset.length * 1000; // }) // this delay will make transistions sequential instead of parallel .duration(500) .attr("x", function(d, i) { return x0Scale(d.year); }) .attr("y", function(d) { return yScale(d.total); }) .attr("width", x0Scale.bandwidth()) .attr("height", function(d) { return height - yScale(d.total); }); //.attr("fill", function(d) { // return "rgb(0, 0, " + (d.total * 10) + ")"; //}); bars.exit() .transition() .duration(500) .attr("x", -x0Scale.bandwidth()) .remove(); let barTexts = svg.selectAll('text.barText').data(dataset); barTexts.enter().append("text") .attr("class", "barText") .attr("text-anchor", "middle") .attr('x', function(d) {return x0Scale(d.year) + x0Scale.bandwidth() / 2;}) .attr('y', function(d) {return yScale(d.total) - 2;}) .text(function(d) {return "$" + Math.round(d.total)}); barTexts.transition() .duration(500) .attr('x', function(d) {return x0Scale(d.year) + x0Scale.bandwidth() / 2;}) .attr('y', function(d) {return yScale(d.total) - 2;}) .text(function(d) {return "$" + Math.round(d.total)}); barTexts.exit() .remove(); //Add the x & y axis labels xLabels.attr("class", "xAxisLabels").call(d3.axisBottom(x0Scale)); yLabels.attr("class", "yAxisLabels").call(d3.axisLeft(yScale)); }); }); Template.GraphTest.helpers({ sales: function() { let sort = []; sort.push(['year', 'asc']); return SalesTotals.find({}, {sort: sort}); }, formatTotal: function(total) { return "$" + total.toFixed(2); } }); Template.GraphTest.events({ 'click button[name="changeData"]': function(event, template) { changeData(); } }); /* //Select… let bars = svg.selectAll("rect").data(dataset, key); //Enter… bars.enter() .append("rect") .attr("x", w) .attr("y", function(d) { return h - yScale(d.total); }) //.attr("width", x0Scale.rangeBand()) .attr("width", x0Scale.bandwidth()) .attr("height", function(d) { return yScale(d.total); }) .attr("fill", function(d) { return "rgb(0, 0, " + (d.total * 10) + ")"; }) .attr("data-id", function(d){ return d._id; }); //Update… bars.transition() // .delay(function(d, i) { // return i / dataset.length * 1000; // }) // this delay will make transistions sequential instead of paralle .duration(500) .attr("x", function(d, i) { return x0Scale(i); }) .attr("y", function(d) { return h - yScale(d.total); }) .attr("width", x0Scale.bandwidth()) .attr("height", function(d) { return yScale(d.total); }).attr("fill", function(d) { return "rgb(0, 0, " + (d.total * 10) + ")"; }); //Exit… bars.exit() .transition() .duration(500) .attr("x", -x0Scale.bandwidth()) .remove(); //Update all labels //Select… let labels = svg.selectAll("text") .data(dataset, key); //Enter… labels.enter() .append("text") .text(function(d) { return d.total; }) .attr("text-anchor", "middle") .attr("x", w) .attr("y", function(d) { return h - yScale(d.total) + 14; }) .attr("font-family", "sans-serif") .attr("font-size", "11px") .attr("fill", "white"); //Update… labels.transition() // .delay(function(d, i) { // return i / dataset.length * 1000; // }) // this delay will make transistions sequential instead of paralle .duration(500) .attr("x", function(d, i) { return x0Scale(i) + x0Scale.bandwidth() / 2; }).attr("y", function(d) { return h - yScale(d.total) + 14; }).text(function(d) { return d.total; }); //Exit… labels.exit() .transition() .duration(500) .attr("x", -x0Scale.bandwidth()) .remove(); */