feat: kick start funnel Chart
This commit is contained in:
parent
39211a406d
commit
edf6077eb4
91
src/js/charts/FunnelChart.js
Normal file
91
src/js/charts/FunnelChart.js
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
import AggregationChart from './AggregationChart';
|
||||||
|
import { getOffset } from '../utils/dom';
|
||||||
|
import { getComponent } from '../objects/ChartComponents';
|
||||||
|
import { PERCENTAGE_BAR_DEFAULT_HEIGHT, PERCENTAGE_BAR_DEFAULT_DEPTH } from '../utils/constants';
|
||||||
|
|
||||||
|
export default class FunnelChart extends AggregationChart {
|
||||||
|
constructor(parent, args) {
|
||||||
|
super(parent, args);
|
||||||
|
this.type = 'funnel';
|
||||||
|
this.setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
setMeasures(options) {
|
||||||
|
let m = this.measures;
|
||||||
|
this.funnelOptions = options.funnelOptions || {};
|
||||||
|
|
||||||
|
let opts = this.funnelOptions;
|
||||||
|
opts.height = opts.height || PERCENTAGE_BAR_DEFAULT_HEIGHT;
|
||||||
|
|
||||||
|
m.paddings.right = 30;
|
||||||
|
m.legendHeight = 60;
|
||||||
|
m.baseHeight = (opts.height + opts.depth * 0.5) * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
setupComponents() {
|
||||||
|
let s = this.state;
|
||||||
|
|
||||||
|
let componentConfigs = [
|
||||||
|
[
|
||||||
|
'percentageBars',
|
||||||
|
{
|
||||||
|
barHeight: this.funnelOptions.height,
|
||||||
|
barDepth: this.funnelOptions.depth,
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
return {
|
||||||
|
xPositions: s.xPositions,
|
||||||
|
widths: s.widths,
|
||||||
|
colors: this.colors
|
||||||
|
};
|
||||||
|
}.bind(this)
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
this.components = new Map(componentConfigs
|
||||||
|
.map(args => {
|
||||||
|
let component = getComponent(...args);
|
||||||
|
return [args[0], component];
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
calc() {
|
||||||
|
super.calc();
|
||||||
|
let s = this.state;
|
||||||
|
|
||||||
|
s.xPositions = [];
|
||||||
|
s.widths = [];
|
||||||
|
|
||||||
|
let xPos = 0;
|
||||||
|
s.sliceTotals.map((value) => {
|
||||||
|
let width = this.width * value / s.grandTotal;
|
||||||
|
s.widths.push(width);
|
||||||
|
s.xPositions.push(xPos);
|
||||||
|
xPos += width;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
makeDataByIndex() { }
|
||||||
|
|
||||||
|
bindTooltip() {
|
||||||
|
let s = this.state;
|
||||||
|
this.container.addEventListener('mousemove', (e) => {
|
||||||
|
let bars = this.components.get('percentageBars').store;
|
||||||
|
let bar = e.target;
|
||||||
|
if(bars.includes(bar)) {
|
||||||
|
|
||||||
|
let i = bars.indexOf(bar);
|
||||||
|
let gOff = getOffset(this.container), pOff = getOffset(bar);
|
||||||
|
|
||||||
|
let x = pOff.left - gOff.left + parseInt(bar.getAttribute('width'))/2;
|
||||||
|
let y = pOff.top - gOff.top;
|
||||||
|
let title = (this.formattedLabels && this.formattedLabels.length>0
|
||||||
|
? this.formattedLabels[i] : this.state.labels[i]) + ': ';
|
||||||
|
let fraction = s.sliceTotals[i]/s.grandTotal;
|
||||||
|
|
||||||
|
this.tip.setValues(x, y, {name: title, value: (fraction*100).toFixed(1) + "%"});
|
||||||
|
this.tip.showTip();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -190,6 +190,32 @@ export function percentageBar(x, y, width, height,
|
|||||||
return createSVG("rect", args);
|
return createSVG("rect", args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function funnelSlice(className, startPositions, height, fill='none') {
|
||||||
|
const endPosition = []
|
||||||
|
let [point_a, point_b] = startPositions[0]
|
||||||
|
|
||||||
|
// For an equilateral triangle, the angles are always 60 deg.
|
||||||
|
// The end points on the polygons can be created using the following formula
|
||||||
|
//
|
||||||
|
// end_point_x = start_x + height
|
||||||
|
// end_point_y = start_y +/- height * 1/2
|
||||||
|
//
|
||||||
|
// b
|
||||||
|
// _______________________________
|
||||||
|
// \ |_| /
|
||||||
|
// \ | /
|
||||||
|
// \ | h /
|
||||||
|
// \ | /
|
||||||
|
// \|____________________/
|
||||||
|
//
|
||||||
|
// b = h * cos(60 deg)
|
||||||
|
//
|
||||||
|
|
||||||
|
endPosition[0] = [point_a[0] + height, point_a[1] + height * 0.5]
|
||||||
|
endPosition[1] = [point_b[0] + height, point_b[1] - height * 0.5]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export function heatSquare(className, x, y, size, fill='none', data={}) {
|
export function heatSquare(className, x, y, size, fill='none', data={}) {
|
||||||
let args = {
|
let args = {
|
||||||
className: className,
|
className: className,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user