mirror of
https://github.com/getredash/redash.git
synced 2026-03-22 19:00:09 -04:00
101 lines
3.0 KiB
JavaScript
101 lines
3.0 KiB
JavaScript
import { each, includes, isString, map, reduce } from 'lodash';
|
|
import d3 from 'd3';
|
|
import { ColorPaletteArray } from '@/visualizations/ColorPalette';
|
|
|
|
import { cleanNumber, normalizeValue } from './utils';
|
|
|
|
export function getPieDimensions(series) {
|
|
const rows = series.length > 2 ? 2 : 1;
|
|
const cellsInRow = Math.ceil(series.length / rows);
|
|
const cellWidth = 1 / cellsInRow;
|
|
const cellHeight = 1 / rows;
|
|
const xPadding = 0.02;
|
|
const yPadding = 0.1;
|
|
|
|
return { rows, cellsInRow, cellWidth, cellHeight, xPadding, yPadding };
|
|
}
|
|
|
|
function getPieHoverInfoPattern(options) {
|
|
const hasX = /{{\s*@@x\s*}}/.test(options.textFormat);
|
|
let result = 'text';
|
|
if (!hasX) result += '+label';
|
|
return result;
|
|
}
|
|
|
|
function prepareSeries(series, options, additionalOptions) {
|
|
const {
|
|
cellWidth, cellHeight, xPadding, yPadding, cellsInRow, hasX,
|
|
index, hoverInfoPattern, getValueColor,
|
|
} = additionalOptions;
|
|
|
|
const xPosition = (index % cellsInRow) * cellWidth;
|
|
const yPosition = Math.floor(index / cellsInRow) * cellHeight;
|
|
|
|
const labels = [];
|
|
const values = [];
|
|
const sourceData = new Map();
|
|
const seriesTotal = reduce(series.data, (result, row) => {
|
|
const y = cleanNumber(row.y);
|
|
return result + Math.abs(y);
|
|
}, 0);
|
|
each(series.data, (row) => {
|
|
const x = hasX ? normalizeValue(row.x, options.xAxis.type) : `Slice ${index}`;
|
|
const y = cleanNumber(row.y);
|
|
labels.push(x);
|
|
values.push(y);
|
|
sourceData.set(x, {
|
|
x,
|
|
y,
|
|
yPercent: y / seriesTotal * 100,
|
|
row,
|
|
});
|
|
});
|
|
|
|
return {
|
|
visible: true,
|
|
values,
|
|
labels,
|
|
type: 'pie',
|
|
hole: 0.4,
|
|
marker: {
|
|
colors: map(series.data, row => getValueColor(row.x)),
|
|
},
|
|
hoverinfo: hoverInfoPattern,
|
|
text: [],
|
|
textinfo: options.showDataLabels ? 'percent' : 'none',
|
|
textposition: 'inside',
|
|
textfont: {
|
|
// In Plotly@1.42.0 and upper this options can be set to array of colors (similar to `marker.colors`):
|
|
// `colors: map(markerColors, c => chooseTextColorForBackground(c))`
|
|
color: '#ffffff',
|
|
},
|
|
name: series.name,
|
|
direction: options.direction.type,
|
|
domain: {
|
|
x: [xPosition, xPosition + cellWidth - xPadding],
|
|
y: [yPosition, yPosition + cellHeight - yPadding],
|
|
},
|
|
sourceData,
|
|
};
|
|
}
|
|
|
|
export default function preparePieData(seriesList, options) {
|
|
// we will use this to assign colors for values that have no explicitly set color
|
|
const getDefaultColor = d3.scale.ordinal().domain([]).range(ColorPaletteArray);
|
|
const valuesColors = {};
|
|
each(options.valuesOptions, (item, key) => {
|
|
if (isString(item.color) && (item.color !== '')) {
|
|
valuesColors[key] = item.color;
|
|
}
|
|
});
|
|
|
|
const additionalOptions = {
|
|
...getPieDimensions(seriesList),
|
|
hasX: includes(options.columnMapping, 'x'),
|
|
hoverInfoPattern: getPieHoverInfoPattern(options),
|
|
getValueColor: v => valuesColors[v] || getDefaultColor(v),
|
|
};
|
|
|
|
return map(seriesList, (series, index) => prepareSeries(series, options, { ...additionalOptions, index }));
|
|
}
|