Skip to content

Commit a6bde7e

Browse files
Merge pull request #137 from ignoreintuition/issue-25-bubble
Issue 25 bubble
2 parents e263861 + 05713b5 commit a6bde7e

File tree

6 files changed

+749
-306
lines changed

6 files changed

+749
-306
lines changed

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,31 @@ export default {
9292
}
9393
}
9494
```
95+
Bubble Charts require three metrics (v1, v2, and v3). These should be passed as triplets
96+
97+
```JavaScript
98+
export default {
99+
name: 'example',
100+
data () {
101+
return {
102+
chartData: {
103+
chartType: "bubbleChart",
104+
selector: "chart",
105+
title: "Important Data",
106+
width: 400,
107+
height: 200,
108+
triplet: ['count', 'pyCount', 'revenue']
109+
data: [
110+
{'count': 120,
111+
'fruit': 'apples'},
112+
{'count': 250,
113+
'fruit': 'oranges'}
114+
]
115+
}
116+
}
117+
}
118+
}
119+
```
95120
### Overrides
96121
If you need to override any of the default values of the charts (pallette colors, ticks, margins, etc) you can pass an overrides object to you chartData.
97122

@@ -131,6 +156,7 @@ chartData: {
131156
* scatterPlot: a graph in which the values of two variables are plotted along two axes, the pattern of the resulting points revealing any correlation present.
132157
* pieChart: a chart in which a circle is divided into slices to illustrate proportion
133158
* areaChart: a chart which displays graphically quantitative data
159+
* bubleChart: a bubble chart is a variation of a scatter chart in which the data points are replaced with bubbles, and an additional dimension of the data is represented in the size of the bubbles.
134160

135161
### Charts that support two or more metrics
136162
* barChart

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "v-chart-plugin",
33
"main": "./dist/module/v-chart-plugin.js",
4-
"version": "0.2.15",
4+
"version": "0.3.0",
55
"description": "This plugin is designed to allow Vue.js developers to incorporate fully reactive and customizable charts into your applications. Uses D3.js for charting.",
66
"keywords": [
77
"vue",

src/components/chartExample.vue

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<div class="col-6 col-md-8">
1818
<div class="row">
1919
<div class="col-12">
20-
<v-chart v-bind:chartData="barChartData"></v-chart>
20+
<v-chart v-bind:chartData="bubbleChartData"></v-chart>
2121
</div>
2222
<div class="col-12 col-lg-6">
2323
<v-chart v-bind:chartData="areaChartData"></v-chart>
@@ -75,15 +75,14 @@ export default {
7575
width: 50
7676
},
7777
},
78-
barChartData: {
79-
chartType: "barChart",
78+
bubbleChartData: {
79+
chartType: "bubbleChart",
8080
selector: "chart",
8181
title: "Bar Chart",
8282
subtitle: "Sales by month",
8383
width: 600,
8484
height: 500,
85-
metric: ["total", "forecast"],
86-
dim: "month",
85+
triplet: ["total", "forecast", "yoy"],
8786
data: sales,
8887
goal: 500,
8988
legends: {

src/import/bubbleChart.js

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/**
2+
* @fileOverview Line Graph component definition
3+
*
4+
* @author Brian Greig
5+
*
6+
* @requires NPM:d3:Vue
7+
* @requires src/v-chart-plugin.js
8+
*/
9+
const d3 = Object.assign({},
10+
require('d3-selection'),
11+
require('d3-scale'),
12+
require('d3-axis'),
13+
require('d3-shape'));
14+
/**
15+
* Builds a Line Graph.
16+
* @module lineGraph
17+
*/
18+
19+
const lineGraph = function chart(mode) {
20+
/**
21+
* The SVG that stores the chart
22+
* @member svgContainer
23+
*/
24+
const svgContainer = d3.select(`#${this.chartData.selector}`);
25+
/**
26+
* The configuration of the coordinate system
27+
* @member cs
28+
*/
29+
let cs = {
30+
palette: {
31+
pointFill: '#005792',
32+
pointStroke: '#d1f4fa',
33+
},
34+
x: {
35+
domain: [],
36+
range: [],
37+
axisHeight: 20,
38+
},
39+
y: {
40+
axisWidth: 30,
41+
ticks: 5,
42+
},
43+
r: {
44+
45+
}
46+
};
47+
48+
/**
49+
* Runs when a new element is added to the dataset
50+
* @member enter
51+
* @function
52+
* @param {Object} points (svg element)
53+
*/
54+
const enter = (points) => {
55+
points.enter()
56+
.append('circle')
57+
.attr('class', this.selector)
58+
.attr('r', d => cs.r.scale(d.metric[0][this.triplet[2]]))
59+
.attr('cx', d => cs.x.scale(d.metric[0][this.triplet[0]]) + cs.y.axisWidth + 5)
60+
.attr('cy', d => cs.y.scale(d.metric[0][this.triplet[1]]));
61+
return points;
62+
};
63+
/**
64+
* Runs when a value of an element in dataset is changed
65+
* @member transition
66+
* @function
67+
* @param {Object} points (svg element)
68+
*/
69+
const transition = (points) => {
70+
points.transition()
71+
.attr('r', d => cs.r.scale(d.metric[0][this.triplet[2]]))
72+
.attr('cx', d => cs.x.scale(d.metric[0][this.triplet[0]]) + cs.y.axisWidth + 5)
73+
.attr('cy', d => cs.y.scale(d.metric[0][this.triplet[1]]));
74+
return points;
75+
};
76+
77+
/**
78+
* Runs when an element is removed from the dataset
79+
* @member exit
80+
* @function
81+
* @param {Object} points (svg element)
82+
*/
83+
const exit = (points) => {
84+
points.exit().remove();
85+
return points;
86+
};
87+
88+
/**
89+
* Builds the scales for the x and y axes
90+
* @member buildScales
91+
* @function
92+
*/
93+
const buildScales = cs => {
94+
cs.y.scale = d3.scaleLinear()
95+
.domain([this.minTriplet.v1, this.maxTriplet.v1])
96+
.range([this.displayHeight - cs.x.axisHeight, this.header]);
97+
cs.x.scale = d3.scaleLinear()
98+
.domain([this.minTriplet.v2, this.maxTriplet.v2])
99+
.range([0, this.width]);
100+
cs.r.scale = d3.scaleLinear()
101+
.domain([this.minTriplet.v3, this.maxTriplet.v3])
102+
.range([0, 20]);
103+
};
104+
/**
105+
* Draws the x and y axes on the svg
106+
* @member drawAxis
107+
* @function
108+
*/
109+
const drawAxis = cs => {
110+
cs.x.axis = d3.axisBottom().scale(cs.x.scale);
111+
cs.x.xOffset = cs.y.axisWidth + 5;
112+
cs.x.yOffset = this.displayHeight - cs.x.axisHeight;
113+
cs.y.axis = d3.axisLeft().ticks(cs.y.ticks, 's').scale(cs.y.scale);
114+
cs.y.xOffset = cs.y.axisWidth;
115+
cs.y.yOffset = 0;
116+
svgContainer.append('g').attr('class', 'axis').attr('transform', `translate(${cs.x.xOffset}, ${cs.x.yOffset})`)
117+
.call(cs.x.axis);
118+
svgContainer.append('g').attr('class', 'axis').attr('transform', `translate(${cs.y.xOffset},${cs.y.yOffset})`)
119+
.call(cs.y.axis);
120+
};
121+
122+
const points = svgContainer.selectAll('circle').data(this.ds);
123+
124+
cs = this.setOverrides(cs, this.chartData.overrides);
125+
126+
buildScales(cs);
127+
drawAxis(cs);
128+
enter(points);
129+
transition(points);
130+
exit(points);
131+
132+
return cs;
133+
};
134+
135+
export default lineGraph;

