feat: new legends
* merge legendBar and legendDots * use BaseChart to render legends
This commit is contained in:
parent
d84614cb65
commit
7cfa35a418
@ -15,6 +15,7 @@ export default class AggregationChart extends BaseChart {
|
||||
this.config.formatTooltipY = (args.tooltipOptions || {}).formatTooltipY;
|
||||
this.config.maxSlices = args.maxSlices || 20;
|
||||
this.config.maxLegendPoints = args.maxLegendPoints || 20;
|
||||
this.config.legendRowHeight = 60;
|
||||
}
|
||||
|
||||
calc() {
|
||||
@ -31,17 +32,17 @@ export default class AggregationChart extends BaseChart {
|
||||
}).filter(d => { return d[0] >= 0; }); // keep only positive results
|
||||
|
||||
let totals = allTotals;
|
||||
if(allTotals.length > maxSlices) {
|
||||
if (allTotals.length > maxSlices) {
|
||||
// Prune and keep a grey area for rest as per maxSlices
|
||||
allTotals.sort((a, b) => { return b[0] - a[0]; });
|
||||
|
||||
totals = allTotals.slice(0, maxSlices-1);
|
||||
let remaining = allTotals.slice(maxSlices-1);
|
||||
totals = allTotals.slice(0, maxSlices - 1);
|
||||
let remaining = allTotals.slice(maxSlices - 1);
|
||||
|
||||
let sumOfRemaining = 0;
|
||||
remaining.map(d => {sumOfRemaining += d[0];});
|
||||
remaining.map(d => { sumOfRemaining += d[0]; });
|
||||
totals.push([sumOfRemaining, 'Rest']);
|
||||
this.colors[maxSlices-1] = 'grey';
|
||||
this.colors[maxSlices - 1] = 'grey';
|
||||
}
|
||||
|
||||
s.labels = [];
|
||||
@ -62,36 +63,22 @@ export default class AggregationChart extends BaseChart {
|
||||
let s = this.state;
|
||||
this.legendArea.textContent = '';
|
||||
this.legendTotals = s.sliceTotals.slice(0, this.config.maxLegendPoints);
|
||||
super.renderLegend(this.legendTotals);
|
||||
}
|
||||
|
||||
let count = 0;
|
||||
let y = 0;
|
||||
this.legendTotals.map((d, i) => {
|
||||
let barWidth = 120;
|
||||
let divisor = Math.floor(
|
||||
(this.width - getExtraWidth(this.measures))/barWidth
|
||||
);
|
||||
if (this.legendTotals.length < divisor) {
|
||||
barWidth = this.width/this.legendTotals.length;
|
||||
}
|
||||
if(count > divisor) {
|
||||
count = 0;
|
||||
y += 60;
|
||||
}
|
||||
let x = barWidth * count + 5;
|
||||
let label = this.config.truncateLegends ? truncateString(s.labels[i], barWidth/10) : s.labels[i];
|
||||
let formatted = this.config.formatTooltipY ? this.config.formatTooltipY(d) : d;
|
||||
let dot = legendDot(
|
||||
x,
|
||||
y,
|
||||
12,
|
||||
3,
|
||||
this.colors[i],
|
||||
`${label}: ${formatted}`,
|
||||
d,
|
||||
false
|
||||
);
|
||||
this.legendArea.appendChild(dot);
|
||||
count++;
|
||||
});
|
||||
makeLegend(data, index, x_pos, y_pos) {
|
||||
let formatted = this.config.formatTooltipY ? this.config.formatTooltipY(data) : data;
|
||||
|
||||
return legendDot(
|
||||
x_pos,
|
||||
y_pos,
|
||||
12, // size
|
||||
3, // dot radius
|
||||
this.colors[index], // fill
|
||||
this.state.labels[index], // label
|
||||
formatted, // value
|
||||
null, // base_font_size
|
||||
this.config.truncateLegends // truncate_legends
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
import BaseChart from './BaseChart';
|
||||
import { dataPrep, zeroDataPrep, getShortenedLabels } from '../utils/axis-chart-utils';
|
||||
import { AXIS_LEGEND_BAR_SIZE } from '../utils/constants';
|
||||
import { getComponent } from '../objects/ChartComponents';
|
||||
import { getOffset, fire } from '../utils/dom';
|
||||
import { calcChartIntervals, getIntervalSize, getValueRange, getZeroIndex, scale, getClosestInArray } from '../utils/intervals';
|
||||
import { floatTwo } from '../utils/helpers';
|
||||
import { makeOverlay, updateOverlay, legendBar } from '../utils/draw';
|
||||
import { getTopOffset, getLeftOffset, MIN_BAR_PERCENT_HEIGHT, BAR_CHART_SPACE_RATIO,
|
||||
LINE_CHART_DOT_SIZE } from '../utils/constants';
|
||||
import { makeOverlay, updateOverlay, legendDot } from '../utils/draw';
|
||||
import {
|
||||
getTopOffset, getLeftOffset, MIN_BAR_PERCENT_HEIGHT, BAR_CHART_SPACE_RATIO,
|
||||
LINE_CHART_DOT_SIZE
|
||||
} from '../utils/constants';
|
||||
|
||||
export default class AxisChart extends BaseChart {
|
||||
constructor(parent, args) {
|
||||
@ -44,6 +45,7 @@ export default class AxisChart extends BaseChart {
|
||||
this.config.formatTooltipY = options.tooltipOptions.formatTooltipY;
|
||||
|
||||
this.config.valuesOverPoints = options.valuesOverPoints;
|
||||
this.config.legendRowHeight = 30;
|
||||
}
|
||||
|
||||
prepareData(data=this.data) {
|
||||
@ -423,29 +425,31 @@ export default class AxisChart extends BaseChart {
|
||||
renderLegend() {
|
||||
let s = this.data;
|
||||
if (s.datasets.length > 1) {
|
||||
this.legendArea.textContent = '';
|
||||
let barWidth = AXIS_LEGEND_BAR_SIZE;
|
||||
s.datasets.map((d, i) => {
|
||||
let rect = legendBar(
|
||||
barWidth * i,
|
||||
'0',
|
||||
this.colors[i],
|
||||
d.name,
|
||||
this.config.truncateLegends);
|
||||
this.legendArea.appendChild(rect);
|
||||
});
|
||||
super.renderLegend(s.datasets);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
makeLegend(data, index, x_pos, y_pos) {
|
||||
return legendDot(
|
||||
x_pos,
|
||||
y_pos + 5, // Extra offset
|
||||
12, // size
|
||||
3, // dot radius
|
||||
this.colors[index], // fill
|
||||
data.name, //label
|
||||
null, // value
|
||||
8.75, // base_font_size
|
||||
this.config.truncateLegends // truncate legends
|
||||
);
|
||||
}
|
||||
|
||||
// Overlay
|
||||
makeOverlay() {
|
||||
if(this.init) {
|
||||
if (this.init) {
|
||||
this.init = 0;
|
||||
return;
|
||||
}
|
||||
if(this.overlayGuides) {
|
||||
if (this.overlayGuides) {
|
||||
this.overlayGuides.forEach(g => {
|
||||
let o = g.overlay;
|
||||
o.parentNode.removeChild(o);
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
import SvgTip from '../objects/SvgTip';
|
||||
import { $, isElementInViewport, getElementContentWidth, isHidden } from '../utils/dom';
|
||||
import { makeSVGContainer, makeSVGDefs, makeSVGGroup, makeText } from '../utils/draw';
|
||||
import { BASE_MEASURES, getExtraHeight, getExtraWidth, getTopOffset, getLeftOffset,
|
||||
INIT_CHART_UPDATE_TIMEOUT, CHART_POST_ANIMATE_TIMEOUT, DEFAULT_COLORS} from '../utils/constants';
|
||||
import { LEGEND_ITEM_WIDTH } from '../utils/constants';
|
||||
import {
|
||||
BASE_MEASURES, getExtraHeight, getExtraWidth, getTopOffset, getLeftOffset,
|
||||
INIT_CHART_UPDATE_TIMEOUT, CHART_POST_ANIMATE_TIMEOUT, DEFAULT_COLORS
|
||||
} from '../utils/constants';
|
||||
import { getColor, isValidColor } from '../utils/colors';
|
||||
import { runSMILAnimation } from '../utils/animation';
|
||||
import { downloadFile, prepareForExport } from '../utils/export';
|
||||
@ -262,10 +265,29 @@ export default class BaseChart {
|
||||
}
|
||||
}
|
||||
|
||||
renderLegend() {}
|
||||
renderLegend(dataset) {
|
||||
this.legendArea.textContent = '';
|
||||
let count = 0;
|
||||
let y = 0;
|
||||
|
||||
setupNavigation(init=false) {
|
||||
if(!this.config.isNavigable) return;
|
||||
dataset.map((data, index) => {
|
||||
let divisor = Math.floor(this.width / LEGEND_ITEM_WIDTH);
|
||||
if (count > divisor) {
|
||||
count = 0;
|
||||
y += this.config.legendRowHeight;
|
||||
}
|
||||
let x = LEGEND_ITEM_WIDTH * count;
|
||||
let dot = this.makeLegend(data, index, x, y);
|
||||
this.legendArea.appendChild(dot);
|
||||
count++;
|
||||
});
|
||||
}
|
||||
|
||||
makeLegend() { }
|
||||
|
||||
|
||||
setupNavigation(init = false) {
|
||||
if (!this.config.isNavigable) return;
|
||||
|
||||
if(init) {
|
||||
this.bindOverlay();
|
||||
|
||||
@ -65,7 +65,7 @@ export const CHART_POST_ANIMATE_TIMEOUT = 400;
|
||||
export const DEFAULT_AXIS_CHART_TYPE = 'line';
|
||||
export const AXIS_DATASET_CHART_TYPES = ['line', 'bar'];
|
||||
|
||||
export const AXIS_LEGEND_BAR_SIZE = 100;
|
||||
export const LEGEND_ITEM_WIDTH = 150;
|
||||
export const SERIES_LABEL_SPACE_RATIO = 0.6;
|
||||
|
||||
export const BAR_CHART_SPACE_RATIO = 0.5;
|
||||
|
||||
@ -4,7 +4,7 @@ import { DOT_OVERLAY_SIZE_INCR } from './constants';
|
||||
|
||||
export const AXIS_TICK_LENGTH = 6;
|
||||
const LABEL_MARGIN = 4;
|
||||
const LABEL_MAX_CHARS = 15;
|
||||
const LABEL_MAX_CHARS = 18;
|
||||
export const FONT_SIZE = 10;
|
||||
const BASE_LINE_COLOR = '#E2E6E9';
|
||||
const FONT_FILL = '#313B44';
|
||||
@ -223,43 +223,9 @@ export function heatSquare(className, x, y, size, radius, fill='none', data={})
|
||||
return createSVG("rect", args);
|
||||
}
|
||||
|
||||
export function legendBar(x, y, fill = 'none', label, truncate = true) {
|
||||
label = truncate ? truncateString(label, LABEL_MAX_CHARS) : label;
|
||||
|
||||
let args = {
|
||||
className: 'legend-bar',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: '12px',
|
||||
height: '12px',
|
||||
rx: '2px',
|
||||
ry: '2px',
|
||||
fill: fill
|
||||
};
|
||||
|
||||
let text = createSVG('text', {
|
||||
className: 'legend-dataset-text',
|
||||
x: 0,
|
||||
y: 0,
|
||||
dy: (FONT_SIZE) + 'px',
|
||||
dx: (FONT_SIZE * 1.5) + 'px',
|
||||
'font-size': (FONT_SIZE * 1.2) + 'px',
|
||||
'text-anchor': 'start',
|
||||
fill: FONT_FILL,
|
||||
innerHTML: label
|
||||
});
|
||||
|
||||
let group = createSVG('g', {
|
||||
transform: `translate(${x}, ${y})`
|
||||
});
|
||||
group.appendChild(createSVG("rect", args));
|
||||
group.appendChild(text);
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
export function legendDot(x, y, size, radius, fill='none', label, value, truncate=false) {
|
||||
export function legendDot(x, y, size, radius, fill = 'none', label, value, font_size = null, truncate = false) {
|
||||
label = truncate ? truncateString(label, LABEL_MAX_CHARS) : label;
|
||||
if (!font_size) font_size = FONT_SIZE;
|
||||
|
||||
let args = {
|
||||
className: 'legend-dot',
|
||||
@ -275,32 +241,38 @@ export function legendDot(x, y, size, radius, fill='none', label, value, truncat
|
||||
className: 'legend-dataset-label',
|
||||
x: size,
|
||||
y: 0,
|
||||
dx: (FONT_SIZE) + 'px',
|
||||
dy: (FONT_SIZE/3) + 'px',
|
||||
'font-size': (FONT_SIZE * 1.6) + 'px',
|
||||
dx: (font_size) + 'px',
|
||||
dy: (font_size / 3) + 'px',
|
||||
'font-size': (font_size * 1.6) + 'px',
|
||||
'text-anchor': 'start',
|
||||
fill: FONT_FILL,
|
||||
innerHTML: label
|
||||
});
|
||||
|
||||
let textValue = createSVG('text', {
|
||||
className: 'legend-dataset-value',
|
||||
x: size,
|
||||
y: FONT_SIZE + 10,
|
||||
dx: (FONT_SIZE) + 'px',
|
||||
dy: (FONT_SIZE/3) + 'px',
|
||||
'font-size': (FONT_SIZE * 1.2) + 'px',
|
||||
'text-anchor': 'start',
|
||||
fill: FONT_FILL,
|
||||
innerHTML: value
|
||||
});
|
||||
let textValue = null;
|
||||
if (value) {
|
||||
textValue = createSVG('text', {
|
||||
className: 'legend-dataset-value',
|
||||
x: size,
|
||||
y: FONT_SIZE + 10,
|
||||
dx: (FONT_SIZE) + 'px',
|
||||
dy: (FONT_SIZE / 3) + 'px',
|
||||
'font-size': (FONT_SIZE * 1.2) + 'px',
|
||||
'text-anchor': 'start',
|
||||
fill: FONT_FILL,
|
||||
innerHTML: value
|
||||
});
|
||||
}
|
||||
|
||||
let group = createSVG('g', {
|
||||
transform: `translate(${x}, ${y})`
|
||||
});
|
||||
group.appendChild(createSVG("rect", args));
|
||||
group.appendChild(textLabel);
|
||||
group.appendChild(textValue);
|
||||
|
||||
if (value && textValue) {
|
||||
group.appendChild(textValue);
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user