Skip to content

Commit

Permalink
D3 charts in playground (#290)
Browse files Browse the repository at this point in the history
* D3 simple charts

* D3: line and bar charts

* D3 area and bar charts

* D3 prettify code
  • Loading branch information
keydunov authored Dec 13, 2019
1 parent 43689f1 commit 16222d1
Show file tree
Hide file tree
Showing 4 changed files with 367 additions and 13 deletions.
1 change: 1 addition & 0 deletions packages/cubejs-playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"codesandbox-import-utils": "^2.1.1",
"component-cookie": "^1.1.4",
"customize-cra": "^0.7.0",
"d3": "^5.14.2",
"history": "^4.9.0",
"less": "^3.10.3",
"less-loader": "^5.0.0",
Expand Down
4 changes: 3 additions & 1 deletion packages/cubejs-playground/src/ChartRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ import ChartContainer from './ChartContainer';
import * as bizChartLibrary from './libraries/bizChart';
import * as rechartsLibrary from './libraries/recharts';
import * as chartjsLibrary from './libraries/chartjs';
import * as d3ChartLibrary from './libraries/d3';
import * as tablesLibrary from './libraries/tables';

export const libraryToTemplate = {
chartjs: { library: chartjsLibrary, title: 'Chart.js' },
recharts: { library: rechartsLibrary, title: 'Recharts' },
bizcharts: { library: bizChartLibrary, title: 'Bizcharts' }
bizcharts: { library: bizChartLibrary, title: 'Bizcharts' },
d3: { library: d3ChartLibrary, title: 'D3' }
};

export const babelConfig = {
Expand Down
169 changes: 169 additions & 0 deletions packages/cubejs-playground/src/libraries/d3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import * as d3 from 'd3';

const drawFrame = `// Set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 30, left: 60},
width = node.clientWidth - margin.left - margin.right, height = 400 - margin.top - margin.bottom;
d3.select(node).html("");
var svg = d3.select(node)
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");`;

const yAxis = (max) => (`// Add Y axis
var y = d3.scaleLinear()
.domain([0, ${max}])
.range([ height, 0 ]);
svg.append("g")
.call(d3.axisLeft(y));`);

const xAxisTime = `// Add X axis
var x = d3.scaleTime()
.domain(d3.extent(resultSet.chartPivot(), c => d3.isoParse(c.x)))
.range([ 0, width ]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));`;

const stackData = `// Transform data into D3 format
var keys = resultSet.seriesNames().map(s => s.key)
const data = d3.stack()
.keys(keys)
(resultSet.chartPivot())
// Color palette
var color = d3.scaleOrdinal()
.domain(keys)
.range(COLORS_SERIES)`;

const drawByChartType = {
line: `
// Prepare data in D3 format
const data = resultSet.series().map((series) => ({
key: series.title, values: series.series
}));
// color palette
var color = d3.scaleOrdinal()
.domain(data.map(d => d.key ))
.range(COLORS_SERIES)
${xAxisTime}
${yAxis(`d3.max(data.map((s) => d3.max(s.values, (i) => i.value)))`)}
// Draw the lines
svg.selectAll(".line")
.data(data)
.enter()
.append("path")
.attr("fill", "none")
.attr("stroke", d => color(d.key))
.attr("stroke-width", 1.5)
.attr("d", (d) => {
return d3.line()
.x(d => x(d3.isoParse(d.x)))
.y(d => y(+d.value))
(d.values)
})
`,
bar: `
${stackData}
// Add X axis
var x = d3.scaleBand()
.range([ 0, width ])
.domain(resultSet.chartPivot().map(c => c.x))
.padding(0.3);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
${yAxis(`d3.max(data.map((s) => d3.max(s, (i) => i[1])))`)}
// Add the bars
svg.append("g")
.selectAll("g")
// Enter in the stack data = loop key per key = group per group
.data(data)
.enter().append("g")
.attr("fill", d => color(d.key))
.selectAll("rect")
// enter a second time = loop subgroup per subgroup to add all rectangles
.data(d => d)
.enter().append("rect")
.attr("x", d => x(d.data.x))
.attr("y", d => y(d[1]))
.attr("height", d => y(d[0]) - y(d[1]))
.attr("width",x.bandwidth())
`,
area: `
${stackData}
${xAxisTime}
${yAxis(`d3.max(data.map((s) => d3.max(s, (i) => i[1])))`)}
// Add the areas
svg
.selectAll("mylayers")
.data(data)
.enter().append("path")
.style("fill", d => color(d.key))
.attr("d", d3.area()
.x(d => x(d3.isoParse(d.data.x)))
.y0(d => y(d[0]))
.y1(d => y(d[1]))
)
`,
pie: `const data = resultSet.series()[0].series.map(s => s.value);
const data_ready = d3.pie()(data);
// The radius of the pieplot is half the width or half the height (smallest one).
var radius = Math.min(400, 400) / 2 - 40;
// Seprate container to center align pie chart
var pieContainer = svg.attr('height', height)
.append('g')
.attr('transform', 'translate(' + width/2 + ',' + height/2 +')');
pieContainer
.selectAll('pieArcs')
.data(data_ready)
.enter()
.append('path')
.attr('d', d3.arc()
.innerRadius(0)
.outerRadius(radius)
)
.attr('fill', d => COLORS_SERIES[d.index])
.style("opacity", 0.7)
`
};

export const sourceCodeTemplate = ({ chartType, renderFnName }) => (
`
import * as d3 from 'd3';
const COLORS_SERIES = ['#FF6492', '#141446', '#7A77FF'];
const draw = (node, resultSet, chartType) => {
${drawFrame}
${drawByChartType[chartType]}
}
const ${renderFnName} = ({ resultSet }) => {
return (
<div
ref={el => el && draw(el, resultSet, '${chartType}')}
/>
);
};
`
);

export const imports = {
'd3': d3
};
Loading

0 comments on commit 16222d1

Please sign in to comment.