src/v-chart-plugin.js

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import lineGraph from './import/lineGraph';
1313
import scatterPlot from './import/scatterPlot';
1414
import pieChart from './import/pieChart';
1515
import areaChart from './import/areaChart';
16+
import bubbleChart from './import/bubbleChart';
1617

1718
const d3 = Object.assign({},
1819
require('d3-selection'));
@@ -189,6 +190,7 @@ const Chart = {
189190
...((typeof pieChart !== 'undefined') && { pieChart }),
190191
...((typeof areaChart !== 'undefined') && { areaChart }),
191192
...((typeof lineGraph !== 'undefined') && { lineGraph }),
193+
...((typeof bubbleChart !== 'undefined') && { bubbleChart }),
192194
},
193195
computed: {
194196
/**
@@ -204,7 +206,7 @@ const Chart = {
204206
return ds.data.map((d) => {
205207
const td = { metric: [] };
206208
if (!ds.metric[0])
207-
td.metric[0] = d;
209+
td.metric[0] = d || 0;
208210
else {
209211
ds.metric.forEach(function(e, i){
210212
td.metric[i] = d[e] || 0;
@@ -228,7 +230,16 @@ const Chart = {
228230
* @returns {array} Metrics
229231
*/
230232
metric() {
231-
return (Array.isArray(this.chartData.metric)) ? this.chartData.metric : new Array(this.chartData.metric);
233+
const metric = (Array.isArray(this.chartData.metric)) ? this.chartData.metric : new Array(this.chartData.metric);
234+
return metric;
235+
},
236+
/**
237+
* triplet getter function
238+
* @memberOf Chart
239+
* @returns {array} Metrics
240+
*/
241+
triplet() {
242+
return this.chartData.triplet;
232243
},
233244
/**
234245
* Height getter function
@@ -262,19 +273,58 @@ const Chart = {
262273
});
263274
return max;
264275
},
276+
/**
277+
* Get the maxium value for triplet
278+
* @memberOf Chart
279+
* @returns {Array} Max values for triplet
280+
*/
281+
maxTriplet() {
282+
const max = {
283+
v1: 0,
284+
v2: 0,
285+
v3: 0
286+
};
287+
this.ds.forEach(e => {
288+
max.v1 = max.v1 > e.metric[0][this.triplet[0]] ? max.v1 : e.metric[0][this.triplet[0]];
289+
max.v2 = max.v2 > e.metric[0][this.triplet[1]] ? max.v2 : e.metric[0][this.triplet[1]];
290+
max.v3 = max.v3 > e.metric[0][this.triplet[2]] ? max.v3 : e.metric[0][this.triplet[2]];
291+
});
292+
return max;
293+
},
265294
/**
266295
* Get the minimum value for dataset
267296
* @memberOf Chart
268297
* @returns {number} Min value for metric
269298
*/
270299
min() {
271-
let max = 0;
272300
var results = [];
273301
this.ds.forEach(e => {
274302
results = results.concat([...e.metric]);
275303
});
276304
return Math.min(...results.map(o => o));
277305
},
306+
/**
307+
* Get the minimum value for triplet
308+
* @memberOf Chart
309+
* @returns {Array} Min values for triplet
310+
*/
311+
minTriplet() {
312+
var results = {
313+
v1: [],
314+
v2: [],
315+
v3: []
316+
};
317+
this.ds.forEach(e => {
318+
results.v1.push(e.metric[0][this.triplet[0]])
319+
results.v2.push(e.metric[0][this.triplet[1]])
320+
results.v3.push(e.metric[0][this.triplet[2]])
321+
})
322+
return {
323+
v1: (Math.min(...results.v1.map(o => o))),
324+
v2: (Math.min(...results.v2.map(o => o))),
325+
v3: (Math.min(...results.v3.map(o => o)))
326+
};
327+
},
278328
/**
279329
* Gets the height of the dispaly area
280330
* @memberOf Chart

0 commit comments

Comments
 (0)