diff --git a/Chart/BarChart.js b/Chart/BarChart.js new file mode 100644 index 0000000..410909a --- /dev/null +++ b/Chart/BarChart.js @@ -0,0 +1,202 @@ +(function (jsOMS) +{ + "use strict"; + + jsOMS.Chart.BarChart = function (id) + { + this.chart = new jsOMS.Chart.ChartAbstract(id); + + // Setting default chart values + this.chart.margin = {top: 5, right: 0, bottom: 0, left: 0}; + this.chart.color = d3.scale.category10(); + this.chart.axis = { + x: { + visible: true, + label: { + visible: true, + text: 'X-Axis', + position: "center", + anchor: 'middle' + }, + tick: { + prefix: '', + orientation: 'bottom', + size: 7 + }, + min: 0, + max: 0 + }, + y: { + visible: true, + label: { + visible: true, + text: 'Y-Axis', + position: 'center', + anchor: 'middle' + }, + tick: { + prefix: '', + orientation: 'bottom', + size: 7 + }, + min: 0, + max: 0 + } + }; + + this.chart.grid = { + x: { + visible: false + }, + y: { + visible: true + } + }; + + this.chart.dataSettings.marker.visible = false; + this.chart.subtype = 'stacked'; + }; + + jsOMS.Chart.BarChart.prototype.getChart = function () + { + return this.chart; + }; + + jsOMS.Chart.BarChart.prototype.setData = function (data) + { + this.chart.setData(data); + }; + + jsOMS.Chart.BarChart.prototype.draw = function () + { + let rect, svg, x, xAxis1, xAxis2, y, yAxis1, yAxis2, xGrid, yGrid, zoom, self = this; + + if (this.chart.subtype === 'grouped') { + this.chart.axis.y.max = d3.max(this.chart.dataset, function (layer) + { + return d3.max(layer.points, function (d) + { + return d.y; + }); + }); + } else { + this.chart.axis.y.max = d3.max(this.chart.dataset, function (layer) + { + return d3.max(layer.points, function (d) + { + return d.y0 + d.y; + }); + }); + } + + this.chart.calculateDimension(); + + x = this.chart.createXScale('ordinal'); + y = this.chart.createYScale('linear'); + xAxis1 = this.chart.createXAxis(x); + yAxis1 = this.chart.createYAxis(y); + xGrid = this.chart.createXGrid(x); + yGrid = this.chart.createYGrid(y); + + x.domain(d3.range(this.chart.dataset[0].points.length)).rangeRoundBands([0, this.chart.dimension.width - this.chart.margin.right - this.chart.margin.left], .1); + y.domain([0, this.chart.axis.y.max + 1]); + + svg = this.chart.chartSelect.append("svg") + .attr("width", this.chart.dimension.width) + .attr("height", this.chart.dimension.height) + .append("g").attr("transform", "translate(" + + (this.chart.margin.left) + "," + + (this.chart.margin.top) + ")"); + + this.chart.drawGrid(svg, xGrid, yGrid); + + let dataPoint, dataPointEnter, + temp = this.drawData(svg, x, y, dataPointEnter, dataPoint); + dataPointEnter = temp[0]; + dataPoint = temp[1]; + this.chart.drawMarker(svg, x, y, dataPointEnter, dataPoint); + this.chart.drawLegend(svg, dataPointEnter, dataPoint); + this.chart.drawText(svg); + this.chart.drawAxis(svg, xAxis1, yAxis1); + + if (this.chart.shouldRedraw) { + this.redraw(); + } + }; + + jsOMS.Chart.BarChart.prototype.redraw = function () + { + this.chart.shouldRedraw = false; + this.chart.chartSelect.select("*").remove(); + this.draw(); + }; + + jsOMS.Chart.BarChart.prototype.drawData = function (svg, x, y, dataPointEnter, dataPoint) + { + let self = this, rect; + + dataPoint = svg.selectAll(".dataPoint").data(this.chart.dataset, function (c) + { + return c.id; + }); + + dataPointEnter = dataPoint.enter().append("g").attr("class", "dataPoint") + .style("fill", function (d) + { + return self.chart.color(d.name); + }); + + rect = dataPointEnter.selectAll("rect") + .data(function (d) + { + return d.points; + }) + .enter().append("rect") + .attr("x", function (d) + { + return x(d.x); + }) + .attr("y", this.chart.dimension.height - this.chart.margin.top - this.chart.margin.bottom) + .attr("width", x.rangeBand()) + .attr("height", 0); + + if(this.chart.subtype === 'stacked') { + rect.transition() + .delay(function (d, i) + { + return i * 10; + }) + .attr("y", function (d) + { + return y(d.y0 + d.y); + }) + .attr("height", function (d) + { + return y(d.y0) - y(d.y0 + d.y); + }); + } else { + rect.transition() + .duration(500) + .delay(function (d, i) + { + return i * 10; + }) + .attr("x", function (d, i, j) + { + return x(d.x) + x.rangeBand() / self.chart.dataset.length * j; + }) + .attr("width", x.rangeBand() /self.chart.dataset.length) + .transition() + .attr("y", function (d) + { + return y(d.y); + }) + .attr("height", function (d) + { + return self.chart.dimension.height - self.chart.margin.top - self.chart.margin.bottom - y(d.y); + }); + } + + return [dataPointEnter, dataPoint]; + }; +}(window.jsOMS = window.jsOMS || {})); diff --git a/Chart/DiffAreaChart.js b/Chart/DiffAreaChart.js index e69de29..9a0f8af 100644 --- a/Chart/DiffAreaChart.js +++ b/Chart/DiffAreaChart.js @@ -0,0 +1,25 @@ +(function (jsOMS) +{ + "use strict"; + + jsOMS.Chart.DiffAreaChart = function (id) + { + this.chart = new jsOMS.Chart.LineChart(id); + this.chart.getChart().subtype = 'area'; + }; + + jsOMS.Chart.DiffAreaChart.prototype.getChart = function () + { + return this.chart.getChart(); + }; + + jsOMS.Chart.DiffAreaChart.prototype.setData = function (data) + { + this.chart.setData(data); + }; + + jsOMS.Chart.DiffAreaChart.prototype.draw = function () + { + return this.chart.draw(); + }; +}(window.jsOMS = window.jsOMS || {})); diff --git a/Chart/GroupedBarChart.js b/Chart/GroupedBarChart.js new file mode 100644 index 0000000..dfed8c7 --- /dev/null +++ b/Chart/GroupedBarChart.js @@ -0,0 +1,25 @@ +(function (jsOMS) +{ + "use strict"; + + jsOMS.Chart.GroupedBarChart = function (id) + { + this.chart = new jsOMS.Chart.BarChart(id); + this.chart.getChart().subtype = 'grouped'; + }; + + jsOMS.Chart.GroupedBarChart.prototype.getChart = function () + { + return this.chart.getChart(); + }; + + jsOMS.Chart.GroupedBarChart.prototype.setData = function (data) + { + this.chart.setData(data); + }; + + jsOMS.Chart.GroupedBarChart.prototype.draw = function () + { + this.chart.draw(); + }; +}(window.jsOMS = window.jsOMS || {})); diff --git a/Chart/PieChart.js b/Chart/PieChart.js index 476eb8b..30ebf60 100644 --- a/Chart/PieChart.js +++ b/Chart/PieChart.js @@ -25,16 +25,6 @@ this.chart.calculateDimension(); - let radius = ( - Math.min(this.chart.dimension.width, this.chart.dimension.height) / 2 - - Math.max(this.chart.margin.right + this.chart.margin.left, - this.chart.margin.top + this.chart.margin.bottom) - ); - - arc = d3.svg.arc() - .outerRadius(radius) - .innerRadius(radius - radius*this.chart.dataSettings.style.strokewidth); - svg = this.chart.chartSelect.append("svg") .attr("width", this.chart.dimension.width) .attr("height", this.chart.dimension.height) @@ -43,7 +33,7 @@ + (this.chart.margin.top) + ")"); let dataPoint, dataPointEnter, - temp = this.drawData(svg, arc, dataPointEnter, dataPoint); + temp = this.drawData(svg, dataPointEnter, dataPoint); dataPointEnter = temp[0]; dataPoint = temp[1]; @@ -68,7 +58,7 @@ this.draw(); }; - jsOMS.Chart.PieChart.prototype.drawData = function (svg, arc, dataPointEnter, dataPoint) + jsOMS.Chart.PieChart.prototype.drawData = function (svg, dataPointEnter, dataPoint) { let self = this, pie = d3.layout.pie() @@ -76,15 +66,21 @@ .value(function (d) { return d.value; - }); - - dataPoint = svg.selectAll(".dataPoint").data(this.chart.dataset, function (c) - { - return c.id; - }); + }), + radius = ( + Math.min(this.chart.dimension.width, this.chart.dimension.height) / 2 + - Math.max(this.chart.margin.right + this.chart.margin.left, + this.chart.margin.top + this.chart.margin.bottom) + ), + innerRadius = radius - radius*self.chart.dataSettings.style.strokewidth, + arc = d3.svg.arc() + .outerRadius(function() { return radius; }) + .innerRadius(function() { return innerRadius; }); + dataPoint = svg.selectAll(".dataPoint").data(this.chart.dataset); + dataPoint.enter().append("g").attr("class", "dataPoint"); - + dataPointEnter = dataPoint.selectAll("path") .data(function (d) { diff --git a/Chart/StackedBarChart.js b/Chart/StackedBarChart.js new file mode 100644 index 0000000..5048199 --- /dev/null +++ b/Chart/StackedBarChart.js @@ -0,0 +1,25 @@ +(function (jsOMS) +{ + "use strict"; + + jsOMS.Chart.StackedBarChart = function (id) + { + this.chart = new jsOMS.Chart.BarChart(id); + this.chart.getChart().subtype = 'stacked'; + }; + + jsOMS.Chart.StackedBarChart.prototype.getChart = function () + { + return this.chart.getChart(); + }; + + jsOMS.Chart.StackedBarChart.prototype.setData = function (data) + { + this.chart.setData(data); + }; + + jsOMS.Chart.StackedBarChart.prototype.draw = function () + { + this.chart.draw(); + }; +}(window.jsOMS = window.jsOMS || {})); diff --git a/Chart/VWaterfallChart.js b/Chart/VWaterfallChart.js new file mode 100644 index 0000000..72af600 --- /dev/null +++ b/Chart/VWaterfallChart.js @@ -0,0 +1,158 @@ +(function (jsOMS) +{ + "use strict"; + + jsOMS.Chart.VWaterfallChart = function (id) + { + this.chart = new jsOMS.Chart.ChartAbstract(id); + + // Setting default chart values + this.chart.margin = {top: 5, right: 0, bottom: 0, left: 0}; + this.chart.color = d3.scale.category10(); + this.chart.axis = { + x: { + visible: true, + label: { + visible: true, + text: 'X-Axis', + position: "center", + anchor: 'middle' + }, + tick: { + prefix: '', + orientation: 'bottom', + size: 7 + }, + min: 0, + max: 0 + }, + y: { + visible: true, + label: { + visible: true, + text: 'Y-Axis', + position: 'center', + anchor: 'middle' + }, + tick: { + prefix: '', + orientation: 'bottom', + size: 7 + }, + min: 0, + max: 0 + } + }; + + this.chart.grid = { + x: { + visible: false + }, + y: { + visible: true + } + }; + this.chart.subtype = 'waterfall'; + }; + + jsOMS.Chart.VWaterfallChart.prototype.getChart = function () + { + return this.chart; + }; + + jsOMS.Chart.VWaterfallChart.prototype.setData = function (data) + { + let dataset = [{id: 1, name: 'Dataset', points: []}], + length = data.length, + add = 0; + + // todo: remove value since positive and negative can be checked by looking at the diff of y-y0 + for(let i = 0; i < length - 1; i++) { + dataset[0].points[i] = { name: data[i].name, y0: add, y: data[i].value + add }; + add += data[i].value; + } + + dataset[0].points[length - 1] = { name: data[length - 1].name, y0: 0, y: add }; + + this.chart.setData(dataset); + }; + + jsOMS.Chart.VWaterfallChart.prototype.draw = function () + { + let bar, svg, x, xAxis1, xAxis2, y, yAxis1, yAxis2, xGrid, yGrid, zoom, self = this; + + this.chart.calculateDimension(); + + x = this.chart.createXScale('ordinal'); + y = this.chart.createYScale('linear'); + xAxis1 = this.chart.createXAxis(x); + yAxis1 = this.chart.createYAxis(y); + xGrid = this.chart.createXGrid(x); + yGrid = this.chart.createYGrid(y); + + x.domain(this.chart.dataset[0].points.map(function(d) { return d.name; })); + y.domain([0, d3.max(this.chart.dataset[0].points, function(d) { return d.y*1.05; })]); + + svg = this.chart.chartSelect.append("svg") + .attr("width", this.chart.dimension.width) + .attr("height", this.chart.dimension.height) + .append("g").attr("transform", "translate(" + + (this.chart.margin.left) + "," + + (this.chart.margin.top) + ")"); + + this.chart.drawGrid(svg, xGrid, yGrid); + + let dataPoint, dataPointEnter, + temp = this.drawData(svg, x, y, dataPointEnter, dataPoint); + dataPointEnter = temp[0]; + dataPoint = temp[1]; + + this.chart.drawText(svg); + this.chart.drawAxis(svg, xAxis1, yAxis1); + + if (this.chart.shouldRedraw) { + this.redraw(); + } + }; + + jsOMS.Chart.VWaterfallChart.prototype.redraw = function () + { + this.chart.shouldRedraw = false; + this.chart.chartSelect.select("*").remove(); + this.draw(); + }; + + jsOMS.Chart.VWaterfallChart.prototype.drawData = function (svg, x, y, dataPointEnter, dataPoint) + { + let self = this; + + dataPoint = svg.selectAll(".dataPoint").data(this.chart.dataset[0].points, function (c) + { + return c.name; + }); + + dataPointEnter = dataPoint.enter().append("g") + .attr("class", function(d) { return "dataPoint " + (d.y < d.y0 ? 'negative' : 'positive'); }) + .attr("transform", function(d) { return "translate(" + x(d.name) + ",0)"; }); + + dataPointEnter.append("rect") + .attr("y", function(d) { return y( Math.max(d.y0, d.y) ); }) + .attr("height", function(d) { return Math.abs( y(d.y0) - y(d.y) ); }) + .attr("width", x.rangeBand()); + + dataPointEnter.append("text") + .attr("x", x.rangeBand() / 2) + .attr("y", function(d) { return y(d.y) + 5; }) + .attr("dy", function(d) { return ((d.y < d.y0) ? '-' : '') + ".75em" }) + .text(function(d) { return d.y - d.y0; }); + + dataPointEnter.filter(function(d) { return d.class != "total" }).append("line") + .attr("class", "connector") + .attr("x1", x.rangeBand() + 5 ) + .attr("y1", function(d) { return y(d.y) } ) + .attr("x2", x.rangeBand() / ( 1 - 5) - 5 ) + .attr("y2", function(d) { return y(d.y) } ); + + return [dataPointEnter, dataPoint]; + }; +}(window.jsOMS = window.jsOMS || {})); diff --git a/Chart/WaterfallChart.js b/Chart/WaterfallChart.js index eada2ec..8b0149a 100644 --- a/Chart/WaterfallChart.js +++ b/Chart/WaterfallChart.js @@ -128,7 +128,7 @@ dataPoint = svg.selectAll(".dataPoint").data(this.chart.dataset[0].points, function (c) { - return c.id; + return c.name; }); dataPointEnter = dataPoint.enter().append("g")