charts/src/js/utils/draw.js
2017-12-05 05:18:18 +05:30

270 lines
5.5 KiB
JavaScript

import { getBarHeightAndYAttr } from './draw-utils';
const AXIS_TICK_LENGTH = 6;
const LABEL_MARGIN = 4;
const FONT_SIZE = 10;
function $(expr, con) {
return typeof expr === "string"? (con || document).querySelector(expr) : expr || null;
}
function createSVG(tag, o) {
var element = document.createElementNS("http://www.w3.org/2000/svg", tag);
for (var i in o) {
var val = o[i];
if (i === "inside") {
$(val).appendChild(element);
}
else if (i === "around") {
var ref = $(val);
ref.parentNode.insertBefore(element, ref);
element.appendChild(ref);
} else if (i === "styles") {
if(typeof val === "object") {
Object.keys(val).map(prop => {
element.style[prop] = val[prop];
});
}
} else {
if(i === "className") { i = "class"; }
if(i === "innerHTML") {
element['textContent'] = val;
} else {
element.setAttribute(i, val);
}
}
}
return element;
}
function renderVerticalGradient(svgDefElem, gradientId) {
return createSVG('linearGradient', {
inside: svgDefElem,
id: gradientId,
x1: 0,
x2: 0,
y1: 0,
y2: 1
});
}
function setGradientStop(gradElem, offset, color, opacity) {
return createSVG('stop', {
'inside': gradElem,
'style': `stop-color: ${color}`,
'offset': offset,
'stop-opacity': opacity
});
}
export function makeSVGContainer(parent, className, width, height) {
return createSVG('svg', {
className: className,
inside: parent,
width: width,
height: height
});
}
export function makeSVGDefs(svgContainer) {
return createSVG('defs', {
inside: svgContainer,
});
}
export function makeSVGGroup(parent, className, transform='') {
return createSVG('g', {
className: className,
inside: parent,
transform: transform
});
}
export function makePath(pathStr, className='', stroke='none', fill='none') {
return createSVG('path', {
className: className,
d: pathStr,
styles: {
stroke: stroke,
fill: fill
}
});
}
export function makeGradient(svgDefElem, color, lighter = false) {
let gradientId ='path-fill-gradient' + '-' + color;
let gradientDef = renderVerticalGradient(svgDefElem, gradientId);
let opacities = [1, 0.6, 0.2];
if(lighter) {
opacities = [0.4, 0.2, 0];
}
setGradientStop(gradientDef, "0%", color, opacities[0]);
setGradientStop(gradientDef, "50%", color, opacities[1]);
setGradientStop(gradientDef, "100%", color, opacities[2]);
return gradientId;
}
export function makeHeatSquare(className, x, y, size, fill='none', data={}) {
let args = {
className: className,
x: x,
y: y,
width: size,
height: size,
fill: fill
};
Object.keys(data).map(key => {
args[key] = data[key];
});
return createSVG("rect", args);
}
export function makeText(className, x, y, content) {
return createSVG('text', {
className: className,
x: x,
y: y,
dy: (FONT_SIZE / 2) + 'px',
'font-size': FONT_SIZE + 'px',
innerHTML: content
});
}
export function makeVertXLine(x, label, totalHeight, mode) {
let height = mode === 'span' ? -1 * AXIS_TICK_LENGTH : totalHeight;
let l = createSVG('line', {
x1: 0,
x2: 0,
y1: totalHeight + AXIS_TICK_LENGTH,
y2: height
});
let text = createSVG('text', {
x: 0,
y: totalHeight + AXIS_TICK_LENGTH + LABEL_MARGIN,
dy: FONT_SIZE + 'px',
'font-size': FONT_SIZE + 'px',
'text-anchor': 'middle',
innerHTML: label
});
let line = createSVG('g', {
transform: `translate(${ x }, 0)`
});
line.appendChild(l);
line.appendChild(text);
return line;
}
export function makeHoriYLine(y, label, totalWidth, mode) {
let lineType = '';
let width = mode === 'span' ? totalWidth + AXIS_TICK_LENGTH : AXIS_TICK_LENGTH;
let l = createSVG('line', {
className: lineType === "dashed" ? "dashed": "",
x1: -1 * AXIS_TICK_LENGTH,
x2: width,
y1: 0,
y2: 0
});
let text = createSVG('text', {
x: -1 * (LABEL_MARGIN + AXIS_TICK_LENGTH),
y: 0,
dy: (FONT_SIZE / 2 - 2) + 'px',
'font-size': FONT_SIZE + 'px',
'text-anchor': 'end',
innerHTML: label+""
});
let line = createSVG('g', {
transform: `translate(0, ${y})`,
'stroke-opacity': 1
});
if(text === 0 || text === '0') {
line.style.stroke = "rgba(27, 31, 35, 0.6)";
}
line.appendChild(l);
line.appendChild(text);
return line;
}
export class AxisChartRenderer {
constructor(state) {
this.refreshState(state);
}
refreshState(state) {
this.totalHeight = state.totalHeight;
this.totalWidth = state.totalWidth;
this.zeroLine = state.zeroLine;
this.unitWidth = state.unitWidth;
this.xAxisMode = state.xAxisMode;
this.yAxisMode = state.yAxisMode;
}
bar(x, yTop, args, color, index, datasetIndex, noOfDatasets) {
let totalWidth = this.unitWidth - args.spaceWidth;
let startX = x - totalWidth/2;
// temp
// let width = totalWidth / noOfDatasets;
// let currentX = startX + width * datasetIndex;
let width = totalWidth;
let currentX = startX;
let [height, y] = getBarHeightAndYAttr(yTop, this.zeroLine, this.totalHeight);
return createSVG('rect', {
className: `bar mini`,
style: `fill: ${color}`,
'data-point-index': index,
x: currentX,
y: y,
width: width,
height: height
});
}
dot(x, y, args, color, index) {
return createSVG('circle', {
style: `fill: ${color}`,
'data-point-index': index,
cx: x,
cy: y,
r: args.radius
});
}
xLine(x, label, mode=this.xAxisMode) {
// Draw X axis line in span/tick mode with optional label
return makeVertXLine(x, label, this.totalHeight, mode);
}
yLine(y, label, mode=this.yAxisMode) {
return makeHoriYLine(y, label, this.totalWidth, mode);
}
xMarker() {}
yMarker() {}
xRegion() {}
yRegion() {}
}