Skip to content

Commit

Permalink
feat: d3-charts template package
Browse files Browse the repository at this point in the history
  • Loading branch information
keydunov committed Dec 14, 2019
1 parent 664dbfe commit f9bd3fb
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 19 deletions.
34 changes: 15 additions & 19 deletions packages/cubejs-playground/src/libraries/d3.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
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;
const 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)
const svg = d3.select(node)
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
Expand All @@ -14,28 +15,28 @@ const drawFrame = `// Set the dimensions and margins of the graph
"translate(" + margin.left + "," + margin.top + ")");`;

const yAxis = (max) => (`// Add Y axis
var y = d3.scaleLinear()
const 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()
const 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 keys = resultSet.seriesNames().map(s => s.key)
const data = d3.stack()
.keys(keys)
(resultSet.chartPivot())
// Color palette
var color = d3.scaleOrdinal()
const color = d3.scaleOrdinal()
.domain(keys)
.range(COLORS_SERIES)`;

Expand All @@ -47,7 +48,7 @@ const drawByChartType = {
}));
// color palette
var color = d3.scaleOrdinal()
const color = d3.scaleOrdinal()
.domain(data.map(d => d.key ))
.range(COLORS_SERIES)
Expand All @@ -74,7 +75,7 @@ const drawByChartType = {
${stackData}
// Add X axis
var x = d3.scaleBand()
const x = d3.scaleBand()
.range([ 0, width ])
.domain(resultSet.chartPivot().map(c => c.x))
.padding(0.3);
Expand Down Expand Up @@ -123,10 +124,10 @@ const drawByChartType = {
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;
const radius = Math.min(400, 400) / 2 - 40;
// Seprate container to center align pie chart
var pieContainer = svg.attr('height', height)
const pieContainer = svg.attr('height', height)
.append('g')
.attr('transform', 'translate(' + width/2 + ',' + height/2 +')');
Expand All @@ -140,7 +141,6 @@ const drawByChartType = {
.outerRadius(radius)
)
.attr('fill', d => COLORS_SERIES[d.index])
.style("opacity", 0.7)
`
};

Expand All @@ -154,13 +154,9 @@ const draw = (node, resultSet, chartType) => {
${drawByChartType[chartType]}
}
const ${renderFnName} = ({ resultSet }) => {
return (
<div
ref={el => el && draw(el, resultSet, '${chartType}')}
/>
);
};
const ${renderFnName} = ({ resultSet }) => (
<div ref={el => el && draw(el, resultSet, '${chartType}')} />
)
`
);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const TemplatePackage = require("../../TemplatePackage");
const ChartRendererSnippet = require("../../ChartRendererSnippet");

class D3Template extends TemplatePackage {
constructor(chartLibrary) {
super({
name: 'd3-charts',
fileToSnippet: {
'/src/components/ChartRenderer.js': new ChartRendererSnippet(chartLibrary)
},
type: 'charts',
version: '0.0.1'
});
}
}

module.exports = D3Template;
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import * as d3 from 'd3';

const COLORS_SERIES = ["#FF6492", "#141446", "#7A77FF"];
const CHART_HEIGHT = 300;

const drawPieChart = (node, resultSet) => {
const data = resultSet.series()[0].series.map(s => s.value);
const data_ready = d3.pie()(data);

d3.select(node).html("");

// The radius of the pieplot is half the width or half the height (smallest one).
const radius = CHART_HEIGHT / 2 - 40;

// Seprate container to center align pie chart
const svg = d3.select(node)
.append("svg")
.attr("width", node.clientWidth)
.attr("height", CHART_HEIGHT)
.append("g")
.attr('transform', 'translate(' + node.clientWidth/2 + ',' + CHART_HEIGHT/2 +')');

svg
.selectAll('pieArcs')
.data(data_ready)
.enter()
.append('path')
.attr('d', d3.arc()
.innerRadius(0)
.outerRadius(radius)
)
.attr('fill', d => COLORS_SERIES[d.index])
}

const drawChart = (node, resultSet, chartType) => {
if (chartType === 'pie') {
return drawPieChart(node, resultSet);
}

const margin = { top: 10, right: 30, bottom: 30, left: 60 },
width = node.clientWidth - margin.left - margin.right,
height = CHART_HEIGHT - margin.top - margin.bottom;

d3.select(node).html("");
const 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 keys = resultSet.seriesNames().map(s => s.key)

let data, maxData;
if (chartType === 'line') {
data = resultSet.series().map((series) => ({
key: series.title, values: series.series
}));
maxData = d3.max(data.map((s) => d3.max(s.values, (i) => i.value)))
} else {
data = d3.stack()
.keys(keys)
(resultSet.chartPivot())
maxData = d3.max(data.map((s) => d3.max(s, (i) => i[1])))
}


const color = d3.scaleOrdinal()
.domain(keys)
.range(COLORS_SERIES);

let x;
if (chartType === 'bar') {
x = d3.scaleBand()
.range([ 0, width ])
.domain(resultSet.chartPivot().map(c => c.x))
.padding(0.3);
} else {
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 y = d3.scaleLinear()
.domain([0, maxData])
.range([ height, 0 ]);
svg.append("g")
.call(d3.axisLeft(y));

if (chartType === 'line') {
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)
})
} else if (chartType === 'area') {
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]))
)
} else {
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())
}
}

const D3Chart = ({ resultSet, type }) => (
<div
ref={el => el && drawChart(el, resultSet, type)}
/>
);

const TypeToChartComponent = {
line: ({ resultSet }) => (
<D3Chart type='line' resultSet={resultSet} />
),
bar: ({ resultSet }) => (
<D3Chart type='bar' resultSet={resultSet} />
),
area: ({ resultSet }) => (
<D3Chart type='area' resultSet={resultSet} />
),
pie: ({ resultSet }) => (
<D3Chart type='pie' resultSet={resultSet} />
),
};

0 comments on commit f9bd3fb

Please sign in to comment.