mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-18 14:59:53 +02:00
support for multiple datasets added
This commit is contained in:
@@ -52,7 +52,7 @@
|
||||
line [+1.3, .6, 2.4, -.34]
|
||||
</pre>
|
||||
|
||||
<h1>XY Charts Bar with multiple category</h1>
|
||||
<h1>XY Charts bar with single dataset</h1>
|
||||
<pre class="mermaid">
|
||||
xychart-beta
|
||||
title "Basic xychart with many categories"
|
||||
@@ -61,7 +61,25 @@
|
||||
bar "sample bar" [52, 96, 35, 10, 87, 34, 67, 99]
|
||||
</pre>
|
||||
|
||||
<h1>XY Charts line with multiple category</h1>
|
||||
<h1>XY Charts bar with multiple datasets</h1>
|
||||
<pre class="mermaid">
|
||||
xychart-beta
|
||||
title "Basic xychart with multiple datasets"
|
||||
x-axis "Relevant categories" [category1, "category 2", category3, category4, category5, category6, category7]
|
||||
y-axis Animals 10 --> 200
|
||||
bar [["dogs" [52, 96, 35, 10, 87, 34, 67, 99]],["cats" [15, 7, 23, 55, 11, 41, 26, 3]]]
|
||||
</pre>
|
||||
|
||||
<h1>XY Charts bar horizontal with multiple datasets</h1>
|
||||
<pre class="mermaid">
|
||||
xychart-beta horizontal
|
||||
title "Basic xychart with multiple datasets"
|
||||
x-axis "Relevant categories" [category1, "category 2", category3, category4, category5, category6, category7]
|
||||
y-axis Animals 10 --> 200
|
||||
bar [["dogs" [52, 96, 35, 10, 87, 34, 67, 99]],["cats" [15, 7, 23, 55, 11, 41, 26, 3]]]
|
||||
</pre>
|
||||
|
||||
<h1>XY Charts line single dataset</h1>
|
||||
<pre class="mermaid">
|
||||
xychart-beta
|
||||
title "Line chart with many category"
|
||||
@@ -70,7 +88,7 @@
|
||||
line "sample line" [52, 96, 35, 10, 87, 34, 67, 99]
|
||||
</pre>
|
||||
|
||||
<h1>XY Charts category with large text</h1>
|
||||
<h1>XY Charts bar with large text</h1>
|
||||
<pre class="mermaid">
|
||||
xychart-beta
|
||||
title "Basic xychart with many categories with category overlap"
|
||||
|
@@ -3,7 +3,7 @@ import type { Axis } from '../axis/index.js';
|
||||
|
||||
export class BarPlot {
|
||||
constructor(
|
||||
private barData: BarPlotData,
|
||||
private barData: BarPlotData[],
|
||||
private boundingRect: BoundingRect,
|
||||
private xAxis: Axis,
|
||||
private yAxis: Axis,
|
||||
@@ -12,49 +12,58 @@ export class BarPlot {
|
||||
) {}
|
||||
|
||||
getDrawableElement(): DrawableElem[] {
|
||||
const finalData: [number, number][] = this.barData.data.map((d) => [
|
||||
this.xAxis.getScaleValue(d[0]),
|
||||
this.yAxis.getScaleValue(d[1]),
|
||||
]);
|
||||
const offset = new Array(this.barData[0].data.length).fill(0);
|
||||
return this.barData.map((barData, dataIndex) => {
|
||||
const finalData: [number, number][] = barData.data.map((d) => [
|
||||
this.xAxis.getScaleValue(d[0]),
|
||||
this.yAxis.getScaleValue(d[1]),
|
||||
]);
|
||||
|
||||
const barPaddingPercent = 0.05;
|
||||
const barPaddingPercent = 0.05;
|
||||
|
||||
const barWidth =
|
||||
Math.min(this.xAxis.getAxisOuterPadding() * 2, this.xAxis.getTickDistance()) *
|
||||
(1 - barPaddingPercent);
|
||||
const barWidthHalf = barWidth / 2;
|
||||
const barWidth =
|
||||
Math.min(this.xAxis.getAxisOuterPadding() * 2, this.xAxis.getTickDistance()) *
|
||||
(1 - barPaddingPercent);
|
||||
const barWidthHalf = barWidth / 2;
|
||||
|
||||
if (this.orientation === 'horizontal') {
|
||||
return [
|
||||
{
|
||||
groupTexts: ['plot', `bar-plot-${this.plotIndex}`],
|
||||
if (this.orientation === 'horizontal') {
|
||||
return {
|
||||
groupTexts: ['plot', `bar-plot-${this.plotIndex}-${dataIndex}`],
|
||||
type: 'rect',
|
||||
data: finalData.map((data, index) => {
|
||||
const x = offset[index] + this.boundingRect.x;
|
||||
const width = data[1] - this.boundingRect.x;
|
||||
offset[index] += width;
|
||||
return {
|
||||
x,
|
||||
y: data[0] - barWidthHalf,
|
||||
height: barWidth,
|
||||
width,
|
||||
fill: barData.fill,
|
||||
strokeWidth: 0,
|
||||
strokeFill: barData.fill,
|
||||
}
|
||||
}),
|
||||
};
|
||||
}
|
||||
return {
|
||||
groupTexts: ['plot', `bar-plot-${this.plotIndex}-${dataIndex}`],
|
||||
type: 'rect',
|
||||
data: finalData.map((data) => ({
|
||||
x: this.boundingRect.x,
|
||||
y: data[0] - barWidthHalf,
|
||||
height: barWidth,
|
||||
width: data[1] - this.boundingRect.x,
|
||||
fill: this.barData.fill,
|
||||
strokeWidth: 0,
|
||||
strokeFill: this.barData.fill,
|
||||
})),
|
||||
},
|
||||
];
|
||||
}
|
||||
return [
|
||||
{
|
||||
groupTexts: ['plot', `bar-plot-${this.plotIndex}`],
|
||||
type: 'rect',
|
||||
data: finalData.map((data) => ({
|
||||
x: data[0] - barWidthHalf,
|
||||
y: data[1],
|
||||
width: barWidth,
|
||||
height: this.boundingRect.y + this.boundingRect.height - data[1],
|
||||
fill: this.barData.fill,
|
||||
strokeWidth: 0,
|
||||
strokeFill: this.barData.fill,
|
||||
})),
|
||||
},
|
||||
];
|
||||
data: finalData.map((data, index) => {
|
||||
const y = data[1] - offset[index];
|
||||
const height = this.boundingRect.y + this.boundingRect.height - data[1];
|
||||
offset[index] += height;
|
||||
return {
|
||||
x: data[0] - barWidthHalf,
|
||||
y,
|
||||
width: barWidth,
|
||||
height,
|
||||
fill: barData.fill,
|
||||
strokeWidth: 0,
|
||||
strokeFill: barData.fill,
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -6,6 +6,8 @@ import type {
|
||||
Point,
|
||||
XYChartThemeConfig,
|
||||
XYChartConfig,
|
||||
BarPlotData,
|
||||
LinePlotData,
|
||||
} from '../../interfaces.js';
|
||||
import type { Axis } from '../axis/index.js';
|
||||
import type { ChartComponent } from '../../interfaces.js';
|
||||
@@ -55,34 +57,31 @@ export class BasePlot implements Plot {
|
||||
throw Error('Axes must be passed to render Plots');
|
||||
}
|
||||
const drawableElem: DrawableElem[] = [];
|
||||
for (const [i, plot] of this.chartData.plots.entries()) {
|
||||
switch (plot.type) {
|
||||
case 'line':
|
||||
{
|
||||
const linePlot = new LinePlot(
|
||||
plot,
|
||||
this.xAxis,
|
||||
this.yAxis,
|
||||
this.chartConfig.chartOrientation,
|
||||
i
|
||||
);
|
||||
drawableElem.push(...linePlot.getDrawableElement());
|
||||
}
|
||||
break;
|
||||
case 'bar':
|
||||
{
|
||||
const barPlot = new BarPlot(
|
||||
plot,
|
||||
this.boundingRect,
|
||||
this.xAxis,
|
||||
this.yAxis,
|
||||
this.chartConfig.chartOrientation,
|
||||
i
|
||||
);
|
||||
drawableElem.push(...barPlot.getDrawableElement());
|
||||
}
|
||||
break;
|
||||
}
|
||||
const linePlots = this.chartData.plots.filter(plot => plot.type === 'line') as LinePlotData[];
|
||||
const barPlots = this.chartData.plots.filter(plot => plot.type === 'bar') as BarPlotData[];
|
||||
|
||||
let plotIndex = 0;
|
||||
if(linePlots.length) {
|
||||
const linePlot = new LinePlot(
|
||||
linePlots[0],
|
||||
this.xAxis,
|
||||
this.yAxis,
|
||||
this.chartConfig.chartOrientation,
|
||||
plotIndex
|
||||
);
|
||||
drawableElem.push(...linePlot.getDrawableElement());
|
||||
}
|
||||
if(barPlots.length) {
|
||||
const barPlot = new BarPlot(
|
||||
barPlots,
|
||||
this.boundingRect,
|
||||
this.xAxis,
|
||||
this.yAxis,
|
||||
this.chartConfig.chartOrientation,
|
||||
plotIndex
|
||||
);
|
||||
drawableElem.push(...barPlot.getDrawableElement());
|
||||
plotIndex++;
|
||||
}
|
||||
return drawableElem;
|
||||
}
|
||||
|
@@ -102,13 +102,28 @@ statement
|
||||
| Y_AXIS parseYAxis
|
||||
| LINE plotData { yy.setLineData({text: '', type: 'text'}, $plotData); }
|
||||
| LINE text plotData { yy.setLineData($text, $plotData); }
|
||||
| BAR plotData { yy.setBarData({text: '', type: 'text'}, $plotData); }
|
||||
| BAR text plotData { yy.setBarData($text, $plotData); }
|
||||
| BAR datasets { yy.setBarData($datasets); }
|
||||
| acc_title acc_title_value { $$=$acc_title_value.trim();yy.setAccTitle($$); }
|
||||
| acc_descr acc_descr_value { $$=$acc_descr_value.trim();yy.setAccDescription($$); }
|
||||
| acc_descr_multiline_value { $$=$acc_descr_multiline_value.trim();yy.setAccDescription($$); }
|
||||
;
|
||||
|
||||
datasets
|
||||
: SQUARE_BRACES_START datasetBraced COMMA datasets SQUARE_BRACES_END { $$ = [$datasetBraced, ...$datasets] }
|
||||
| SQUARE_BRACES_START datasetBraced SQUARE_BRACES_END { $$ = [$datasetBraced] }
|
||||
| datasetBraced { $$ = [$datasetBraced] }
|
||||
| dataset { $$ = [$dataset] }
|
||||
;
|
||||
|
||||
datasetBraced
|
||||
: SQUARE_BRACES_START dataset SQUARE_BRACES_END { $$ = $dataset }
|
||||
;
|
||||
|
||||
dataset
|
||||
: plotData { $$ = ['', $plotData] }
|
||||
| text plotData { $$ = [$text, $plotData] }
|
||||
;
|
||||
|
||||
plotData
|
||||
: SQUARE_BRACES_START commaSeparatedNumbers SQUARE_BRACES_END { $$ = $commaSeparatedNumbers }
|
||||
;
|
||||
|
@@ -169,14 +169,18 @@ function setLineData(title: NormalTextType, data: number[]) {
|
||||
plotIndex++;
|
||||
}
|
||||
|
||||
function setBarData(title: NormalTextType, data: number[]) {
|
||||
const plotData = transformDataWithoutCategory(data);
|
||||
xyChartData.plots.push({
|
||||
type: 'bar',
|
||||
fill: getPlotColorFromPalette(plotIndex),
|
||||
data: plotData,
|
||||
type NamedDataset = [title: NormalTextType, data: number[]];
|
||||
|
||||
function setBarData(datasets: NamedDataset[]) {
|
||||
datasets.forEach(dataset => {
|
||||
const plotData = transformDataWithoutCategory(dataset[1]);
|
||||
xyChartData.plots.push({
|
||||
type: 'bar',
|
||||
fill: getPlotColorFromPalette(plotIndex),
|
||||
data: plotData,
|
||||
});
|
||||
plotIndex++;
|
||||
});
|
||||
plotIndex++;
|
||||
}
|
||||
|
||||
function getDrawableElem(): DrawableElem[] {
|
||||
|
Reference in New Issue
Block a user