Skip to content

Instantly share code, notes, and snippets.

@kristw
Last active November 9, 2016 21:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kristw/4628672d57f5fe822bb4c84b682abb6e to your computer and use it in GitHub Desktop.
Save kristw/4628672d57f5fe822bb4c84b682abb6e to your computer and use it in GitHub Desktop.
d3Kit - Reusable <svg> chart
license: mit

Bubble chart created with d3Kit v3. Click on the circles to see info

<!DOCTYPE html>
<title>blockup</title>
<link href='style.css' rel='stylesheet' />
<body>
<button id="data-btn">Change data</button>
<button id="resize-btn">Resize</button>
<div id="chart"></div>
<div id="info"></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://rawgit.com/twitter/d3kit/master/dist/d3kit.min.js"></script>
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
<script type="text/babel" src="MyChart.js"></script>
<script type="text/babel" src='main.js'></script>
</body>
//---------------------------------------------------
// Generate random data
//---------------------------------------------------
function generateBubbles() {
const array = [];
for(let i=0;i<100;i++){
array.push({
x: Math.random()*100,
y: Math.random()*100,
r: Math.random()*5+3
});
}
return array;
}
const bubbles = generateBubbles();
const info = document.querySelector('#info');
//---------------------------------------------------
// Use the bubble chart
//---------------------------------------------------
const chart = new MyChart('#chart', {
margin: { top: 20 },
initialWidth: 300,
initialHeight: 300,
})
.data(bubbles)
// handle bubbleClick event
.on('bubbleClick', d => { info.innerHTML = (JSON.stringify(d)); })
.fit({
width: '100%',
height: 400
}, true);
//---------------------------------------------------
// Buttons
//---------------------------------------------------
document.querySelector('#data-btn')
.addEventListener('click', () => {
chart.data(generateBubbles());
})
let i = 1;
document.querySelector('#resize-btn')
.addEventListener('click', () => {
chart.dimension([200 * i, 200 * i]);
i = i===1 ? 2 : 1;
})
const { scaleLinear, scaleOrdinal, schemeCategory10 } = d3;
const { axisLeft, axisBottom } = d3;
const { extent } = d3;
const { SvgChart, helper } = d3Kit;
class MyChart extends SvgChart {
static getDefaultOptions() {
return helper.deepExtend(
super.getDefaultOptions(),
{
margin: {top: 60, right: 60, bottom: 60, left: 60},
initialWidth: 800,
initialHeight: 460
}
);
}
/**
* Define the names of custom events that can be dispatched from this chart
* @return {Array[String]} event names
*/
static getCustomEventNames() {
return ['bubbleClick'];
}
constructor(selector, options) {
super(selector, options);
// create <g> layers
this.layers.create(['content', 'x-axis', 'y-axis']);
// add custom variables
this.xScale = scaleLinear();
this.yScale = scaleLinear();
this.color = scaleOrdinal(schemeCategory10);
this.xAxis = axisBottom().scale(this.xScale);
this.yAxis = axisLeft().scale(this.yScale);
// add basic event listeners
this.visualize = this.visualize.bind(this);
this.on('resize.default', this.visualize);
this.on('data.default', this.visualize);
}
// You can define a new function for this class.
visualize() {
if(!this.hasData()){
this.layers.get('content').selectAll('*').remove();
return;
}
const data = this.data();
this.xScale.domain(extent(data, d => d.x))
.range([0, this.getInnerWidth()]);
this.yScale.domain(extent(data, d => d.y))
.range([this.getInnerHeight(), 0]);
this.layers.get('x-axis')
.attr('transform', `translate(0,${this.getInnerHeight()})`)
.call(this.xAxis);
this.layers.get('y-axis')
.call(this.yAxis);
const selection = this.layers.get('content').selectAll('circle')
.data(data);
selection.exit().remove();
const sEnter = selection.enter().append('circle')
.attr('cx', d => this.xScale(d.x))
.attr('cy', d => this.yScale(d.y))
.on('click', (...args) => {
this.dispatcher.apply('bubbleClick', this, args);
});
selection.merge(sEnter)
.attr('cx', d => this.xScale(d.x))
.attr('cy', d => this.yScale(d.y))
.attr('r', d => d.r)
.style('fill', (d,i) => this.color(i));
}
}
window.MyChart = MyChart;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment