|
|
@@ -136,7 +136,7 @@ const AXIS_DATASET_CHART_TYPES = ['line', 'bar']; |
|
|
|
const AXIS_LEGEND_BAR_SIZE = 100; |
|
|
|
|
|
|
|
const BAR_CHART_SPACE_RATIO = 0.5; |
|
|
|
const MIN_BAR_PERCENT_HEIGHT = 0.01; |
|
|
|
const MIN_BAR_PERCENT_HEIGHT = 0.00; |
|
|
|
|
|
|
|
const LINE_CHART_DOT_SIZE = 4; |
|
|
|
const DOT_OVERLAY_SIZE_INCR = 4; |
|
|
@@ -382,6 +382,35 @@ function equilizeNoOfElements(array1, array2, |
|
|
|
return [array1, array2]; |
|
|
|
} |
|
|
|
|
|
|
|
function truncateString(txt, len) { |
|
|
|
if (!txt) { |
|
|
|
return; |
|
|
|
} |
|
|
|
if (txt.length > len) { |
|
|
|
return txt.slice(0, len-3) + '...'; |
|
|
|
} else { |
|
|
|
return txt; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function shortenLargeNumber(label) { |
|
|
|
let number; |
|
|
|
if (typeof label === 'number') number = label; |
|
|
|
else if (typeof label === 'string') { |
|
|
|
number = Number(label); |
|
|
|
if (Number.isNaN(number)) return label; |
|
|
|
} |
|
|
|
|
|
|
|
// Using absolute since log wont work for negative numbers |
|
|
|
let p = Math.floor(Math.log10(Math.abs(number))); |
|
|
|
if (p <= 2) return number; // Return as is for a 3 digit number of less |
|
|
|
let l = Math.floor(p / 3); |
|
|
|
let shortened = (Math.pow(10, p - l * 3) * +(number / Math.pow(10, p)).toFixed(1)); |
|
|
|
|
|
|
|
// Correct for floating point error upto 2 decimal places |
|
|
|
return Math.round(shortened*100)/100 + ' ' + ['', 'K', 'M', 'B', 'T'][l]; |
|
|
|
} |
|
|
|
|
|
|
|
const PRESET_COLOR_MAP = { |
|
|
|
'light-blue': '#7cd6fd', |
|
|
|
'blue': '#5e64ff', |
|
|
@@ -430,6 +459,7 @@ const getColor = (color) => { |
|
|
|
|
|
|
|
const AXIS_TICK_LENGTH = 6; |
|
|
|
const LABEL_MARGIN = 4; |
|
|
|
const LABEL_MAX_CHARS = 15; |
|
|
|
const FONT_SIZE = 10; |
|
|
|
const BASE_LINE_COLOR = '#dadada'; |
|
|
|
const FONT_FILL = '#555b51'; |
|
|
@@ -538,12 +568,36 @@ function makeArcPathStr(startPosition, endPosition, center, radius, clockWise=1, |
|
|
|
${arcEndX} ${arcEndY} z`; |
|
|
|
} |
|
|
|
|
|
|
|
function makeArcStrokePathStr(startPosition, endPosition, center, radius, clockWise=1){ |
|
|
|
function makeCircleStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){ |
|
|
|
let [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y]; |
|
|
|
let [arcEndX, midArc, arcEndY] = [center.x + endPosition.x, center.y * 2, center.y + endPosition.y]; |
|
|
|
return `M${center.x} ${center.y} |
|
|
|
L${arcStartX} ${arcStartY} |
|
|
|
A ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0} |
|
|
|
${arcEndX} ${midArc} z |
|
|
|
L${arcStartX} ${midArc} |
|
|
|
A ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0} |
|
|
|
${arcEndX} ${arcEndY} z`; |
|
|
|
} |
|
|
|
|
|
|
|
function makeArcStrokePathStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){ |
|
|
|
let [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y]; |
|
|
|
let [arcEndX, arcEndY] = [center.x + endPosition.x, center.y + endPosition.y]; |
|
|
|
|
|
|
|
return `M${arcStartX} ${arcStartY} |
|
|
|
A ${radius} ${radius} 0 0 ${clockWise ? 1 : 0} |
|
|
|
A ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0} |
|
|
|
${arcEndX} ${arcEndY}`; |
|
|
|
} |
|
|
|
|
|
|
|
function makeStrokeCircleStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){ |
|
|
|
let [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y]; |
|
|
|
let [arcEndX, midArc, arcEndY] = [center.x + endPosition.x, radius * 2 + arcStartY, center.y + startPosition.y]; |
|
|
|
|
|
|
|
return `M${arcStartX} ${arcStartY} |
|
|
|
A ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0} |
|
|
|
${arcEndX} ${midArc} |
|
|
|
M${arcStartX} ${midArc} |
|
|
|
A ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0} |
|
|
|
${arcEndX} ${arcEndY}`; |
|
|
|
} |
|
|
|
|
|
|
@@ -601,7 +655,9 @@ function heatSquare(className, x, y, size, fill='none', data={}) { |
|
|
|
return createSVG("rect", args); |
|
|
|
} |
|
|
|
|
|
|
|
function legendBar(x, y, size, fill='none', label) { |
|
|
|
function legendBar(x, y, size, fill='none', label, truncate=false) { |
|
|
|
label = truncate ? truncateString(label, LABEL_MAX_CHARS) : label; |
|
|
|
|
|
|
|
let args = { |
|
|
|
className: 'legend-bar', |
|
|
|
x: 0, |
|
|
@@ -711,6 +767,8 @@ function makeVertLine(x, label, y1, y2, options={}) { |
|
|
|
function makeHoriLine(y, label, x1, x2, options={}) { |
|
|
|
if(!options.stroke) options.stroke = BASE_LINE_COLOR; |
|
|
|
if(!options.lineType) options.lineType = ''; |
|
|
|
if (options.shortenNumbers) label = shortenLargeNumber(label); |
|
|
|
|
|
|
|
let className = 'line-horizontal ' + options.className + |
|
|
|
(options.lineType === "dashed" ? "dashed": ""); |
|
|
|
|
|
|
@@ -772,7 +830,8 @@ function yLine(y, label, width, options={}) { |
|
|
|
return makeHoriLine(y, label, x1, x2, { |
|
|
|
stroke: options.stroke, |
|
|
|
className: options.className, |
|
|
|
lineType: options.lineType |
|
|
|
lineType: options.lineType, |
|
|
|
shortenNumbers: options.shortenNumbers |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
@@ -1379,7 +1438,8 @@ class BaseChart { |
|
|
|
showTooltip: 1, // calculate |
|
|
|
showLegend: 1, // calculate |
|
|
|
isNavigable: options.isNavigable || 0, |
|
|
|
animate: 1 |
|
|
|
animate: 1, |
|
|
|
truncateLegends: options.truncateLegends || 0 |
|
|
|
}; |
|
|
|
|
|
|
|
this.measures = JSON.parse(JSON.stringify(BASE_MEASURES)); |
|
|
@@ -1941,7 +2001,7 @@ let componentConfigs = { |
|
|
|
makeElements(data) { |
|
|
|
return data.positions.map((position, i) => |
|
|
|
yLine(position, data.labels[i], this.constants.width, |
|
|
|
{mode: this.constants.mode, pos: this.constants.pos}) |
|
|
|
{mode: this.constants.mode, pos: this.constants.pos, shortenNumbers: this.constants.shortenNumbers}) |
|
|
|
); |
|
|
|
}, |
|
|
|
|
|
|
@@ -2389,10 +2449,7 @@ class PieChart extends AggregationChart { |
|
|
|
s.sliceTotals.map((total, i) => { |
|
|
|
const startAngle = curAngle; |
|
|
|
const originDiffAngle = (total / s.grandTotal) * FULL_ANGLE; |
|
|
|
let largeArc = 0; |
|
|
|
if(originDiffAngle > 180){ |
|
|
|
largeArc = 1; |
|
|
|
} |
|
|
|
const largeArc = originDiffAngle > 180 ? 1: 0; |
|
|
|
const diffAngle = clockWise ? -originDiffAngle : originDiffAngle; |
|
|
|
const endAngle = curAngle = curAngle + diffAngle; |
|
|
|
const startPosition = getPositionByAngle(startAngle, radius); |
|
|
@@ -2408,7 +2465,11 @@ class PieChart extends AggregationChart { |
|
|
|
curStart = startPosition; |
|
|
|
curEnd = endPosition; |
|
|
|
} |
|
|
|
const curPath = makeArcPathStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc); |
|
|
|
const curPath = |
|
|
|
originDiffAngle === 360 |
|
|
|
? makeCircleStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc) |
|
|
|
: makeArcPathStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc); |
|
|
|
|
|
|
|
s.sliceStrings.push(curPath); |
|
|
|
s.slicesProperties.push({ |
|
|
|
startPosition, |
|
|
@@ -3161,6 +3222,7 @@ class AxisChart extends BaseChart { |
|
|
|
this.config.xAxisMode = options.axisOptions.xAxisMode || 'span'; |
|
|
|
this.config.yAxisMode = options.axisOptions.yAxisMode || 'span'; |
|
|
|
this.config.xIsSeries = options.axisOptions.xIsSeries || 0; |
|
|
|
this.config.shortenYAxisNumbers = options.axisOptions.shortenYAxisNumbers || 0; |
|
|
|
|
|
|
|
this.config.formatTooltipX = options.tooltipOptions.formatTooltipX; |
|
|
|
this.config.formatTooltipY = options.tooltipOptions.formatTooltipY; |
|
|
@@ -3315,6 +3377,7 @@ class AxisChart extends BaseChart { |
|
|
|
{ |
|
|
|
mode: this.config.yAxisMode, |
|
|
|
width: this.width, |
|
|
|
shortenNumbers: this.config.shortenYAxisNumbers |
|
|
|
// pos: 'right' |
|
|
|
}, |
|
|
|
function() { |
|
|
@@ -3552,7 +3615,8 @@ class AxisChart extends BaseChart { |
|
|
|
'0', |
|
|
|
barWidth, |
|
|
|
this.colors[i], |
|
|
|
d.name); |
|
|
|
d.name, |
|
|
|
this.config.truncateLegends); |
|
|
|
this.legendArea.appendChild(rect); |
|
|
|
}); |
|
|
|
} |
|
|
@@ -3746,6 +3810,7 @@ class DonutChart extends AggregationChart { |
|
|
|
s.sliceTotals.map((total, i) => { |
|
|
|
const startAngle = curAngle; |
|
|
|
const originDiffAngle = (total / s.grandTotal) * FULL_ANGLE; |
|
|
|
const largeArc = originDiffAngle > 180 ? 1: 0; |
|
|
|
const diffAngle = clockWise ? -originDiffAngle : originDiffAngle; |
|
|
|
const endAngle = curAngle = curAngle + diffAngle; |
|
|
|
const startPosition = getPositionByAngle(startAngle, radius); |
|
|
@@ -3761,7 +3826,10 @@ class DonutChart extends AggregationChart { |
|
|
|
curStart = startPosition; |
|
|
|
curEnd = endPosition; |
|
|
|
} |
|
|
|
const curPath = makeArcStrokePathStr(curStart, curEnd, this.center, this.radius, this.clockWise); |
|
|
|
const curPath = |
|
|
|
originDiffAngle === 360 |
|
|
|
? makeStrokeCircleStr(curStart, curEnd, this.center, this.radius, this.clockWise, largeArc) |
|
|
|
: makeArcStrokePathStr(curStart, curEnd, this.center, this.radius, this.clockWise, largeArc); |
|
|
|
|
|
|
|
s.sliceStrings.push(curPath); |
|
|
|
s.slicesProperties.push({ |
|
|
|