axis chart renderer

This commit is contained in:
pratu16x7 2017-12-04 05:00:05 +05:30
parent f2616bfa08
commit 02685dab7e
14 changed files with 492 additions and 522 deletions

View File

@ -247,62 +247,6 @@ function fillArray(array, count, element, start=false) {
const MIN_BAR_PERCENT_HEIGHT = 0.01;
function getXLineProps(totalHeight, mode) {
let startAt = totalHeight + 6, height, textStartAt, axisLineClass = '';
if(mode === 'span') { // long spanning lines
startAt = -7;
height = totalHeight + 15;
textStartAt = totalHeight + 25;
} else if(mode === 'tick'){ // short label lines
startAt = totalHeight;
height = 6;
textStartAt = 9;
axisLineClass = 'x-axis-label';
}
return [startAt, height, textStartAt, axisLineClass];
}
// export function getYLineProps(totalWidth, mode, specific=false) {
function getYLineProps(totalWidth, mode) {
// if(specific) {
// return[totalWidth, totalWidth + 5, 'specific-value', 0];
// }
let width, text_end_at = -9, axisLineClass = '', startAt = 0;
if(mode === 'span') { // long spanning lines
width = totalWidth + 6;
startAt = -6;
} else if(mode === 'tick'){ // short label lines
width = -6;
axisLineClass = 'y-axis-label';
}
return [width, text_end_at, axisLineClass, startAt];
}
// let char_width = 8;
// let allowed_space = avg_unit_width * 1.5;
// let allowed_letters = allowed_space / 8;
// return values.map((value, i) => {
// let space_taken = getStringWidth(value, char_width) + 2;
// if(space_taken > allowed_space) {
// if(is_series) {
// // Skip some axis lines if X axis is a series
// let skips = 1;
// while((space_taken/skips)*2 > allowed_space) {
// skips++;
// }
// if(i % skips !== 0) {
// return;
// }
// } else {
// value = value.slice(0, allowed_letters-3) + " ...";
// }
// }
function getBarHeightAndYAttr(yTop, zeroLine, totalHeight) {
let height, y;
if (yTop <= zeroLine) {
@ -338,11 +282,30 @@ function equilizeNoOfElements(array1, array2,
return [array1, array2];
}
const X_LABEL_CLASS = 'x-value-text';
const Y_LABEL_CLASS = 'y-value-text';
// let char_width = 8;
// let allowed_space = avgUnitWidth * 1.5;
// let allowed_letters = allowed_space / 8;
// const X_AXIS_LINE_CLASS = 'x-value-text';
// const Y_AXIS_LINE_CLASS = 'y-value-text';
// return values.map((value, i) => {
// let space_taken = getStringWidth(value, char_width) + 2;
// if(space_taken > allowed_space) {
// if(is_series) {
// // Skip some axis lines if X axis is a series
// let skips = 1;
// while((space_taken/skips)*2 > allowed_space) {
// skips++;
// }
// if(i % skips !== 0) {
// return;
// }
// } else {
// value = value.slice(0, allowed_letters-3) + " ...";
// }
// }
const AXIS_TICK_LENGTH = 6;
const LABEL_MARGIN = 4;
const FONT_SIZE = 10;
function $$1(expr, con) {
return typeof expr === "string"? (con || document).querySelector(expr) : expr || null;
@ -472,125 +435,136 @@ function makeText(className, x, y, content) {
className: className,
x: x,
y: y,
dy: '.32em',
dy: (FONT_SIZE / 2) + 'px',
'font-size': FONT_SIZE + 'px',
innerHTML: content
});
}
var AxisChartRenderer = (function() {
var AxisChartRenderer = function(totalHeight, totalWidth, zeroLine, avgUnitWidth, xAxisMode, yAxisMode) {
this.totalHeight = totalHeight;
this.totalWidth = totalWidth;
this.zeroLine = zeroLine;
this.avgUnitWidth = avgUnitWidth;
this.xAxisMode = xAxisMode;
this.yAxisMode = yAxisMode;
};
function makeVertXLine(x, label, totalHeight, mode) {
let height = mode === 'span' ? -1 * AXIS_TICK_LENGTH : totalHeight;
AxisChartRenderer.prototype = {
bar: function (x, yTop, args, color, index, datasetIndex, noOfDatasets) {
let totalWidth = this.avgUnitWidth - args.spaceWidth;
let startX = x - totalWidth/2;
let l = createSVG('line', {
x1: 0,
x2: 0,
y1: totalHeight + AXIS_TICK_LENGTH,
y2: height
});
let width = totalWidth / noOfDatasets;
let currentX = startX + width * datasetIndex;
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 [height, y] = getBarHeightAndYAttr(yTop, this.zeroLine, this.totalHeight);
let line = createSVG('g', {
transform: `translate(${ x }, 0)`
});
return createSVG('rect', {
className: `bar mini`,
style: `fill: ${color}`,
'data-point-index': index,
x: currentX,
y: y,
width: width,
height: height
});
},
line.appendChild(l);
line.appendChild(text);
dot: function(x, y, args, color, index) {
return createSVG('circle', {
style: `fill: ${color}`,
'data-point-index': index,
cx: x,
cy: y,
r: args.radius
});
},
return line;
}
xLine: function(x, label, mode=this.xAxisMode) {
// Draw X axis line in span/tick mode with optional label
let [startAt, height, textStartAt, axisLineClass] = getXLineProps(this.totalHeight, mode);
let l = createSVG('line', {
x1: 0,
x2: 0,
y1: startAt,
y2: height
});
function makeHoriYLine(y, label, totalWidth, mode) {
let lineType = '';
let width = mode === 'span' ? totalWidth + AXIS_TICK_LENGTH : AXIS_TICK_LENGTH;
let text = createSVG('text', {
className: X_LABEL_CLASS,
x: 0,
y: textStartAt,
dy: '.71em',
innerHTML: label
});
let l = createSVG('line', {
className: lineType === "dashed" ? "dashed": "",
x1: -1 * AXIS_TICK_LENGTH,
x2: width,
y1: 0,
y2: 0
});
let line = createSVG('g', {
className: `tick ${axisLineClass}`,
transform: `translate(${ x }, 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+""
});
line.appendChild(l);
line.appendChild(text);
let line = createSVG('g', {
transform: `translate(0, ${y})`,
'stroke-opacity': 1
});
return line;
},
if(text === 0 || text === '0') {
line.style.stroke = "rgba(27, 31, 35, 0.6)";
}
yLine: function(y, label, mode=this.yAxisMode) {
// TODO: stroke type
let lineType = '';
line.appendChild(l);
line.appendChild(text);
let [width, textEndAt, axisLineClass, startAt] = getYLineProps(this.totalWidth, mode);
let l = createSVG('line', {
className: lineType === "dashed" ? "dashed": "",
x1: startAt,
x2: width,
y1: 0,
y2: 0
});
return line;
}
let text = createSVG('text', {
className: Y_LABEL_CLASS,
x: textEndAt,
y: 0,
dy: '.32em',
innerHTML: label+""
});
class AxisChartRenderer {
constructor(state) {
this.updateState(state);
}
let line = createSVG('g', {
className: `tick ${axisLineClass}`,
transform: `translate(0, ${y})`,
'stroke-opacity': 1
});
updateState(state) {
this.totalHeight = state.totalHeight;
this.totalWidth = state.totalWidth;
this.zeroLine = state.zeroLine;
this.avgUnitWidth = state.avgUnitWidth;
this.xAxisMode = state.xAxisMode;
this.yAxisMode = state.yAxisMode;
}
// if(darker) {
// line.style.stroke = "rgba(27, 31, 35, 0.6)";
// }
bar(x, yTop, args, color, index, datasetIndex, noOfDatasets) {
let totalWidth = this.avgUnitWidth - args.spaceWidth;
let startX = x - totalWidth/2;
line.appendChild(l);
line.appendChild(text);
let width = totalWidth / noOfDatasets;
let currentX = startX + width * datasetIndex;
return line;
},
let [height, y] = getBarHeightAndYAttr(yTop, this.zeroLine, this.totalHeight);
xRegion: function(x1, x2, label) { },
return createSVG('rect', {
className: `bar mini`,
style: `fill: ${color}`,
'data-point-index': index,
x: currentX,
y: y,
width: width,
height: height
});
}
yRegion: function(y1, y2, label) { }
};
dot(x, y, args, color, index) {
return createSVG('circle', {
style: `fill: ${color}`,
'data-point-index': index,
cx: x,
cy: y,
r: args.radius
});
}
return AxisChartRenderer;
})();
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() {}
}
const PRESET_COLOR_MAP = {
'light-blue': '#7cd6fd',
@ -725,10 +699,12 @@ class BaseChart {
this.setColors();
this.setMargins();
// constants
this.config = {
showTooltip: 1,
showLegend: 1,
isNavigable: 0
isNavigable: 0,
animate: 1
};
}
@ -770,17 +746,21 @@ class BaseChart {
parseData() {
let data = this.rawChartArgs.data;
// Check and all
// If all good
this.data = data;
let valid = this.checkData(data);
if(!valid) return false;
if(!this.config.animate) {
this.data = data;
} else {
[this.data, this.firstUpdateData] =
this.getFirstUpdateData(data);
}
return true;
}
checkData() {}
getFirstUpdateData(data) {}
setup() {
if(this.validate()) {
this._setup();
@ -791,56 +771,19 @@ class BaseChart {
this.bindWindowEvents();
this.setupConstants();
// this.setupComponents();
this.makeContainer();
this.makeTooltip(); // without binding
this.draw(true);
}
draw(init=false) {
// (draw everything, layers, groups, units)
this.calc();
this.setupRenderer(); // this chart's rendered with the config
this.setupComponents();
this.makeChartArea();
this.makeLayers();
this.renderComponents(); // with zero values
this.renderLegend();
this.setupNavigation(init);
if(init) this.update(this.data);
}
bindWindowEvents() {
window.addEventListener('resize', () => this.draw());
window.addEventListener('orientationchange', () => this.draw());
}
calcWidth() {
let outerAnnotationsWidth = 0;
// let charWidth = 8;
// this.specificValues.map(val => {
// let strWidth = getStringWidth((val.title + ""), charWidth);
// if(strWidth > outerAnnotationsWidth) {
// outerAnnotationsWidth = strWidth - 40;
// }
// });
this.baseWidth = getElementContentWidth(this.parent) - outerAnnotationsWidth;
this.width = this.baseWidth - this.translateX * 2;
window.addEventListener('resize orientationchange', () => this.draw());
}
setupConstants() {}
calc() {
this.calcWidth();
this.reCalc();
}
setupRenderer() {}
setupComponents() {
// Components config
this.components = [];
@ -863,6 +806,58 @@ class BaseChart {
this.statsWrapper = this.container.querySelector('.graph-stats-container');
}
makeTooltip() {
this.tip = new SvgTip({
parent: this.chartWrapper,
colors: this.colors
});
this.bindTooltip();
}
draw(init=false) {
// difference from update(): draw the whole object due to groudbreaking event (init, resize, etc.)
// (draw everything, layers, groups, units)
this.calc();
this.refreshRenderer(); // this chart's rendered with the config
this.setupComponents();
this.makeChartArea();
this.makeLayers();
this.renderComponents(); // with zero values
this.renderLegend();
this.setupNavigation(init);
if(this.config.animate) this.update(this.firstUpdateData);
}
update() {
// difference from draw(): yes you do rerender everything here as well,
// but not things like the chart itself, mosty only at component level
this.reCalc();
this.reRender();
}
refreshRenderer() {}
calcWidth() {
let outerAnnotationsWidth = 0;
// let charWidth = 8;
// this.specificValues.map(val => {
// let strWidth = getStringWidth((val.title + ""), charWidth);
// if(strWidth > outerAnnotationsWidth) {
// outerAnnotationsWidth = strWidth - 40;
// }
// });
this.baseWidth = getElementContentWidth(this.parent) - outerAnnotationsWidth;
this.width = this.baseWidth - this.translateX * 2;
}
calc() {
this.calcWidth();
this.reCalc();
}
makeChartArea() {
this.svg = makeSVGContainer(
this.chartWrapper,
@ -896,11 +891,6 @@ class BaseChart {
});
}
update() {
this.reCalc();
this.reRender();
}
reCalc() {
// Will update values(state)
// Will recalc specific parts depending on the update
@ -931,13 +921,6 @@ class BaseChart {
calcInitStage() {}
makeTooltip() {
this.tip = new SvgTip({
parent: this.chartWrapper,
colors: this.colors
});
this.bindTooltip();
}
renderLegend() {}
@ -1391,7 +1374,7 @@ class AxisChart extends BaseChart {
this.is_series = args.is_series;
this.format_tooltip_y = args.format_tooltip_y;
this.format_tooltip_x = args.format_tooltip_x;
this.zero_line = this.height;
this.zeroLine = this.height;
}
parseData() {
@ -1457,22 +1440,27 @@ class AxisChart extends BaseChart {
}
// this should be inherent in BaseChart
getRenderer() {
// These args are basically the current state/config of the chart,
refreshRenderer() {
// These args are basically the current state of the chart,
// with constant and alive params mixed
return new AxisChartRenderer(this.height, this.width,
this.zero_line, this.avg_unit_width, this.xAxisMode, this.yAxisMode);
this.renderer = new AxisChartRenderer({
totalHeight: this.height,
totalWidth: this.width,
zeroLine: this.zeroLine,
avgUnitWidth: this.avgUnitWidth,
xAxisMode: this.xAxisMode,
yAxisMode: this.yAxisMode
});
}
setupComponents() {
// Must have access to all current data things
let self = this;
let renderer = this.getRenderer();
this.yAxis = {
layerClass: 'y axis',
layer: undefined,
make: self.makeYLines,
makeArgs: [renderer, self.yAxisPositions, self.yAxisLabels],
make: self.makeYLines.bind(self),
makeArgs: [self.yAxisPositions, self.yAxisLabels],
store: [],
// animate? or update? will come to while implementing
animate: self.animateYLines,
@ -1481,10 +1469,9 @@ class AxisChart extends BaseChart {
this.xAxis = {
layerClass: 'x axis',
layer: undefined,
make: self.makeXLines,
// TODO: better context of renderer
make: self.makeXLines.bind(self),
// TODO: will implement series skip with avgUnitWidth and isSeries later
makeArgs: [renderer, self.xPositions, self.xAxisLabels],
makeArgs: [self.xPositions, self.xAxisLabels],
store: [],
animate: self.animateXLines
};
@ -1535,12 +1522,12 @@ class AxisChart extends BaseChart {
}
setup_x() {
this.set_avg_unit_width_and_x_offset();
this.set_avgUnitWidth_and_x_offset();
if(this.xPositions) {
this.x_old_axis_positions = this.xPositions.slice();
}
this.xPositions = this.xAxisLabels.map((d, i) =>
floatTwo(this.x_offset + i * this.avg_unit_width));
floatTwo(this.x_offset + i * this.avgUnitWidth));
if(!this.x_old_axis_positions) {
this.x_old_axis_positions = this.xPositions.slice();
@ -1592,28 +1579,27 @@ class AxisChart extends BaseChart {
zero_index = (-1) * max / interval + (y_pts.length - 1);
}
if(this.zero_line) this.old_zero_line = this.zero_line;
this.zero_line = this.height - (zero_index * interval_height);
if(!this.old_zero_line) this.old_zero_line = this.zero_line;
if(this.zeroLine) this.old_zeroLine = this.zeroLine;
this.zeroLine = this.height - (zero_index * interval_height);
if(!this.old_zeroLine) this.old_zeroLine = this.zeroLine;
// Make positions arrays for y elements
if(this.yAxisPositions) this.oldYAxisPositions = this.yAxisPositions;
this.yAxisPositions = this.yAxisLabels.map(d => this.zero_line - d * this.multiplier);
this.yAxisPositions = this.yAxisLabels.map(d => this.zeroLine - d * this.multiplier);
if(!this.oldYAxisPositions) this.oldYAxisPositions = this.yAxisPositions;
// if(this.yAnnotationPositions) this.oldYAnnotationPositions = this.yAnnotationPositions;
// this.yAnnotationPositions = this.specific_values.map(d => this.zero_line - d.value * this.multiplier);
// this.yAnnotationPositions = this.specific_values.map(d => this.zeroLine - d.value * this.multiplier);
// if(!this.oldYAnnotationPositions) this.oldYAnnotationPositions = this.yAnnotationPositions;
}
makeXLines(renderer, positions, values) {
// TODO: draw as per condition
return positions.map((position, i) => renderer.xLine(position, values[i]));
makeXLines(positions, values) {
// TODO: draw as per condition (with/without label etc.)
return positions.map((position, i) => this.renderer.xLine(position, values[i]));
}
makeYLines(renderer, positions, values) {
return positions.map((position, i) => renderer.yLine(position, values[i]));
makeYLines(positions, values) {
return positions.map((position, i) => this.renderer.yLine(position, values[i]));
}
draw_graph(init=false) {
@ -1642,7 +1628,7 @@ class AxisChart extends BaseChart {
let data = [];
this.y.map((d, i) => {
// Anim: Don't draw initial values, store them and update later
d.yUnitPositions = new Array(d.values.length).fill(this.zero_line); // no value
d.yUnitPositions = new Array(d.values.length).fill(this.zeroLine); // no value
data.push({values: d.values});
d.svg_units = [];
@ -1686,7 +1672,7 @@ class AxisChart extends BaseChart {
units_group.textContent = '';
units_array.length = 0;
let unit_AxisChartRenderer = new AxisChartRenderer(this.height, this.zero_line, this.avg_unit_width);
let unit_AxisChartRenderer = new AxisChartRenderer(this.height, this.zeroLine, this.avgUnitWidth);
y_values.map((y, i) => {
let data_unit = unit_AxisChartRenderer[unit.type](
@ -1734,8 +1720,8 @@ class AxisChart extends BaseChart {
for(var i=this.xPositions.length - 1; i >= 0 ; i--) {
let x_val = this.xPositions[i];
// let delta = i === 0 ? this.avg_unit_width : x_val - this.xPositions[i-1];
if(relX > x_val - this.avg_unit_width/2) {
// let delta = i === 0 ? this.avgUnitWidth : x_val - this.xPositions[i-1];
if(relX > x_val - this.avgUnitWidth/2) {
let x = x_val + this.translateX;
let y = this.y_min_tops[i] + this.translateY;
@ -1778,7 +1764,7 @@ class AxisChart extends BaseChart {
this.calcYDependencies();
// Got the values? Now begin drawing
this.animator = new Animator(this.height, this.width, this.zero_line, this.avg_unit_width);
this.animator = new Animator(this.height, this.width, this.zeroLine, this.avgUnitWidth);
this.animate_graphs();
@ -1927,9 +1913,9 @@ class AxisChart extends BaseChart {
fire(this.parent, "data-select", this.getDataPoint());
}
set_avg_unit_width_and_x_offset() {
set_avgUnitWidth_and_x_offset() {
// Set the ... you get it
this.avg_unit_width = this.width/(this.xAxisLabels.length - 1);
this.avgUnitWidth = this.width/(this.xAxisLabels.length - 1);
this.x_offset = 0;
}
@ -1948,7 +1934,7 @@ class AxisChart extends BaseChart {
calcYDependencies() {
this.y_min_tops = new Array(this.xAxisLabels.length).fill(9999);
this.y.map(d => {
d.yUnitPositions = d.values.map( val => floatTwo(this.zero_line - val * this.multiplier));
d.yUnitPositions = d.values.map( val => floatTwo(this.zeroLine - val * this.multiplier));
d.yUnitPositions.map( (yUnitPosition, i) => {
if(yUnitPosition < this.y_min_tops[i]) {
this.y_min_tops[i] = yUnitPosition;
@ -1972,11 +1958,11 @@ class BarChart extends AxisChart {
setup_values() {
super.setup_values();
this.x_offset = this.avg_unit_width;
this.x_offset = this.avgUnitWidth;
this.unit_args = {
type: 'bar',
args: {
spaceWidth: this.avg_unit_width/2,
spaceWidth: this.avgUnitWidth/2,
}
};
}
@ -2034,9 +2020,9 @@ class BarChart extends AxisChart {
this.updateCurrentDataPoint(this.currentIndex + 1);
}
set_avg_unit_width_and_x_offset() {
this.avg_unit_width = this.width/(this.xAxisLabels.length + 1);
this.x_offset = this.avg_unit_width;
set_avgUnitWidth_and_x_offset() {
this.avgUnitWidth = this.width/(this.xAxisLabels.length + 1);
this.x_offset = this.avgUnitWidth;
}
}
@ -2118,7 +2104,7 @@ class LineChart extends AxisChart {
fill_region_for_dataset(d, color, points_str) {
let gradient_id = makeGradient(this.svg_defs, color, true);
let pathStr = "M" + `0,${this.zero_line}L` + points_str + `L${this.width},${this.zero_line}`;
let pathStr = "M" + `0,${this.zeroLine}L` + points_str + `L${this.width},${this.zeroLine}`;
d.regionPath = makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id})`);
this.paths_groups[d.index].appendChild(d.regionPath);

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
.chart-container{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.chart-container .graph-focus-margin{margin:0 5%}.chart-container>.title{margin-top:25px;margin-left:25px;text-align:left;font-weight:400;font-size:12px;color:#6c7680}.chart-container .graphics{margin-top:10px;padding-top:10px;padding-bottom:10px;position:relative}.chart-container .graph-stats-group{-ms-flex-pack:distribute;-webkit-box-flex:1;-ms-flex:1;flex:1}.chart-container .graph-stats-container,.chart-container .graph-stats-group{display:-webkit-box;display:-ms-flexbox;display:flex;justify-content:space-around}.chart-container .graph-stats-container{-ms-flex-pack:distribute;padding-top:10px}.chart-container .graph-stats-container .stats{padding-bottom:15px}.chart-container .graph-stats-container .stats-title{color:#8d99a6}.chart-container .graph-stats-container .stats-value{font-size:20px;font-weight:300}.chart-container .graph-stats-container .stats-description{font-size:12px;color:#8d99a6}.chart-container .graph-stats-container .graph-data .stats-value{color:#98d85b}.chart-container .axis,.chart-container .chart-label{font-size:11px;fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .percentage-graph .progress{margin-bottom:0}.chart-container .data-points circle{stroke:#fff;stroke-width:2}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .tick.x-axis-label{display:block}.chart-container .tick .specific-value{text-anchor:start}.chart-container .tick .y-value-text{text-anchor:end}.chart-container .tick .x-value-text{text-anchor:middle}.chart-container .progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.chart-container .progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#36414c;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;transition:width .6s ease}.chart-container .graph-svg-tip{position:absolute;z-index:1;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.chart-container .graph-svg-tip ol,.chart-container .graph-svg-tip ul{padding-left:0;display:-webkit-box;display:-ms-flexbox;display:flex}.chart-container .graph-svg-tip ul.data-point-list li{min-width:90px;-webkit-box-flex:1;-ms-flex:1;flex:1;font-weight:600}.chart-container .graph-svg-tip strong{color:#dfe2e5;font-weight:600}.chart-container .graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:" ";border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.chart-container .graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.chart-container .graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.chart-container .graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.chart-container .graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}.chart-container .indicator,.chart-container .indicator-right{background:none;font-size:12px;vertical-align:middle;font-weight:700;color:#6c7680}.chart-container .indicator i{content:"";display:inline-block;height:8px;width:8px;border-radius:8px}.chart-container .indicator:before,.chart-container .indicator i{margin:0 4px 0 0}.chart-container .indicator-right:after{margin:0 0 0 4px}
.chart-container{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.chart-container .graph-focus-margin{margin:0 5%}.chart-container>.title{margin-top:25px;margin-left:25px;text-align:left;font-weight:400;font-size:12px;color:#6c7680}.chart-container .graphics{margin-top:10px;padding-top:10px;padding-bottom:10px;position:relative}.chart-container .graph-stats-group{-ms-flex-pack:distribute;-webkit-box-flex:1;-ms-flex:1;flex:1}.chart-container .graph-stats-container,.chart-container .graph-stats-group{display:-webkit-box;display:-ms-flexbox;display:flex;justify-content:space-around}.chart-container .graph-stats-container{-ms-flex-pack:distribute;padding-top:10px}.chart-container .graph-stats-container .stats{padding-bottom:15px}.chart-container .graph-stats-container .stats-title{color:#8d99a6}.chart-container .graph-stats-container .stats-value{font-size:20px;font-weight:300}.chart-container .graph-stats-container .stats-description{font-size:12px;color:#8d99a6}.chart-container .graph-stats-container .graph-data .stats-value{color:#98d85b}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .percentage-graph .progress{margin-bottom:0}.chart-container .data-points circle{stroke:#fff;stroke-width:2}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.chart-container .progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#36414c;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;transition:width .6s ease}.chart-container .graph-svg-tip{position:absolute;z-index:1;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.chart-container .graph-svg-tip ol,.chart-container .graph-svg-tip ul{padding-left:0;display:-webkit-box;display:-ms-flexbox;display:flex}.chart-container .graph-svg-tip ul.data-point-list li{min-width:90px;-webkit-box-flex:1;-ms-flex:1;flex:1;font-weight:600}.chart-container .graph-svg-tip strong{color:#dfe2e5;font-weight:600}.chart-container .graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:" ";border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.chart-container .graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.chart-container .graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.chart-container .graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.chart-container .graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}.chart-container .indicator,.chart-container .indicator-right{background:none;font-size:12px;vertical-align:middle;font-weight:700;color:#6c7680}.chart-container .indicator i{content:"";display:inline-block;height:8px;width:8px;border-radius:8px}.chart-container .indicator:before,.chart-container .indicator i{margin:0 4px 0 0}.chart-container .indicator-right:after{margin:0 0 0 4px}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -13,7 +13,7 @@ export default class AxisChart extends BaseChart {
this.is_series = args.is_series;
this.format_tooltip_y = args.format_tooltip_y;
this.format_tooltip_x = args.format_tooltip_x;
this.zero_line = this.height;
this.zeroLine = this.height;
}
parseData() {
@ -79,22 +79,27 @@ export default class AxisChart extends BaseChart {
}
// this should be inherent in BaseChart
getRenderer() {
// These args are basically the current state/config of the chart,
refreshRenderer() {
// These args are basically the current state of the chart,
// with constant and alive params mixed
return new AxisChartRenderer(this.height, this.width,
this.zero_line, this.avg_unit_width, this.xAxisMode, this.yAxisMode);
this.renderer = new AxisChartRenderer({
totalHeight: this.height,
totalWidth: this.width,
zeroLine: this.zeroLine,
avgUnitWidth: this.avgUnitWidth,
xAxisMode: this.xAxisMode,
yAxisMode: this.yAxisMode
});
}
setupComponents() {
// Must have access to all current data things
let self = this;
let renderer = this.getRenderer();
this.yAxis = {
layerClass: 'y axis',
layer: undefined,
make: self.makeYLines,
makeArgs: [renderer, self.yAxisPositions, self.yAxisLabels],
make: self.makeYLines.bind(self),
makeArgs: [self.yAxisPositions, self.yAxisLabels],
store: [],
// animate? or update? will come to while implementing
animate: self.animateYLines,
@ -103,10 +108,9 @@ export default class AxisChart extends BaseChart {
this.xAxis = {
layerClass: 'x axis',
layer: undefined,
make: self.makeXLines,
// TODO: better context of renderer
make: self.makeXLines.bind(self),
// TODO: will implement series skip with avgUnitWidth and isSeries later
makeArgs: [renderer, self.xPositions, self.xAxisLabels],
makeArgs: [self.xPositions, self.xAxisLabels],
store: [],
animate: self.animateXLines
};
@ -157,12 +161,12 @@ export default class AxisChart extends BaseChart {
}
setup_x() {
this.set_avg_unit_width_and_x_offset();
this.set_avgUnitWidth_and_x_offset();
if(this.xPositions) {
this.x_old_axis_positions = this.xPositions.slice();
}
this.xPositions = this.xAxisLabels.map((d, i) =>
floatTwo(this.x_offset + i * this.avg_unit_width));
floatTwo(this.x_offset + i * this.avgUnitWidth));
if(!this.x_old_axis_positions) {
this.x_old_axis_positions = this.xPositions.slice();
@ -214,28 +218,27 @@ export default class AxisChart extends BaseChart {
zero_index = (-1) * max / interval + (y_pts.length - 1);
}
if(this.zero_line) this.old_zero_line = this.zero_line;
this.zero_line = this.height - (zero_index * interval_height);
if(!this.old_zero_line) this.old_zero_line = this.zero_line;
if(this.zeroLine) this.old_zeroLine = this.zeroLine;
this.zeroLine = this.height - (zero_index * interval_height);
if(!this.old_zeroLine) this.old_zeroLine = this.zeroLine;
// Make positions arrays for y elements
if(this.yAxisPositions) this.oldYAxisPositions = this.yAxisPositions;
this.yAxisPositions = this.yAxisLabels.map(d => this.zero_line - d * this.multiplier);
this.yAxisPositions = this.yAxisLabels.map(d => this.zeroLine - d * this.multiplier);
if(!this.oldYAxisPositions) this.oldYAxisPositions = this.yAxisPositions;
// if(this.yAnnotationPositions) this.oldYAnnotationPositions = this.yAnnotationPositions;
// this.yAnnotationPositions = this.specific_values.map(d => this.zero_line - d.value * this.multiplier);
// this.yAnnotationPositions = this.specific_values.map(d => this.zeroLine - d.value * this.multiplier);
// if(!this.oldYAnnotationPositions) this.oldYAnnotationPositions = this.yAnnotationPositions;
}
makeXLines(renderer, positions, values) {
// TODO: draw as per condition
return positions.map((position, i) => renderer.xLine(position, values[i]));
makeXLines(positions, values) {
// TODO: draw as per condition (with/without label etc.)
return positions.map((position, i) => this.renderer.xLine(position, values[i]));
}
makeYLines(renderer, positions, values) {
return positions.map((position, i) => renderer.yLine(position, values[i]));
makeYLines(positions, values) {
return positions.map((position, i) => this.renderer.yLine(position, values[i]));
}
draw_graph(init=false) {
@ -264,7 +267,7 @@ export default class AxisChart extends BaseChart {
let data = [];
this.y.map((d, i) => {
// Anim: Don't draw initial values, store them and update later
d.yUnitPositions = new Array(d.values.length).fill(this.zero_line); // no value
d.yUnitPositions = new Array(d.values.length).fill(this.zeroLine); // no value
data.push({values: d.values});
d.svg_units = [];
@ -308,7 +311,7 @@ export default class AxisChart extends BaseChart {
units_group.textContent = '';
units_array.length = 0;
let unit_AxisChartRenderer = new AxisChartRenderer(this.height, this.zero_line, this.avg_unit_width);
let unit_AxisChartRenderer = new AxisChartRenderer(this.height, this.zeroLine, this.avgUnitWidth);
y_values.map((y, i) => {
let data_unit = unit_AxisChartRenderer[unit.type](
@ -356,8 +359,8 @@ export default class AxisChart extends BaseChart {
for(var i=this.xPositions.length - 1; i >= 0 ; i--) {
let x_val = this.xPositions[i];
// let delta = i === 0 ? this.avg_unit_width : x_val - this.xPositions[i-1];
if(relX > x_val - this.avg_unit_width/2) {
// let delta = i === 0 ? this.avgUnitWidth : x_val - this.xPositions[i-1];
if(relX > x_val - this.avgUnitWidth/2) {
let x = x_val + this.translateX;
let y = this.y_min_tops[i] + this.translateY;
@ -400,7 +403,7 @@ export default class AxisChart extends BaseChart {
this.calcYDependencies();
// Got the values? Now begin drawing
this.animator = new Animator(this.height, this.width, this.zero_line, this.avg_unit_width);
this.animator = new Animator(this.height, this.width, this.zeroLine, this.avgUnitWidth);
this.animate_graphs();
@ -549,9 +552,9 @@ export default class AxisChart extends BaseChart {
fire(this.parent, "data-select", this.getDataPoint());
}
set_avg_unit_width_and_x_offset() {
set_avgUnitWidth_and_x_offset() {
// Set the ... you get it
this.avg_unit_width = this.width/(this.xAxisLabels.length - 1);
this.avgUnitWidth = this.width/(this.xAxisLabels.length - 1);
this.x_offset = 0;
}
@ -570,7 +573,7 @@ export default class AxisChart extends BaseChart {
calcYDependencies() {
this.y_min_tops = new Array(this.xAxisLabels.length).fill(9999);
this.y.map(d => {
d.yUnitPositions = d.values.map( val => floatTwo(this.zero_line - val * this.multiplier));
d.yUnitPositions = d.values.map( val => floatTwo(this.zeroLine - val * this.multiplier));
d.yUnitPositions.map( (yUnitPosition, i) => {
if(yUnitPosition < this.y_min_tops[i]) {
this.y_min_tops[i] = yUnitPosition;

View File

@ -12,11 +12,11 @@ export default class BarChart extends AxisChart {
setup_values() {
super.setup_values();
this.x_offset = this.avg_unit_width;
this.x_offset = this.avgUnitWidth;
this.unit_args = {
type: 'bar',
args: {
spaceWidth: this.avg_unit_width/2,
spaceWidth: this.avgUnitWidth/2,
}
};
}
@ -74,8 +74,8 @@ export default class BarChart extends AxisChart {
this.updateCurrentDataPoint(this.currentIndex + 1);
}
set_avg_unit_width_and_x_offset() {
this.avg_unit_width = this.width/(this.xAxisLabels.length + 1);
this.x_offset = this.avg_unit_width;
set_avgUnitWidth_and_x_offset() {
this.avgUnitWidth = this.width/(this.xAxisLabels.length + 1);
this.x_offset = this.avgUnitWidth;
}
}

View File

@ -41,10 +41,12 @@ export default class BaseChart {
this.setColors();
this.setMargins();
// constants
this.config = {
showTooltip: 1,
showLegend: 1,
isNavigable: 0
isNavigable: 0,
animate: 1
};
}
@ -88,17 +90,21 @@ export default class BaseChart {
parseData() {
let data = this.rawChartArgs.data;
// Check and all
// If all good
this.data = data;
let valid = this.checkData(data);
if(!valid) return false;
if(!this.config.animate) {
this.data = data;
} else {
[this.data, this.firstUpdateData] =
this.getFirstUpdateData(data);
}
return true;
}
checkData() {}
getFirstUpdateData(data) {}
setup() {
if(this.validate()) {
this._setup();
@ -109,56 +115,19 @@ export default class BaseChart {
this.bindWindowEvents();
this.setupConstants();
// this.setupComponents();
this.makeContainer();
this.makeTooltip(); // without binding
this.draw(true);
}
draw(init=false) {
// (draw everything, layers, groups, units)
this.calc();
this.setupRenderer(); // this chart's rendered with the config
this.setupComponents();
this.makeChartArea();
this.makeLayers();
this.renderComponents(); // with zero values
this.renderLegend();
this.setupNavigation(init);
if(init) this.update(this.data);
}
bindWindowEvents() {
window.addEventListener('resize', () => this.draw());
window.addEventListener('orientationchange', () => this.draw());
}
calcWidth() {
let outerAnnotationsWidth = 0;
// let charWidth = 8;
// this.specificValues.map(val => {
// let strWidth = getStringWidth((val.title + ""), charWidth);
// if(strWidth > outerAnnotationsWidth) {
// outerAnnotationsWidth = strWidth - 40;
// }
// });
this.baseWidth = getElementContentWidth(this.parent) - outerAnnotationsWidth;
this.width = this.baseWidth - this.translateX * 2;
window.addEventListener('resize orientationchange', () => this.draw());
}
setupConstants() {}
calc() {
this.calcWidth();
this.reCalc();
}
setupRenderer() {}
setupComponents() {
// Components config
this.components = [];
@ -181,6 +150,58 @@ export default class BaseChart {
this.statsWrapper = this.container.querySelector('.graph-stats-container');
}
makeTooltip() {
this.tip = new SvgTip({
parent: this.chartWrapper,
colors: this.colors
});
this.bindTooltip();
}
draw(init=false) {
// difference from update(): draw the whole object due to groudbreaking event (init, resize, etc.)
// (draw everything, layers, groups, units)
this.calc();
this.refreshRenderer() // this chart's rendered with the config
this.setupComponents();
this.makeChartArea();
this.makeLayers();
this.renderComponents(); // with zero values
this.renderLegend();
this.setupNavigation(init);
if(this.config.animate) this.update(this.firstUpdateData);
}
update() {
// difference from draw(): yes you do rerender everything here as well,
// but not things like the chart itself, mosty only at component level
this.reCalc();
this.reRender();
}
refreshRenderer() {}
calcWidth() {
let outerAnnotationsWidth = 0;
// let charWidth = 8;
// this.specificValues.map(val => {
// let strWidth = getStringWidth((val.title + ""), charWidth);
// if(strWidth > outerAnnotationsWidth) {
// outerAnnotationsWidth = strWidth - 40;
// }
// });
this.baseWidth = getElementContentWidth(this.parent) - outerAnnotationsWidth;
this.width = this.baseWidth - this.translateX * 2;
}
calc() {
this.calcWidth();
this.reCalc();
}
makeChartArea() {
this.svg = makeSVGContainer(
this.chartWrapper,
@ -214,11 +235,6 @@ export default class BaseChart {
});
}
update() {
this.reCalc();
this.reRender();
}
reCalc() {
// Will update values(state)
// Will recalc specific parts depending on the update
@ -249,13 +265,6 @@ export default class BaseChart {
calcInitStage() {}
makeTooltip() {
this.tip = new SvgTip({
parent: this.chartWrapper,
colors: this.colors
});
this.bindTooltip();
}
renderLegend() {}

View File

@ -79,7 +79,7 @@ export default class LineChart extends AxisChart {
fill_region_for_dataset(d, color, points_str) {
let gradient_id = makeGradient(this.svg_defs, color, true);
let pathStr = "M" + `0,${this.zero_line}L` + points_str + `L${this.width},${this.zero_line}`;
let pathStr = "M" + `0,${this.zeroLine}L` + points_str + `L${this.width},${this.zeroLine}`;
d.regionPath = makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id})`);
this.paths_groups[d.index].appendChild(d.regionPath);

View File

@ -0,0 +1,2 @@
import { getBarHeightAndYAttr } from '../utils/draw-utils';

View File

@ -1,67 +1,7 @@
import { fillArray } from '../utils/helpers';
const AXIS_TICK_LENGTH = 6;
const LABEL_MARGIN = 4;
const MIN_BAR_PERCENT_HEIGHT = 0.01;
export function verticalLineProps(start, height, label='down') {
//
}
export function getXLineProps(totalHeight, mode) {
let startAt = totalHeight + 6, height, textStartAt, axisLineClass = '';
if(mode === 'span') { // long spanning lines
startAt = -7;
height = totalHeight + 15;
textStartAt = totalHeight + 25;
} else if(mode === 'tick'){ // short label lines
startAt = totalHeight;
height = 6;
textStartAt = 9;
axisLineClass = 'x-axis-label';
}
return [startAt, height, textStartAt, axisLineClass];
}
// export function getYLineProps(totalWidth, mode, specific=false) {
export function getYLineProps(totalWidth, mode) {
// if(specific) {
// return[totalWidth, totalWidth + 5, 'specific-value', 0];
// }
let width, text_end_at = -9, axisLineClass = '', startAt = 0;
if(mode === 'span') { // long spanning lines
width = totalWidth + 6;
startAt = -6;
} else if(mode === 'tick'){ // short label lines
width = -6;
axisLineClass = 'y-axis-label';
}
return [width, text_end_at, axisLineClass, startAt];
}
// let char_width = 8;
// let allowed_space = avg_unit_width * 1.5;
// let allowed_letters = allowed_space / 8;
// return values.map((value, i) => {
// let space_taken = getStringWidth(value, char_width) + 2;
// if(space_taken > allowed_space) {
// if(is_series) {
// // Skip some axis lines if X axis is a series
// let skips = 1;
// while((space_taken/skips)*2 > allowed_space) {
// skips++;
// }
// if(i % skips !== 0) {
// return;
// }
// } else {
// value = value.slice(0, allowed_letters-3) + " ...";
// }
// }
export function getBarHeightAndYAttr(yTop, zeroLine, totalHeight) {
let height, y;
if (yTop <= zeroLine) {
@ -96,3 +36,24 @@ export function equilizeNoOfElements(array1, array2,
}
return [array1, array2];
}
// let char_width = 8;
// let allowed_space = avgUnitWidth * 1.5;
// let allowed_letters = allowed_space / 8;
// return values.map((value, i) => {
// let space_taken = getStringWidth(value, char_width) + 2;
// if(space_taken > allowed_space) {
// if(is_series) {
// // Skip some axis lines if X axis is a series
// let skips = 1;
// while((space_taken/skips)*2 > allowed_space) {
// skips++;
// }
// if(i % skips !== 0) {
// return;
// }
// } else {
// value = value.slice(0, allowed_letters-3) + " ...";
// }
// }

View File

@ -1,10 +1,8 @@
import { getBarHeightAndYAttr, getXLineProps, getYLineProps } from './draw-utils';
import { getBarHeightAndYAttr } from './draw-utils';
const X_LABEL_CLASS = 'x-value-text';
const Y_LABEL_CLASS = 'y-value-text';
// const X_AXIS_LINE_CLASS = 'x-value-text';
// const Y_AXIS_LINE_CLASS = 'y-value-text';
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;
@ -134,122 +132,133 @@ export function makeText(className, x, y, content) {
className: className,
x: x,
y: y,
dy: '.32em',
dy: (FONT_SIZE / 2) + 'px',
'font-size': FONT_SIZE + 'px',
innerHTML: content
});
}
export var AxisChartRenderer = (function() {
var AxisChartRenderer = function(totalHeight, totalWidth, zeroLine, avgUnitWidth, xAxisMode, yAxisMode) {
this.totalHeight = totalHeight;
this.totalWidth = totalWidth;
this.zeroLine = zeroLine;
this.avgUnitWidth = avgUnitWidth;
this.xAxisMode = xAxisMode;
this.yAxisMode = yAxisMode;
};
export function makeVertXLine(x, label, totalHeight, mode) {
let height = mode === 'span' ? -1 * AXIS_TICK_LENGTH : totalHeight;
AxisChartRenderer.prototype = {
bar: function (x, yTop, args, color, index, datasetIndex, noOfDatasets) {
let totalWidth = this.avgUnitWidth - args.spaceWidth;
let startX = x - totalWidth/2;
let l = createSVG('line', {
x1: 0,
x2: 0,
y1: totalHeight + AXIS_TICK_LENGTH,
y2: height
});
let width = totalWidth / noOfDatasets;
let currentX = startX + width * datasetIndex;
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 [height, y] = getBarHeightAndYAttr(yTop, this.zeroLine, this.totalHeight);
let line = createSVG('g', {
transform: `translate(${ x }, 0)`
});
return createSVG('rect', {
className: `bar mini`,
style: `fill: ${color}`,
'data-point-index': index,
x: currentX,
y: y,
width: width,
height: height
});
},
line.appendChild(l);
line.appendChild(text);
dot: function(x, y, args, color, index) {
return createSVG('circle', {
style: `fill: ${color}`,
'data-point-index': index,
cx: x,
cy: y,
r: args.radius
});
},
return line;
}
xLine: function(x, label, mode=this.xAxisMode) {
// Draw X axis line in span/tick mode with optional label
let [startAt, height, textStartAt, axisLineClass] = getXLineProps(this.totalHeight, mode);
let l = createSVG('line', {
x1: 0,
x2: 0,
y1: startAt,
y2: height
});
export function makeHoriYLine(y, label, totalWidth, mode) {
let lineType = '';
let width = mode === 'span' ? totalWidth + AXIS_TICK_LENGTH : AXIS_TICK_LENGTH;
let text = createSVG('text', {
className: X_LABEL_CLASS,
x: 0,
y: textStartAt,
dy: '.71em',
innerHTML: label
});
let l = createSVG('line', {
className: lineType === "dashed" ? "dashed": "",
x1: -1 * AXIS_TICK_LENGTH,
x2: width,
y1: 0,
y2: 0
});
let line = createSVG('g', {
className: `tick ${axisLineClass}`,
transform: `translate(${ x }, 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+""
});
line.appendChild(l);
line.appendChild(text);
let line = createSVG('g', {
transform: `translate(0, ${y})`,
'stroke-opacity': 1
});
return line;
},
if(text === 0 || text === '0') {
line.style.stroke = "rgba(27, 31, 35, 0.6)";
}
yLine: function(y, label, mode=this.yAxisMode) {
// TODO: stroke type
let lineType = '';
line.appendChild(l);
line.appendChild(text);
let [width, textEndAt, axisLineClass, startAt] = getYLineProps(this.totalWidth, mode);
let l = createSVG('line', {
className: lineType === "dashed" ? "dashed": "",
x1: startAt,
x2: width,
y1: 0,
y2: 0
});
return line;
}
let text = createSVG('text', {
className: Y_LABEL_CLASS,
x: textEndAt,
y: 0,
dy: '.32em',
innerHTML: label+""
});
export class AxisChartRenderer {
constructor(state) {
this.updateState(state);
}
let line = createSVG('g', {
className: `tick ${axisLineClass}`,
transform: `translate(0, ${y})`,
'stroke-opacity': 1
});
updateState(state) {
this.totalHeight = state.totalHeight;
this.totalWidth = state.totalWidth;
this.zeroLine = state.zeroLine;
this.avgUnitWidth = state.avgUnitWidth;
this.xAxisMode = state.xAxisMode;
this.yAxisMode = state.yAxisMode;
}
// if(darker) {
// line.style.stroke = "rgba(27, 31, 35, 0.6)";
// }
bar(x, yTop, args, color, index, datasetIndex, noOfDatasets) {
let totalWidth = this.avgUnitWidth - args.spaceWidth;
let startX = x - totalWidth/2;
line.appendChild(l);
line.appendChild(text);
let width = totalWidth / noOfDatasets;
let currentX = startX + width * datasetIndex;
return line;
},
let [height, y] = getBarHeightAndYAttr(yTop, this.zeroLine, this.totalHeight);
xRegion: function(x1, x2, label) { },
return createSVG('rect', {
className: `bar mini`,
style: `fill: ${color}`,
'data-point-index': index,
x: currentX,
y: y,
width: width,
height: height
});
}
yRegion: function(y1, y2, label) { }
};
dot(x, y, args, color, index) {
return createSVG('circle', {
style: `fill: ${color}`,
'data-point-index': index,
cx: x,
cy: y,
r: args.radius
});
}
return AxisChartRenderer;
})();
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() {}
}

View File

@ -51,7 +51,6 @@
}
}
.axis, .chart-label {
font-size: 11px;
fill: #555b51;
line {
stroke: #dadada;
@ -78,17 +77,18 @@
line.dashed {
stroke-dasharray: 5,3;
}
.tick {
&.x-axis-label {
display: block;
}
.axis-line {
// &.x-axis-label {
// display: block;
// }
// TODO: hack dy attr to be settable via styles
.specific-value {
text-anchor: start;
}
.y-value-text {
.y-line {
text-anchor: end;
}
.x-value-text {
.x-line {
text-anchor: middle;
}
}