mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-10-28 17:34:16 +01:00
Addressed all requested changes
This commit is contained in:
@@ -17,7 +17,7 @@
|
|||||||
<h1>XY Charts demos</h1>
|
<h1>XY Charts demos</h1>
|
||||||
<pre class="mermaid">
|
<pre class="mermaid">
|
||||||
xychart-beta horizontal
|
xychart-beta horizontal
|
||||||
title Basic xychart
|
title "Basic xychart"
|
||||||
x-axis "this is x axis" [category1, "category 2", category3, category4]
|
x-axis "this is x axis" [category1, "category 2", category3, category4]
|
||||||
y-axis yaxisText 10 --> 150
|
y-axis yaxisText 10 --> 150
|
||||||
bar "sample bat" [52, 96, 35, 10]
|
bar "sample bat" [52, 96, 35, 10]
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
<h1>XY Charts demos</h1>
|
<h1>XY Charts demos</h1>
|
||||||
<pre class="mermaid">
|
<pre class="mermaid">
|
||||||
xychart-beta
|
xychart-beta
|
||||||
title Basic xychart
|
title "Basic xychart"
|
||||||
x-axis "this is x axis" [category1, "category 2", category3, category4]
|
x-axis "this is x axis" [category1, "category 2", category3, category4]
|
||||||
y-axis yaxisText 10 --> 150
|
y-axis yaxisText 10 --> 150
|
||||||
bar "sample bat" [52, 96, 35, 10]
|
bar "sample bat" [52, 96, 35, 10]
|
||||||
@@ -48,6 +48,24 @@
|
|||||||
bar "sample bat" [52, 96, 35, 10]
|
bar "sample bat" [52, 96, 35, 10]
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
<h1>XY Charts demos</h1>
|
||||||
|
<pre class="mermaid">
|
||||||
|
xychart-beta
|
||||||
|
title "Basic xychart with many categories"
|
||||||
|
x-axis "this is x axis" [category1, "category 2", category3, category4, category5, category6, category7]
|
||||||
|
y-axis yaxisText 10 --> 150
|
||||||
|
bar "sample bat" [52, 96, 35, 10, 87, 34, 67, 99]
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<h1>XY Charts demos</h1>
|
||||||
|
<pre class="mermaid">
|
||||||
|
xychart-beta
|
||||||
|
title "Basic xychart with many categories with category overlap"
|
||||||
|
x-axis "this is x axis" [category1, "Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.", category3, category4, category5, category6, category7]
|
||||||
|
y-axis yaxisText 10 --> 150
|
||||||
|
bar "sample bat" [52, 96, 35, 10, 87, 34, 67, 99]
|
||||||
|
</pre>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<script type="module">
|
<script type="module">
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export interface BarPlotData {
|
|||||||
export type PlotData = LinePlotData | BarPlotData;
|
export type PlotData = LinePlotData | BarPlotData;
|
||||||
|
|
||||||
export function isBarPlot(data: PlotData): data is BarPlotData {
|
export function isBarPlot(data: PlotData): data is BarPlotData {
|
||||||
return data.type === 'line';
|
return data.type === 'bar';
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BandAxisDataType {
|
export interface BandAxisDataType {
|
||||||
|
|||||||
@@ -8,23 +8,25 @@ import {
|
|||||||
} from './Interfaces.js';
|
} from './Interfaces.js';
|
||||||
import { getChartTitleComponent } from './components/ChartTitle.js';
|
import { getChartTitleComponent } from './components/ChartTitle.js';
|
||||||
import { ChartComponent } from './Interfaces.js';
|
import { ChartComponent } from './Interfaces.js';
|
||||||
import { IAxis, getAxis } from './components/axis/index.js';
|
import { Axis, getAxis } from './components/axis/index.js';
|
||||||
import { IPlot, getPlotComponent } from './components/plot/index.js';
|
import { Plot, getPlotComponent } from './components/plot/index.js';
|
||||||
|
import { SVGGType } from '../xychartDb.js';
|
||||||
|
|
||||||
export class Orchestrator {
|
export class Orchestrator {
|
||||||
private componentStore: {
|
private componentStore: {
|
||||||
title: ChartComponent;
|
title: ChartComponent;
|
||||||
plot: IPlot;
|
plot: Plot;
|
||||||
xAxis: IAxis;
|
xAxis: Axis;
|
||||||
yAxis: IAxis;
|
yAxis: Axis;
|
||||||
};
|
};
|
||||||
constructor(
|
constructor(
|
||||||
private chartConfig: XYChartConfig,
|
private chartConfig: XYChartConfig,
|
||||||
private chartData: XYChartData,
|
private chartData: XYChartData,
|
||||||
private chartThemeConfig: XYChartThemeConfig
|
private chartThemeConfig: XYChartThemeConfig,
|
||||||
|
private tmpSVGGElem: SVGGType
|
||||||
) {
|
) {
|
||||||
this.componentStore = {
|
this.componentStore = {
|
||||||
title: getChartTitleComponent(chartConfig, chartData, chartThemeConfig),
|
title: getChartTitleComponent(chartConfig, chartData, chartThemeConfig, tmpSVGGElem),
|
||||||
plot: getPlotComponent(chartConfig, chartData, chartThemeConfig),
|
plot: getPlotComponent(chartConfig, chartData, chartThemeConfig),
|
||||||
xAxis: getAxis(
|
xAxis: getAxis(
|
||||||
chartData.xAxis,
|
chartData.xAxis,
|
||||||
@@ -34,7 +36,7 @@ export class Orchestrator {
|
|||||||
labelColor: chartThemeConfig.xAxisLableColor,
|
labelColor: chartThemeConfig.xAxisLableColor,
|
||||||
tickColor: chartThemeConfig.xAxisTickColor,
|
tickColor: chartThemeConfig.xAxisTickColor,
|
||||||
},
|
},
|
||||||
chartConfig.fontFamily
|
tmpSVGGElem
|
||||||
),
|
),
|
||||||
yAxis: getAxis(
|
yAxis: getAxis(
|
||||||
chartData.yAxis,
|
chartData.yAxis,
|
||||||
@@ -44,7 +46,7 @@ export class Orchestrator {
|
|||||||
labelColor: chartThemeConfig.yAxisLableColor,
|
labelColor: chartThemeConfig.yAxisLableColor,
|
||||||
tickColor: chartThemeConfig.yAxisTickColor,
|
tickColor: chartThemeConfig.yAxisTickColor,
|
||||||
},
|
},
|
||||||
chartConfig.fontFamily
|
tmpSVGGElem
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,49 +1,15 @@
|
|||||||
import { Dimension } from './Interfaces.js';
|
import { Dimension } from './Interfaces.js';
|
||||||
|
import { computeDimensionOfText } from '../../../rendering-util/createText.js';
|
||||||
|
import { SVGGType } from '../xychartDb.js';
|
||||||
|
|
||||||
export interface ITextDimensionCalculator {
|
export interface TextDimensionCalculator {
|
||||||
getDimension(texts: string[], fontSize: number, fontFamily?: string): Dimension;
|
getMaxDimension(texts: string[], fontSize: number): Dimension;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TextDimensionCalculator implements ITextDimensionCalculator {
|
export class TextDimensionCalculatorWithFont implements TextDimensionCalculator {
|
||||||
getDimension(texts: string[], fontSize: number): Dimension {
|
constructor(private parentGroup: SVGGType) {}
|
||||||
return {
|
getMaxDimension(texts: string[], fontSize: number): Dimension {
|
||||||
width: texts.reduce((acc, cur) => Math.max(cur.length, acc), 0) * fontSize,
|
if (!this.parentGroup) {
|
||||||
height: fontSize,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class TextDimensionCalculatorWithFont implements ITextDimensionCalculator {
|
|
||||||
private container: HTMLSpanElement | null = null;
|
|
||||||
private hiddenElementId = 'mermaid-text-dimension-calculator';
|
|
||||||
constructor(fontFamily?: string) {
|
|
||||||
if (document) {
|
|
||||||
let parentContainer = document.getElementById(this.hiddenElementId);
|
|
||||||
if (!parentContainer) {
|
|
||||||
parentContainer = document.createElement('div');
|
|
||||||
parentContainer.id = this.hiddenElementId;
|
|
||||||
parentContainer.style.position = 'absolute';
|
|
||||||
parentContainer.style.top = '-100px';
|
|
||||||
parentContainer.style.left = '0px';
|
|
||||||
parentContainer.style.visibility = 'hidden';
|
|
||||||
document.body.append(parentContainer);
|
|
||||||
}
|
|
||||||
const fontClassName = `font-${fontFamily}`;
|
|
||||||
const prevContainerAvailable = parentContainer.getElementsByClassName(fontClassName);
|
|
||||||
if (prevContainerAvailable.length > 0) {
|
|
||||||
this.container = prevContainerAvailable.item(0) as HTMLSpanElement;
|
|
||||||
} else {
|
|
||||||
this.container = document.createElement('div');
|
|
||||||
this.container.className = fontClassName;
|
|
||||||
if (fontFamily) {
|
|
||||||
this.container.style.fontFamily = fontFamily;
|
|
||||||
}
|
|
||||||
parentContainer.append(this.container);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getDimension(texts: string[], fontSize: number): Dimension {
|
|
||||||
if (!this.container) {
|
|
||||||
return {
|
return {
|
||||||
width: texts.reduce((acc, cur) => Math.max(cur.length, acc), 0) * fontSize,
|
width: texts.reduce((acc, cur) => Math.max(cur.length, acc), 0) * fontSize,
|
||||||
height: fontSize,
|
height: fontSize,
|
||||||
@@ -55,14 +21,17 @@ export class TextDimensionCalculatorWithFont implements ITextDimensionCalculator
|
|||||||
height: 0,
|
height: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.container.style.fontSize = `${fontSize}px`;
|
const elem = this.parentGroup
|
||||||
|
.append('g')
|
||||||
|
.attr('visibility', 'hidden')
|
||||||
|
.attr('font-size', fontSize);
|
||||||
|
|
||||||
for (const t of texts) {
|
for (const t of texts) {
|
||||||
this.container.innerHTML = t;
|
const bbox = computeDimensionOfText(elem, 1, t);
|
||||||
const bbox = this.container.getBoundingClientRect();
|
|
||||||
dimension.width = Math.max(dimension.width, bbox.width);
|
dimension.width = Math.max(dimension.width, bbox.width);
|
||||||
dimension.height = Math.max(dimension.height, bbox.height);
|
dimension.height = Math.max(dimension.height, bbox.height);
|
||||||
}
|
}
|
||||||
|
elem.remove();
|
||||||
return dimension;
|
return dimension;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { SVGGType } from '../../xychartDb.js';
|
||||||
import {
|
import {
|
||||||
BoundingRect,
|
BoundingRect,
|
||||||
ChartComponent,
|
ChartComponent,
|
||||||
@@ -9,7 +10,7 @@ import {
|
|||||||
XYChartConfig,
|
XYChartConfig,
|
||||||
} from '../Interfaces.js';
|
} from '../Interfaces.js';
|
||||||
import {
|
import {
|
||||||
ITextDimensionCalculator,
|
TextDimensionCalculator,
|
||||||
TextDimensionCalculatorWithFont,
|
TextDimensionCalculatorWithFont,
|
||||||
} from '../TextDimensionCalculator.js';
|
} from '../TextDimensionCalculator.js';
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@ export class ChartTitle implements ChartComponent {
|
|||||||
private boundingRect: BoundingRect;
|
private boundingRect: BoundingRect;
|
||||||
private showChartTitle: boolean;
|
private showChartTitle: boolean;
|
||||||
constructor(
|
constructor(
|
||||||
private textDimensionCalculator: ITextDimensionCalculator,
|
private textDimensionCalculator: TextDimensionCalculator,
|
||||||
private chartConfig: XYChartConfig,
|
private chartConfig: XYChartConfig,
|
||||||
private chartData: XYChartData,
|
private chartData: XYChartData,
|
||||||
private chartThemeConfig: XYChartThemeConfig
|
private chartThemeConfig: XYChartThemeConfig
|
||||||
@@ -35,7 +36,7 @@ export class ChartTitle implements ChartComponent {
|
|||||||
this.boundingRect.y = point.y;
|
this.boundingRect.y = point.y;
|
||||||
}
|
}
|
||||||
calculateSpace(availableSpace: Dimension): Dimension {
|
calculateSpace(availableSpace: Dimension): Dimension {
|
||||||
const titleDimension = this.textDimensionCalculator.getDimension(
|
const titleDimension = this.textDimensionCalculator.getMaxDimension(
|
||||||
[this.chartData.title],
|
[this.chartData.title],
|
||||||
this.chartConfig.titleFontSize
|
this.chartConfig.titleFontSize
|
||||||
);
|
);
|
||||||
@@ -82,8 +83,9 @@ export class ChartTitle implements ChartComponent {
|
|||||||
export function getChartTitleComponent(
|
export function getChartTitleComponent(
|
||||||
chartConfig: XYChartConfig,
|
chartConfig: XYChartConfig,
|
||||||
chartData: XYChartData,
|
chartData: XYChartData,
|
||||||
chartThemeConfig: XYChartThemeConfig
|
chartThemeConfig: XYChartThemeConfig,
|
||||||
|
tmpSVGGElem: SVGGType
|
||||||
): ChartComponent {
|
): ChartComponent {
|
||||||
const textDimensionCalculator = new TextDimensionCalculatorWithFont(chartConfig.fontFamily);
|
const textDimensionCalculator = new TextDimensionCalculatorWithFont(tmpSVGGElem);
|
||||||
return new ChartTitle(textDimensionCalculator, chartConfig, chartData, chartThemeConfig);
|
return new ChartTitle(textDimensionCalculator, chartConfig, chartData, chartThemeConfig);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ScaleBand, scaleBand } from 'd3';
|
import { ScaleBand, scaleBand } from 'd3';
|
||||||
import { log } from '../../../../../logger.js';
|
import { log } from '../../../../../logger.js';
|
||||||
import { ITextDimensionCalculator } from '../../TextDimensionCalculator.js';
|
import { TextDimensionCalculator } from '../../TextDimensionCalculator.js';
|
||||||
import { BaseAxis } from './BaseAxis.js';
|
import { BaseAxis } from './BaseAxis.js';
|
||||||
import { XYChartAxisThemeConfig, XYChartAxisConfig } from '../../Interfaces.js';
|
import { XYChartAxisThemeConfig, XYChartAxisConfig } from '../../Interfaces.js';
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ export class BandAxis extends BaseAxis {
|
|||||||
axisThemeConfig: XYChartAxisThemeConfig,
|
axisThemeConfig: XYChartAxisThemeConfig,
|
||||||
categories: string[],
|
categories: string[],
|
||||||
title: string,
|
title: string,
|
||||||
textDimensionCalculator: ITextDimensionCalculator
|
textDimensionCalculator: TextDimensionCalculator
|
||||||
) {
|
) {
|
||||||
super(axisConfig, title, textDimensionCalculator, axisThemeConfig);
|
super(axisConfig, title, textDimensionCalculator, axisThemeConfig);
|
||||||
this.categories = categories;
|
this.categories = categories;
|
||||||
|
|||||||
@@ -7,10 +7,12 @@ import {
|
|||||||
XYChartAxisThemeConfig,
|
XYChartAxisThemeConfig,
|
||||||
XYChartAxisConfig,
|
XYChartAxisConfig,
|
||||||
} from '../../Interfaces.js';
|
} from '../../Interfaces.js';
|
||||||
import { ITextDimensionCalculator } from '../../TextDimensionCalculator.js';
|
import { TextDimensionCalculator } from '../../TextDimensionCalculator.js';
|
||||||
import { AxisPosition, IAxis } from './index.js';
|
import { AxisPosition, Axis } from './index.js';
|
||||||
|
|
||||||
export abstract class BaseAxis implements IAxis {
|
const BAR_WIDTH_TO_TICK_WIDTH_RATIO = 0.7;
|
||||||
|
|
||||||
|
export abstract class BaseAxis implements Axis {
|
||||||
protected boundingRect: BoundingRect = { x: 0, y: 0, width: 0, height: 0 };
|
protected boundingRect: BoundingRect = { x: 0, y: 0, width: 0, height: 0 };
|
||||||
protected axisPosition: AxisPosition = 'left';
|
protected axisPosition: AxisPosition = 'left';
|
||||||
private range: [number, number];
|
private range: [number, number];
|
||||||
@@ -22,7 +24,7 @@ export abstract class BaseAxis implements IAxis {
|
|||||||
constructor(
|
constructor(
|
||||||
protected axisConfig: XYChartAxisConfig,
|
protected axisConfig: XYChartAxisConfig,
|
||||||
protected title: string,
|
protected title: string,
|
||||||
protected textDimensionCalculator: ITextDimensionCalculator,
|
protected textDimensionCalculator: TextDimensionCalculator,
|
||||||
protected axisThemeConfig: XYChartAxisThemeConfig
|
protected axisThemeConfig: XYChartAxisThemeConfig
|
||||||
) {
|
) {
|
||||||
this.range = [0, 10];
|
this.range = [0, 10];
|
||||||
@@ -58,15 +60,15 @@ export abstract class BaseAxis implements IAxis {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getLabelDimension(): Dimension {
|
private getLabelDimension(): Dimension {
|
||||||
return this.textDimensionCalculator.getDimension(
|
return this.textDimensionCalculator.getMaxDimension(
|
||||||
this.getTickValues().map((tick) => tick.toString()),
|
this.getTickValues().map((tick) => tick.toString()),
|
||||||
this.axisConfig.labelFontSize
|
this.axisConfig.labelFontSize
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
recalculateOuterPaddingToDrawBar(): void {
|
recalculateOuterPaddingToDrawBar(): void {
|
||||||
if (0.7 * this.getTickDistance() > this.outerPadding * 2) {
|
if (BAR_WIDTH_TO_TICK_WIDTH_RATIO * this.getTickDistance() > this.outerPadding * 2) {
|
||||||
this.outerPadding = Math.floor((0.7 * this.getTickDistance()) / 2);
|
this.outerPadding = Math.floor((BAR_WIDTH_TO_TICK_WIDTH_RATIO * this.getTickDistance()) / 2);
|
||||||
}
|
}
|
||||||
this.recalculateScale();
|
this.recalculateScale();
|
||||||
}
|
}
|
||||||
@@ -88,7 +90,7 @@ export abstract class BaseAxis implements IAxis {
|
|||||||
availableHeight -= this.axisConfig.tickLength;
|
availableHeight -= this.axisConfig.tickLength;
|
||||||
}
|
}
|
||||||
if (this.axisConfig.showTitle) {
|
if (this.axisConfig.showTitle) {
|
||||||
const spaceRequired = this.textDimensionCalculator.getDimension(
|
const spaceRequired = this.textDimensionCalculator.getMaxDimension(
|
||||||
[this.title],
|
[this.title],
|
||||||
this.axisConfig.labelFontSize
|
this.axisConfig.labelFontSize
|
||||||
);
|
);
|
||||||
@@ -120,7 +122,7 @@ export abstract class BaseAxis implements IAxis {
|
|||||||
availableWidth -= this.axisConfig.tickLength;
|
availableWidth -= this.axisConfig.tickLength;
|
||||||
}
|
}
|
||||||
if (this.axisConfig.showTitle) {
|
if (this.axisConfig.showTitle) {
|
||||||
const spaceRequired = this.textDimensionCalculator.getDimension(
|
const spaceRequired = this.textDimensionCalculator.getMaxDimension(
|
||||||
[this.title],
|
[this.title],
|
||||||
this.axisConfig.labelFontSize
|
this.axisConfig.labelFontSize
|
||||||
);
|
);
|
||||||
@@ -270,7 +272,7 @@ export abstract class BaseAxis implements IAxis {
|
|||||||
if (this.showLabel) {
|
if (this.showLabel) {
|
||||||
drawableElement.push({
|
drawableElement.push({
|
||||||
type: 'text',
|
type: 'text',
|
||||||
groupTexts: ['bottom-axis', 'label'],
|
groupTexts: ['top-axis', 'label'],
|
||||||
data: this.getTickValues().map((tick) => ({
|
data: this.getTickValues().map((tick) => ({
|
||||||
text: tick.toString(),
|
text: tick.toString(),
|
||||||
x: this.getScaleValue(tick),
|
x: this.getScaleValue(tick),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ScaleLinear, scaleLinear } from 'd3';
|
import { ScaleLinear, scaleLinear } from 'd3';
|
||||||
import { log } from '../../../../../logger.js';
|
import { log } from '../../../../../logger.js';
|
||||||
import { ITextDimensionCalculator } from '../../TextDimensionCalculator.js';
|
import { TextDimensionCalculator } from '../../TextDimensionCalculator.js';
|
||||||
import { BaseAxis } from './BaseAxis.js';
|
import { BaseAxis } from './BaseAxis.js';
|
||||||
import { XYChartAxisThemeConfig, XYChartAxisConfig } from '../../Interfaces.js';
|
import { XYChartAxisThemeConfig, XYChartAxisConfig } from '../../Interfaces.js';
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ export class LinearAxis extends BaseAxis {
|
|||||||
axisThemeConfig: XYChartAxisThemeConfig,
|
axisThemeConfig: XYChartAxisThemeConfig,
|
||||||
domain: [number, number],
|
domain: [number, number],
|
||||||
title: string,
|
title: string,
|
||||||
textDimensionCalculator: ITextDimensionCalculator
|
textDimensionCalculator: TextDimensionCalculator
|
||||||
) {
|
) {
|
||||||
super(axisConfig, title, textDimensionCalculator, axisThemeConfig);
|
super(axisConfig, title, textDimensionCalculator, axisThemeConfig);
|
||||||
this.domain = domain;
|
this.domain = domain;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { SVGGType } from '../../../xychartDb.js';
|
||||||
import {
|
import {
|
||||||
AxisDataType,
|
AxisDataType,
|
||||||
ChartComponent,
|
ChartComponent,
|
||||||
@@ -11,7 +12,7 @@ import { LinearAxis } from './LinearAxis.js';
|
|||||||
|
|
||||||
export type AxisPosition = 'left' | 'right' | 'top' | 'bottom';
|
export type AxisPosition = 'left' | 'right' | 'top' | 'bottom';
|
||||||
|
|
||||||
export interface IAxis extends ChartComponent {
|
export interface Axis extends ChartComponent {
|
||||||
getScaleValue(value: string | number): number;
|
getScaleValue(value: string | number): number;
|
||||||
setAxisPosition(axisPosition: AxisPosition): void;
|
setAxisPosition(axisPosition: AxisPosition): void;
|
||||||
getAxisOuterPadding(): number;
|
getAxisOuterPadding(): number;
|
||||||
@@ -24,9 +25,9 @@ export function getAxis(
|
|||||||
data: AxisDataType,
|
data: AxisDataType,
|
||||||
axisConfig: XYChartAxisConfig,
|
axisConfig: XYChartAxisConfig,
|
||||||
axisThemeConfig: XYChartAxisThemeConfig,
|
axisThemeConfig: XYChartAxisThemeConfig,
|
||||||
fontFamily?: string
|
tmpSVGGElem: SVGGType
|
||||||
): IAxis {
|
): Axis {
|
||||||
const textDimansionCalculator = new TextDimensionCalculatorWithFont(fontFamily);
|
const textDimansionCalculator = new TextDimensionCalculatorWithFont(tmpSVGGElem);
|
||||||
if (isBandAxisData(data)) {
|
if (isBandAxisData(data)) {
|
||||||
return new BandAxis(
|
return new BandAxis(
|
||||||
axisConfig,
|
axisConfig,
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { BarPlotData, BoundingRect, DrawableElem, XYChartConfig } from '../../Interfaces.js';
|
import { BarPlotData, BoundingRect, DrawableElem, XYChartConfig } from '../../Interfaces.js';
|
||||||
import { IAxis } from '../axis/index.js';
|
import { Axis } from '../axis/index.js';
|
||||||
|
|
||||||
export class BarPlot {
|
export class BarPlot {
|
||||||
constructor(
|
constructor(
|
||||||
private barData: BarPlotData,
|
private barData: BarPlotData,
|
||||||
private boundingRect: BoundingRect,
|
private boundingRect: BoundingRect,
|
||||||
private xAxis: IAxis,
|
private xAxis: Axis,
|
||||||
private yAxis: IAxis,
|
private yAxis: Axis,
|
||||||
private orientation: XYChartConfig['chartOrientation'],
|
private orientation: XYChartConfig['chartOrientation'],
|
||||||
private plotIndex: number
|
private plotIndex: number
|
||||||
) {}
|
) {}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { line } from 'd3';
|
import { line } from 'd3';
|
||||||
import { DrawableElem, LinePlotData, XYChartConfig } from '../../Interfaces.js';
|
import { DrawableElem, LinePlotData, XYChartConfig } from '../../Interfaces.js';
|
||||||
import { IAxis } from '../axis/index.js';
|
import { Axis } from '../axis/index.js';
|
||||||
|
|
||||||
export class LinePlot {
|
export class LinePlot {
|
||||||
constructor(
|
constructor(
|
||||||
private plotData: LinePlotData,
|
private plotData: LinePlotData,
|
||||||
private xAxis: IAxis,
|
private xAxis: Axis,
|
||||||
private yAxis: IAxis,
|
private yAxis: Axis,
|
||||||
private orientation: XYChartConfig['chartOrientation'],
|
private orientation: XYChartConfig['chartOrientation'],
|
||||||
private plotIndex: number
|
private plotIndex: number
|
||||||
) {}
|
) {}
|
||||||
|
|||||||
@@ -7,20 +7,20 @@ import {
|
|||||||
XYChartThemeConfig,
|
XYChartThemeConfig,
|
||||||
XYChartConfig,
|
XYChartConfig,
|
||||||
} from '../../Interfaces.js';
|
} from '../../Interfaces.js';
|
||||||
import { IAxis } from '../axis/index.js';
|
import { Axis } from '../axis/index.js';
|
||||||
import { ChartComponent } from '../../Interfaces.js';
|
import { ChartComponent } from '../../Interfaces.js';
|
||||||
import { LinePlot } from './LinePlot.js';
|
import { LinePlot } from './LinePlot.js';
|
||||||
import { PlotBorder } from './PlotBorder.js';
|
import { PlotBorder } from './PlotBorder.js';
|
||||||
import { BarPlot } from './BarPlot.js';
|
import { BarPlot } from './BarPlot.js';
|
||||||
|
|
||||||
export interface IPlot extends ChartComponent {
|
export interface Plot extends ChartComponent {
|
||||||
setAxes(xAxis: IAxis, yAxis: IAxis): void;
|
setAxes(xAxis: Axis, yAxis: Axis): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Plot implements IPlot {
|
export class Plot implements Plot {
|
||||||
private boundingRect: BoundingRect;
|
private boundingRect: BoundingRect;
|
||||||
private xAxis?: IAxis;
|
private xAxis?: Axis;
|
||||||
private yAxis?: IAxis;
|
private yAxis?: Axis;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private chartConfig: XYChartConfig,
|
private chartConfig: XYChartConfig,
|
||||||
@@ -34,7 +34,7 @@ export class Plot implements IPlot {
|
|||||||
height: 0,
|
height: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
setAxes(xAxis: IAxis, yAxis: IAxis) {
|
setAxes(xAxis: Axis, yAxis: Axis) {
|
||||||
this.xAxis = xAxis;
|
this.xAxis = xAxis;
|
||||||
this.yAxis = yAxis;
|
this.yAxis = yAxis;
|
||||||
}
|
}
|
||||||
@@ -99,6 +99,6 @@ export function getPlotComponent(
|
|||||||
chartConfig: XYChartConfig,
|
chartConfig: XYChartConfig,
|
||||||
chartData: XYChartData,
|
chartData: XYChartData,
|
||||||
chartThemeConfig: XYChartThemeConfig
|
chartThemeConfig: XYChartThemeConfig
|
||||||
): IPlot {
|
): Plot {
|
||||||
return new Plot(chartConfig, chartData, chartThemeConfig);
|
return new Plot(chartConfig, chartData, chartThemeConfig);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { log } from '../../../logger.js';
|
import { log } from '../../../logger.js';
|
||||||
|
import { SVGGType } from '../xychartDb.js';
|
||||||
import { DrawableElem, XYChartData, XYChartConfig, XYChartThemeConfig } from './Interfaces.js';
|
import { DrawableElem, XYChartData, XYChartConfig, XYChartThemeConfig } from './Interfaces.js';
|
||||||
import { Orchestrator } from './Orchestrator.js';
|
import { Orchestrator } from './Orchestrator.js';
|
||||||
|
|
||||||
@@ -6,12 +7,13 @@ export class XYChartBuilder {
|
|||||||
static build(
|
static build(
|
||||||
config: XYChartConfig,
|
config: XYChartConfig,
|
||||||
chartData: XYChartData,
|
chartData: XYChartData,
|
||||||
chartThemeConfig: XYChartThemeConfig
|
chartThemeConfig: XYChartThemeConfig,
|
||||||
|
tmpSVGGElem: SVGGType
|
||||||
): DrawableElem[] {
|
): DrawableElem[] {
|
||||||
log.trace(`Build start with Config: ${JSON.stringify(config, null, 2)}`);
|
log.trace(`Build start with Config: ${JSON.stringify(config, null, 2)}`);
|
||||||
log.trace(`Build start with ChartData: ${JSON.stringify(chartData, null, 2)}`);
|
log.trace(`Build start with ChartData: ${JSON.stringify(chartData, null, 2)}`);
|
||||||
log.trace(`Build start with ChartThemeConfig: ${JSON.stringify(chartThemeConfig, null, 2)}`);
|
log.trace(`Build start with ChartThemeConfig: ${JSON.stringify(chartThemeConfig, null, 2)}`);
|
||||||
const orchestrator = new Orchestrator(config, chartData, chartThemeConfig);
|
const orchestrator = new Orchestrator(config, chartData, chartThemeConfig, tmpSVGGElem);
|
||||||
return orchestrator.getDrawableElement();
|
return orchestrator.getDrawableElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,9 @@
|
|||||||
%s data
|
%s data
|
||||||
%s data_inner
|
%s data_inner
|
||||||
%%
|
%%
|
||||||
\%\%\{ { this.begin('open_directive'); return 'open_directive'; }
|
\%\%\{ { this.pushState('open_directive'); return 'open_directive'; }
|
||||||
<open_directive>((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; }
|
<open_directive>((?:(?!\}\%\%)[^:.])*) { this.pushState('type_directive'); return 'type_directive'; }
|
||||||
<type_directive>":" { this.popState(); this.begin('arg_directive'); return ':'; }
|
<type_directive>":" { this.popState(); this.pushState('arg_directive'); return ':'; }
|
||||||
<type_directive,arg_directive>\}\%\% { this.popState(); this.popState(); return 'close_directive'; }
|
<type_directive,arg_directive>\}\%\% { this.popState(); this.popState(); return 'close_directive'; }
|
||||||
<arg_directive>((?:(?!\}\%\%).|\n)*) return 'arg_directive';
|
<arg_directive>((?:(?!\}\%\%).|\n)*) return 'arg_directive';
|
||||||
\%\%(?!\{)[^\n]* /* skip comments */
|
\%\%(?!\{)[^\n]* /* skip comments */
|
||||||
@@ -27,41 +27,39 @@
|
|||||||
[\n\r]+ return 'NEWLINE';
|
[\n\r]+ return 'NEWLINE';
|
||||||
\%\%[^\n]* /* do nothing */
|
\%\%[^\n]* /* do nothing */
|
||||||
|
|
||||||
title { this.begin("title"); return 'title'; }
|
"title" { return 'title'; }
|
||||||
<title>(?!\n|;|#)*[^\n]* { this.popState(); return "title_value"; }
|
|
||||||
|
|
||||||
|
"accTitle"\s*":"\s* { this.pushState("acc_title");return 'acc_title'; }
|
||||||
accTitle\s*":"\s* { this.begin("acc_title");return 'acc_title'; }
|
|
||||||
<acc_title>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_title_value"; }
|
<acc_title>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_title_value"; }
|
||||||
accDescr\s*":"\s* { this.begin("acc_descr");return 'acc_descr'; }
|
"accDescr"\s*":"\s* { this.pushState("acc_descr");return 'acc_descr'; }
|
||||||
<acc_descr>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_descr_value"; }
|
<acc_descr>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_descr_value"; }
|
||||||
accDescr\s*"{"\s* { this.begin("acc_descr_multiline");}
|
"accDescr"\s*"{"\s* { this.pushState("acc_descr_multiline");}
|
||||||
<acc_descr_multiline>[\}] { this.popState(); }
|
<acc_descr_multiline>[\}] { this.popState(); }
|
||||||
<acc_descr_multiline>[^\}]* { return "acc_descr_multiline_value"; }
|
<acc_descr_multiline>[^\}]* { return "acc_descr_multiline_value"; }
|
||||||
|
|
||||||
"xychart-beta" {return 'XYCHART';}
|
"xychart-beta" {return 'XYCHART';}
|
||||||
("vertical"|"horizontal") {return 'CHART_ORIENTATION'}
|
("vertical"|"horizontal") {return 'CHART_ORIENTATION'}
|
||||||
|
|
||||||
"x-axis" { this.begin("axis_data"); return "X_AXIS"; }
|
"x-axis" { this.pushState("axis_data"); return "X_AXIS"; }
|
||||||
"y-axis" { this.begin("axis_data"); return "Y_AXIS"; }
|
"y-axis" { this.pushState("axis_data"); return "Y_AXIS"; }
|
||||||
<axis_data>[\[] { this.popState(); return 'SQUARE_BRACES_START'; }
|
<axis_data>[\[] { this.popState(); return 'SQUARE_BRACES_START'; }
|
||||||
<axis_data>[+-]?\d+(?:\.\d+)? { return 'NUMBER_WITH_DECIMAL'; }
|
<axis_data>[+-]?(?:\d+(?:\.\d+)?|\.\d+) { return 'NUMBER_WITH_DECIMAL'; }
|
||||||
<axis_data>"-->" { return 'ARROW_DELIMITER'; }
|
<axis_data>"-->" { return 'ARROW_DELIMITER'; }
|
||||||
|
|
||||||
|
|
||||||
"line" { this.begin("data"); return 'LINE'; }
|
"line" { this.pushState("data"); return 'LINE'; }
|
||||||
"bar" { this.begin("data"); return 'BAR'; }
|
"bar" { this.pushState("data"); return 'BAR'; }
|
||||||
<data>[\[] { this.popState(); this.begin("data_inner"); return 'SQUARE_BRACES_START'; }
|
<data>[\[] { this.pushState("data_inner"); return 'SQUARE_BRACES_START'; }
|
||||||
<data_inner>[+-]?\d+(?:\.\d+)? { return 'NUMBER_WITH_DECIMAL';}
|
<data_inner>[+-]?(?:\d+(?:\.\d+)?|\.\d+) { return 'NUMBER_WITH_DECIMAL';}
|
||||||
<data_inner>[\]] { this.popState(); return 'SQUARE_BRACES_END'; }
|
<data_inner>[\]] { this.popState(); return 'SQUARE_BRACES_END'; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
["][`] { this.begin("md_string");}
|
["][`] { this.pushState("md_string");}
|
||||||
<md_string>[^`"]+ { return "MD_STR";}
|
<md_string>[^`"]+ { return "MD_STR";}
|
||||||
<md_string>[`]["] { this.popState();}
|
<md_string>[`]["] { this.popState();}
|
||||||
["] this.begin("string");
|
["] this.pushState("string");
|
||||||
<string>["] this.popState();
|
<string>["] this.popState();
|
||||||
<string>[^"]* return "STR";
|
<string>[^"]* return "STR";
|
||||||
|
|
||||||
@@ -72,7 +70,6 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multiline");}
|
|||||||
":" return 'COLON';
|
":" return 'COLON';
|
||||||
\+ return 'PLUS';
|
\+ return 'PLUS';
|
||||||
"," return 'COMMA';
|
"," return 'COMMA';
|
||||||
"=" return 'EQUALS';
|
|
||||||
\= return 'EQUALS';
|
\= return 'EQUALS';
|
||||||
"*" return 'MULT';
|
"*" return 'MULT';
|
||||||
\# return 'BRKT';
|
\# return 'BRKT';
|
||||||
@@ -81,9 +78,8 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multiline");}
|
|||||||
"&" return 'AMP';
|
"&" return 'AMP';
|
||||||
\- return 'MINUS';
|
\- return 'MINUS';
|
||||||
[0-9]+ return 'NUM';
|
[0-9]+ return 'NUM';
|
||||||
\s /* skip */
|
\s+ /* skip */
|
||||||
";" return 'SEMI';
|
";" return 'SEMI';
|
||||||
[!"#$%&'*+,-.`?\\_/] return 'PUNCTUATION';
|
|
||||||
<<EOF>> return 'EOF';
|
<<EOF>> return 'EOF';
|
||||||
|
|
||||||
/lex
|
/lex
|
||||||
@@ -109,48 +105,66 @@ document
|
|||||||
| document statement
|
| document statement
|
||||||
;
|
;
|
||||||
|
|
||||||
line
|
|
||||||
: statement
|
|
||||||
;
|
|
||||||
|
|
||||||
statement
|
statement
|
||||||
: statement eol
|
: statement eol
|
||||||
| title title_value { yy.setDiagramTitle($title_value.trim()); }
|
| title text { yy.setDiagramTitle($text.text.trim()); }
|
||||||
| X_AXIS parseXAxis
|
| X_AXIS parseXAxis
|
||||||
| Y_AXIS parseYAxis
|
| Y_AXIS parseYAxis
|
||||||
| LINE parseLineData { yy.setLineData({text: '', type: 'text'}, $parseLineData); }
|
| LINE plotData { yy.setLineData({text: '', type: 'text'}, $plotData); }
|
||||||
| LINE text parseLineData { yy.setLineData($text, $parseLineData); }
|
| LINE text plotData { yy.setLineData($text, $plotData); }
|
||||||
| BAR parseBarData { yy.setBarData({text: '', type: 'text'}, $parseBarData); }
|
| BAR plotData { yy.setBarData({text: '', type: 'text'}, $plotData); }
|
||||||
| BAR text parseBarData { yy.setBarData($text, $parseBarData); }
|
| BAR text plotData { yy.setBarData($text, $plotData); }
|
||||||
;
|
;
|
||||||
|
|
||||||
parseLineData
|
plotData
|
||||||
: SQUARE_BRACES_START NUMBER_WITH_DECIMAL parseLineData {$parseLineData.unshift(Number($NUMBER_WITH_DECIMAL)); $$ = $parseLineData}
|
: SQUARE_BRACES_START commaSeperateNumber SQUARE_BRACES_END { $$ = $commaSeperateNumber }
|
||||||
| COMMA NUMBER_WITH_DECIMAL parseLineData {$parseLineData.unshift(Number($NUMBER_WITH_DECIMAL)); $$ = $parseLineData;}
|
|
||||||
| SQUARE_BRACES_END {$$ = []}
|
|
||||||
;
|
;
|
||||||
|
|
||||||
parseBarData
|
commaSeperateNumber
|
||||||
: SQUARE_BRACES_START NUMBER_WITH_DECIMAL parseBarData {$parseBarData.unshift(Number($NUMBER_WITH_DECIMAL)); $$ = $parseBarData}
|
: NUMBER_WITH_DECIMAL commaSeperateNumberValues {
|
||||||
| COMMA NUMBER_WITH_DECIMAL parseBarData {$parseBarData.unshift(Number($NUMBER_WITH_DECIMAL)); $$ = $parseBarData;}
|
$commaSeperateNumberValues = $commaSeperateNumberValues || [];
|
||||||
| SQUARE_BRACES_END {$$ = []}
|
$commaSeperateNumberValues.unshift(Number($NUMBER_WITH_DECIMAL));
|
||||||
|
$$ = $commaSeperateNumberValues
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
commaSeperateNumberValues
|
||||||
|
: COMMA NUMBER_WITH_DECIMAL commaSeperateNumberValues {
|
||||||
|
$commaSeperateNumberValues = $commaSeperateNumberValues || [];
|
||||||
|
$commaSeperateNumberValues.unshift(Number($NUMBER_WITH_DECIMAL));
|
||||||
|
$$ = $commaSeperateNumberValues
|
||||||
|
}
|
||||||
|
|;
|
||||||
|
|
||||||
parseXAxis
|
parseXAxis
|
||||||
: text {yy.setXAxisTitle($text);}
|
: text {yy.setXAxisTitle($text);}
|
||||||
| text xAxisBandData {yy.setXAxisTitle($text); yy.setXAxisBand($xAxisBandData);}
|
| text bandData {yy.setXAxisTitle($text); yy.setXAxisBand($bandData);}
|
||||||
| text NUMBER_WITH_DECIMAL ARROW_DELIMITER NUMBER_WITH_DECIMAL {yy.setXAxisTitle($text); yy.setXAxisRangeData(Number($2), Number($4));}
|
| text NUMBER_WITH_DECIMAL ARROW_DELIMITER NUMBER_WITH_DECIMAL {yy.setXAxisTitle($text); yy.setXAxisRangeData(Number($NUMBER_WITH_DECIMAL1), Number($NUMBER_WITH_DECIMAL2));}
|
||||||
;
|
;
|
||||||
|
|
||||||
xAxisBandData
|
bandData
|
||||||
: SQUARE_BRACES_START text xAxisBandData {$xAxisBandData.unshift($text); $$ = $xAxisBandData}
|
: SQUARE_BRACES_START commaSeperateText SQUARE_BRACES_END {$$ = $commaSeperateText}
|
||||||
| COMMA text xAxisBandData {$xAxisBandData.unshift($text); $$ = $xAxisBandData;}
|
|
||||||
| SQUARE_BRACES_END {$$ = []}
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
commaSeperateText
|
||||||
|
: text commaSeperateTextValues {
|
||||||
|
$commaSeperateTextValues = $commaSeperateTextValues || [];
|
||||||
|
$commaSeperateTextValues.unshift($text);
|
||||||
|
$$ = $commaSeperateTextValues
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
commaSeperateTextValues
|
||||||
|
: COMMA text commaSeperateTextValues {
|
||||||
|
$commaSeperateTextValues = $commaSeperateTextValues || [];
|
||||||
|
$commaSeperateTextValues.unshift($text);
|
||||||
|
$$ = $commaSeperateTextValues
|
||||||
|
}
|
||||||
|
|;
|
||||||
|
|
||||||
parseYAxis
|
parseYAxis
|
||||||
: text {yy.setYAxisTitle($text);}
|
: text {yy.setYAxisTitle($text);}
|
||||||
| text NUMBER_WITH_DECIMAL ARROW_DELIMITER NUMBER_WITH_DECIMAL {yy.setYAxisTitle($text); yy.setYAxisRangeData(Number($2), Number($4));}
|
| text NUMBER_WITH_DECIMAL ARROW_DELIMITER NUMBER_WITH_DECIMAL {yy.setYAxisTitle($text); yy.setYAxisRangeData(Number($NUMBER_WITH_DECIMAL1), Number($NUMBER_WITH_DECIMAL2));}
|
||||||
;
|
;
|
||||||
|
|
||||||
directive
|
directive
|
||||||
@@ -180,22 +194,17 @@ closeDirective
|
|||||||
: close_directive { yy.parseDirective('}%%', 'close_directive', 'xychart'); }
|
: close_directive { yy.parseDirective('}%%', 'close_directive', 'xychart'); }
|
||||||
;
|
;
|
||||||
|
|
||||||
text: alphaNum
|
text: alphaNum { $$={text:$alphaNum, type: 'text'};}
|
||||||
{ $$={text:$alphaNum, type: 'text'};}
|
| STR { $$={text: $STR, type: 'text'};}
|
||||||
| STR
|
| MD_STR { $$={text: $MD_STR, type: 'markdown'};}
|
||||||
{ $$={text: $STR, type: 'text'};}
|
|
||||||
| MD_STR
|
|
||||||
{ $$={text: $MD_STR, type: 'markdown'};}
|
|
||||||
;
|
;
|
||||||
|
|
||||||
alphaNum
|
alphaNum
|
||||||
: alphaNumToken
|
: alphaNumToken {$$=$alphaNumToken;}
|
||||||
{$$=$alphaNumToken;}
|
| alphaNum alphaNumToken {$$=$alphaNum+''+$alphaNumToken;}
|
||||||
| alphaNum alphaNumToken
|
|
||||||
{$$=$alphaNum+''+$alphaNumToken;}
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
alphaNumToken : PUNCTUATION | AMP | NUM | ALPHA | PLUS | EQUALS | MULT | DOT | BRKT| UNDERSCORE ;
|
alphaNumToken : AMP | NUM | ALPHA | PLUS | EQUALS | MULT | DOT | BRKT| MINUS | UNDERSCORE ;
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|||||||
@@ -43,11 +43,16 @@ describe('Testing xychart jison file', () => {
|
|||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parse title of the chart', () => {
|
it('parse title of the chart within "', () => {
|
||||||
const str = 'xychart-beta \n title This is a title';
|
const str = 'xychart-beta \n title "This is a title"';
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setDiagramTitle).toHaveBeenCalledWith('This is a title');
|
expect(mockDB.setDiagramTitle).toHaveBeenCalledWith('This is a title');
|
||||||
});
|
});
|
||||||
|
it('parse title of the chart without "', () => {
|
||||||
|
const str = 'xychart-beta \n title oneLinertitle';
|
||||||
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
|
expect(mockDB.setDiagramTitle).toHaveBeenCalledWith('oneLinertitle');
|
||||||
|
});
|
||||||
|
|
||||||
it('should be able to parse directive', () => {
|
it('should be able to parse directive', () => {
|
||||||
const str =
|
const str =
|
||||||
@@ -63,13 +68,13 @@ describe('Testing xychart jison file', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('parse chart orientation', () => {
|
it('parse chart orientation', () => {
|
||||||
let str = 'xychart-beta vertical';
|
const str = 'xychart-beta vertical';
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setOrientation).toHaveBeenCalledWith('vertical');
|
expect(mockDB.setOrientation).toHaveBeenCalledWith('vertical');
|
||||||
|
});
|
||||||
|
|
||||||
clearMocks();
|
it('parse chart orientation with spaces', () => {
|
||||||
|
let str = 'xychart-beta horizontal ';
|
||||||
str = 'xychart-beta horizontal ';
|
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setOrientation).toHaveBeenCalledWith('horizontal');
|
expect(mockDB.setOrientation).toHaveBeenCalledWith('horizontal');
|
||||||
|
|
||||||
@@ -78,52 +83,66 @@ describe('Testing xychart jison file', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('parse x-axis', () => {
|
it('parse x-axis', () => {
|
||||||
let str = 'xychart-beta \nx-axis xAxisName\n';
|
const str = 'xychart-beta \nx-axis xAxisName\n';
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||||
text: 'xAxisName',
|
text: 'xAxisName',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
clearMocks();
|
it('parse x-axis with axis name without "', () => {
|
||||||
|
const str = 'xychart-beta \nx-axis xAxisName \n';
|
||||||
str = 'xychart-beta \nx-axis xAxisName \n';
|
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||||
text: 'xAxisName',
|
text: 'xAxisName',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
clearMocks();
|
it('parse x-axis with axis name with "', () => {
|
||||||
|
const str = 'xychart-beta \n x-axis "xAxisName has space"\n';
|
||||||
str = 'xychart-beta \n x-axis "xAxisName has space"\n';
|
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||||
text: 'xAxisName has space',
|
text: 'xAxisName has space',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
clearMocks();
|
it('parse x-axis with axis name with " with spaces', () => {
|
||||||
|
const str = 'xychart-beta \n x-axis " xAxisName has space " \n';
|
||||||
str = 'xychart-beta \n x-axis " xAxisName has space " \n';
|
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||||
text: ' xAxisName has space ',
|
text: ' xAxisName has space ',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
clearMocks();
|
it('parse x-axis with axis name and range data', () => {
|
||||||
str = 'xychart-beta \nx-axis xAxisName 45.5 --> 33 \n';
|
const str = 'xychart-beta \nx-axis xAxisName 45.5 --> 33 \n';
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||||
text: 'xAxisName',
|
text: 'xAxisName',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
});
|
});
|
||||||
expect(mockDB.setXAxisRangeData).toHaveBeenCalledWith(45.5, 33);
|
expect(mockDB.setXAxisRangeData).toHaveBeenCalledWith(45.5, 33);
|
||||||
|
});
|
||||||
|
it('parse x-axis throw error for invalid range data', () => {
|
||||||
|
const str = 'xychart-beta \nx-axis xAxisName aaa --> 33 \n';
|
||||||
|
expect(parserFnConstructor(str)).toThrow();
|
||||||
|
});
|
||||||
|
it('parse x-axis with axis name and range data with only decimal part', () => {
|
||||||
|
const str = 'xychart-beta \nx-axis xAxisName 45.5 --> .34 \n';
|
||||||
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
|
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||||
|
text: 'xAxisName',
|
||||||
|
type: 'text',
|
||||||
|
});
|
||||||
|
expect(mockDB.setXAxisRangeData).toHaveBeenCalledWith(45.5, 0.34);
|
||||||
|
});
|
||||||
|
|
||||||
clearMocks();
|
it('parse x-axis with axis name and category data', () => {
|
||||||
|
const str = 'xychart-beta \nx-axis xAxisName [ "cat1" , cat2a ] \n ';
|
||||||
str = 'xychart-beta \nx-axis xAxisName [ "cat1" , cat2a ] \n ';
|
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
||||||
text: 'xAxisName',
|
text: 'xAxisName',
|
||||||
@@ -136,9 +155,17 @@ describe('Testing xychart jison file', () => {
|
|||||||
},
|
},
|
||||||
{ text: 'cat2a', type: 'text' },
|
{ text: 'cat2a', type: 'text' },
|
||||||
]);
|
]);
|
||||||
clearMocks();
|
});
|
||||||
|
|
||||||
str = `xychart-beta \n x-axis "this is x axis" [category1, "category 2", category3]\n`;
|
it('parse x-axis throw error if unbalanced bracket', () => {
|
||||||
|
let str = 'xychart-beta \nx-axis xAxisName [ "cat1" [ cat2a ] \n ';
|
||||||
|
expect(parserFnConstructor(str)).toThrow();
|
||||||
|
str = 'xychart-beta \nx-axis xAxisName [ "cat1" , cat2a ] ] \n ';
|
||||||
|
expect(parserFnConstructor(str)).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('parse x-axis complete variant 1', () => {
|
||||||
|
const str = `xychart-beta \n x-axis "this is x axis" [category1, "category 2", category3]\n`;
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'this is x axis', type: 'text' });
|
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'this is x axis', type: 'text' });
|
||||||
expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
|
expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
|
||||||
@@ -146,9 +173,11 @@ describe('Testing xychart jison file', () => {
|
|||||||
{ text: 'category 2', type: 'text' },
|
{ text: 'category 2', type: 'text' },
|
||||||
{ text: 'category3', type: 'text' },
|
{ text: 'category3', type: 'text' },
|
||||||
]);
|
]);
|
||||||
clearMocks();
|
});
|
||||||
|
|
||||||
str = 'xychart-beta \nx-axis xAxisName [ "cat1 with space" , cat2 , cat3] \n ';
|
it('parse x-axis complete variant 2', () => {
|
||||||
|
const str =
|
||||||
|
'xychart-beta \nx-axis xAxisName [ "cat1 with space" , cat2 , cat3] \n ';
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||||
expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
|
expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
|
||||||
@@ -156,9 +185,11 @@ describe('Testing xychart jison file', () => {
|
|||||||
{ text: 'cat2', type: 'text' },
|
{ text: 'cat2', type: 'text' },
|
||||||
{ text: 'cat3', type: 'text' },
|
{ text: 'cat3', type: 'text' },
|
||||||
]);
|
]);
|
||||||
clearMocks();
|
});
|
||||||
|
|
||||||
str = 'xychart-beta \nx-axis xAxisName [ "cat1 with space" , cat2 asdf , cat3] \n ';
|
it('parse x-axis complete variant 3', () => {
|
||||||
|
const str =
|
||||||
|
'xychart-beta \nx-axis xAxisName [ "cat1 with space" , cat2 asdf , cat3] \n ';
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||||
expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
|
expect(mockDB.setXAxisBand).toHaveBeenCalledWith([
|
||||||
@@ -167,77 +198,61 @@ describe('Testing xychart jison file', () => {
|
|||||||
{ text: 'cat3', type: 'text' },
|
{ text: 'cat3', type: 'text' },
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
it('parse y-axis', () => {
|
|
||||||
let str = 'xychart-beta \ny-axis yAxisName\n';
|
it('parse y-axis with axis name', () => {
|
||||||
|
const str = 'xychart-beta \ny-axis yAxisName\n';
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||||
|
});
|
||||||
clearMocks();
|
it('parse y-axis with axis name with spaces', () => {
|
||||||
|
const str = 'xychart-beta \ny-axis yAxisName \n';
|
||||||
str = 'xychart-beta \ny-axis yAxisName \n';
|
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||||
|
});
|
||||||
clearMocks();
|
it('parse y-axis with axis name with "', () => {
|
||||||
|
const str = 'xychart-beta \n y-axis "yAxisName has space"\n';
|
||||||
str = 'xychart-beta \n y-axis "yAxisName has space"\n';
|
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({
|
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({
|
||||||
text: 'yAxisName has space',
|
text: 'yAxisName has space',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
});
|
});
|
||||||
|
});
|
||||||
clearMocks();
|
it('parse y-axis with axis name with " and spaces', () => {
|
||||||
|
const str = 'xychart-beta \n y-axis " yAxisName has space " \n';
|
||||||
str = 'xychart-beta \n y-axis " yAxisName has space " \n';
|
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({
|
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({
|
||||||
text: ' yAxisName has space ',
|
text: ' yAxisName has space ',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
});
|
});
|
||||||
|
});
|
||||||
clearMocks();
|
it('parse y-axis with axis name with range data', () => {
|
||||||
str = 'xychart-beta \ny-axis yAxisName 45.5 --> 33 \n';
|
const str = 'xychart-beta \ny-axis yAxisName 45.5 --> 33 \n';
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||||
expect(mockDB.setYAxisRangeData).toHaveBeenCalledWith(45.5, 33);
|
expect(mockDB.setYAxisRangeData).toHaveBeenCalledWith(45.5, 33);
|
||||||
|
});
|
||||||
clearMocks();
|
it('parse y-axis with axis name with range data with only decimal part', () => {
|
||||||
|
const str = 'xychart-beta \ny-axis yAxisName 45.5 --> .33 \n';
|
||||||
str = 'xychart-beta \ny-axis yAxisName [ 45.3, 33 ] \n';
|
|
||||||
expect(parserFnConstructor(str)).toThrow();
|
|
||||||
|
|
||||||
clearMocks();
|
|
||||||
|
|
||||||
str = 'xychart-beta \ny-axis yAxisName\n';
|
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||||
|
expect(mockDB.setYAxisRangeData).toHaveBeenCalledWith(45.5, 0.33);
|
||||||
});
|
});
|
||||||
it('parse both axis', () => {
|
it('parse y-axis throw error for invalid number in range data', () => {
|
||||||
let str = 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n';
|
const str = 'xychart-beta \ny-axis yAxisName 45.5 --> abc \n';
|
||||||
|
expect(parserFnConstructor(str)).toThrow();
|
||||||
|
});
|
||||||
|
it('parse y-axis throws error if range data is passed', () => {
|
||||||
|
const str = 'xychart-beta \ny-axis yAxisName [ 45.3, 33 ] \n';
|
||||||
|
expect(parserFnConstructor(str)).toThrow();
|
||||||
|
});
|
||||||
|
it('parse both axis at once', () => {
|
||||||
|
const str = 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n';
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||||
|
|
||||||
clearMocks();
|
|
||||||
|
|
||||||
str = 'xychart-beta \nx-axis xAxisName\n';
|
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
|
||||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({
|
|
||||||
text: 'xAxisName',
|
|
||||||
type: 'text',
|
|
||||||
});
|
|
||||||
|
|
||||||
clearMocks();
|
|
||||||
|
|
||||||
str = 'xychart-beta \ny-axis yAxisName';
|
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
|
||||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
|
||||||
|
|
||||||
clearMocks();
|
|
||||||
});
|
});
|
||||||
it('parse line Data', () => {
|
it('parse line Data', () => {
|
||||||
let str = 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line lineTitle [23, 45, 56.6]';
|
const str = 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line lineTitle [23, 45, 56.6]';
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setLineData).toHaveBeenCalledWith(
|
expect(mockDB.setLineData).toHaveBeenCalledWith(
|
||||||
{ text: 'lineTitle', type: 'text' },
|
{ text: 'lineTitle', type: 'text' },
|
||||||
@@ -245,10 +260,9 @@ describe('Testing xychart jison file', () => {
|
|||||||
);
|
);
|
||||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||||
|
});
|
||||||
clearMocks();
|
it('parse line Data with spaces and +,- symbols', () => {
|
||||||
|
const str =
|
||||||
str =
|
|
||||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , -45 , 56.6 ] ';
|
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , -45 , 56.6 ] ';
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||||
@@ -257,32 +271,58 @@ describe('Testing xychart jison file', () => {
|
|||||||
{ text: 'lineTitle with space', type: 'text' },
|
{ text: 'lineTitle with space', type: 'text' },
|
||||||
[23, -45, 56.6]
|
[23, -45, 56.6]
|
||||||
);
|
);
|
||||||
|
});
|
||||||
// set line data without title
|
it('parse line Data without title', () => {
|
||||||
str = 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line [ +23 , -45 , 56.6 ] ';
|
const str =
|
||||||
|
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line [ +23 , -45 , 56.6 , .33] ';
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||||
expect(mockDB.setLineData).toHaveBeenCalledWith({ text: '', type: 'text' }, [23, -45, 56.6]);
|
expect(mockDB.setLineData).toHaveBeenCalledWith(
|
||||||
|
{ text: '', type: 'text' },
|
||||||
clearMocks();
|
[23, -45, 56.6, 0.33]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('parse line Data throws error unbalanced brackets', () => {
|
||||||
|
let str =
|
||||||
|
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 [ -45 , 56.6 ] ';
|
||||||
|
expect(parserFnConstructor(str)).toThrow();
|
||||||
str =
|
str =
|
||||||
|
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , -45 ] 56.6 ] ';
|
||||||
|
expect(parserFnConstructor(str)).toThrow();
|
||||||
|
});
|
||||||
|
it('parse line Data throws error if data is not provided', () => {
|
||||||
|
const str = 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" ';
|
||||||
|
expect(parserFnConstructor(str)).toThrow();
|
||||||
|
});
|
||||||
|
it('parse line Data throws error if data is empty', () => {
|
||||||
|
const str =
|
||||||
|
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ ] ';
|
||||||
|
expect(parserFnConstructor(str)).toThrow();
|
||||||
|
});
|
||||||
|
it('parse line Data throws error if , is not in proper', () => {
|
||||||
|
const str =
|
||||||
|
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , , -45 , 56.6 ] ';
|
||||||
|
expect(parserFnConstructor(str)).toThrow();
|
||||||
|
});
|
||||||
|
it('parse line Data throws error if not number', () => {
|
||||||
|
const str =
|
||||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , -4aa5 , 56.6 ] ';
|
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , -4aa5 , 56.6 ] ';
|
||||||
expect(parserFnConstructor(str)).toThrow();
|
expect(parserFnConstructor(str)).toThrow();
|
||||||
});
|
});
|
||||||
it('parse bar Data', () => {
|
it('parse bar Data', () => {
|
||||||
let str = 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar barTitle [23, 45, 56.6]';
|
const str =
|
||||||
|
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar barTitle [23, 45, 56.6, .22]';
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||||
expect(mockDB.setBarData).toHaveBeenCalledWith(
|
expect(mockDB.setBarData).toHaveBeenCalledWith(
|
||||||
{ text: 'barTitle', type: 'text' },
|
{ text: 'barTitle', type: 'text' },
|
||||||
[23, 45, 56.6]
|
[23, 45, 56.6, 0.22]
|
||||||
);
|
);
|
||||||
|
});
|
||||||
clearMocks();
|
it('parse bar Data spaces and +,- symbol', () => {
|
||||||
|
const str =
|
||||||
str =
|
|
||||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 , -45 , 56.6 ] ';
|
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 , -45 , 56.6 ] ';
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||||
@@ -291,22 +331,45 @@ describe('Testing xychart jison file', () => {
|
|||||||
{ text: 'barTitle with space', type: 'text' },
|
{ text: 'barTitle with space', type: 'text' },
|
||||||
[23, -45, 56.6]
|
[23, -45, 56.6]
|
||||||
);
|
);
|
||||||
clearMocks();
|
});
|
||||||
|
it('parse bar Data without plot title', () => {
|
||||||
// set bar data without title
|
const str =
|
||||||
str = 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar [ +23 , -45 , 56.6 ] ';
|
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar [ +23 , -45 , 56.6 ] ';
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||||
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
expect(mockDB.setXAxisTitle).toHaveBeenCalledWith({ text: 'xAxisName', type: 'text' });
|
||||||
expect(mockDB.setBarData).toHaveBeenCalledWith({ text: '', type: 'text' }, [23, -45, 56.6]);
|
expect(mockDB.setBarData).toHaveBeenCalledWith({ text: '', type: 'text' }, [23, -45, 56.6]);
|
||||||
clearMocks();
|
clearMocks();
|
||||||
|
});
|
||||||
|
it('parse bar should throw for unbalanced brackets', () => {
|
||||||
|
let str =
|
||||||
|
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 [ -45 , 56.6 ] ';
|
||||||
|
expect(parserFnConstructor(str)).toThrow();
|
||||||
str =
|
str =
|
||||||
|
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 , -45 ] 56.6 ] ';
|
||||||
|
expect(parserFnConstructor(str)).toThrow();
|
||||||
|
});
|
||||||
|
it('parse bar should throw error if data is not provided', () => {
|
||||||
|
const str = 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" ';
|
||||||
|
expect(parserFnConstructor(str)).toThrow();
|
||||||
|
});
|
||||||
|
it('parse bar should throw error if data is empty', () => {
|
||||||
|
const str =
|
||||||
|
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ ] ';
|
||||||
|
expect(parserFnConstructor(str)).toThrow();
|
||||||
|
});
|
||||||
|
it('parse bar should throw error if comma is not proper', () => {
|
||||||
|
const str =
|
||||||
|
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 , , -45 , 56.6 ] ';
|
||||||
|
expect(parserFnConstructor(str)).toThrow();
|
||||||
|
});
|
||||||
|
it('parse bar should throw error if number is not passed', () => {
|
||||||
|
const str =
|
||||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 , -4aa5 , 56.6 ] ';
|
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 , -4aa5 , 56.6 ] ';
|
||||||
expect(parserFnConstructor(str)).toThrow();
|
expect(parserFnConstructor(str)).toThrow();
|
||||||
});
|
});
|
||||||
it('parse multiple bar and line', () => {
|
it('parse multiple bar and line varient 1', () => {
|
||||||
let str =
|
const str =
|
||||||
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar barTitle1 [23, 45, 56.6] \n line lineTitle1 [11, 45.5, 67, 23] \n bar barTitle2 [13, 42, 56.89] \n line lineTitle2 [45, 99, 012]';
|
'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar barTitle1 [23, 45, 56.6] \n line lineTitle1 [11, 45.5, 67, 23] \n bar barTitle2 [13, 42, 56.89] \n line lineTitle2 [45, 99, 012]';
|
||||||
expect(parserFnConstructor(str)).not.toThrow();
|
expect(parserFnConstructor(str)).not.toThrow();
|
||||||
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
expect(mockDB.setYAxisTitle).toHaveBeenCalledWith({ text: 'yAxisName', type: 'text' });
|
||||||
@@ -327,9 +390,9 @@ describe('Testing xychart jison file', () => {
|
|||||||
{ text: 'lineTitle2', type: 'text' },
|
{ text: 'lineTitle2', type: 'text' },
|
||||||
[45, 99, 12]
|
[45, 99, 12]
|
||||||
);
|
);
|
||||||
clearMocks();
|
});
|
||||||
|
it('parse multiple bar and line varient 2', () => {
|
||||||
str = `
|
const str = `
|
||||||
xychart-beta horizontal
|
xychart-beta horizontal
|
||||||
title Basic xychart
|
title Basic xychart
|
||||||
x-axis "this is x axis" [category1, "category 2", category3]
|
x-axis "this is x axis" [category1, "category 2", category3]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// @ts-ignore: TODO Fix ts errors
|
// @ts-ignore: TODO Fix ts errors
|
||||||
import { adjust, channel } from 'khroma';
|
import { adjust, channel } from 'khroma';
|
||||||
|
import { Selection } from 'd3-selection';
|
||||||
import mermaidAPI from '../../mermaidAPI.js';
|
import mermaidAPI from '../../mermaidAPI.js';
|
||||||
import * as configApi from '../../config.js';
|
import * as configApi from '../../config.js';
|
||||||
import defaultConfig from '../../defaultConfig.js';
|
import defaultConfig from '../../defaultConfig.js';
|
||||||
@@ -25,12 +26,30 @@ import {
|
|||||||
} from './chartBuilder/Interfaces.js';
|
} from './chartBuilder/Interfaces.js';
|
||||||
import { getThemeVariables } from '../../themes/theme-default.js';
|
import { getThemeVariables } from '../../themes/theme-default.js';
|
||||||
|
|
||||||
|
export type SVGGType = Selection<SVGGElement, unknown, HTMLElement, any>;
|
||||||
|
|
||||||
const defaultThemeVariables = getThemeVariables();
|
const defaultThemeVariables = getThemeVariables();
|
||||||
|
|
||||||
const config = configApi.getConfig();
|
const config = configApi.getConfig();
|
||||||
|
|
||||||
let plotIndex = 0;
|
let plotIndex = 0;
|
||||||
|
|
||||||
|
let tmpSVGGElem: SVGGType;
|
||||||
|
|
||||||
|
let xyChartConfig: XYChartConfig = getChartDefaultConfig();
|
||||||
|
let xyChartThemeConfig: XYChartThemeConfig = getChartDefaultThemeConfig();
|
||||||
|
let xyChartData: XYChartData = getChartDefalutData();
|
||||||
|
let plotColorPalette = Array.isArray(xyChartThemeConfig.plotBaseColor)
|
||||||
|
? xyChartThemeConfig.plotBaseColor
|
||||||
|
: plotColorPaletteGenerator(xyChartThemeConfig.plotBaseColor);
|
||||||
|
let hasSetXAxis = false;
|
||||||
|
let hasSetYAxis = false;
|
||||||
|
|
||||||
|
interface NormalTextType {
|
||||||
|
type: 'text';
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
function plotColorPaletteGenerator(baseColor: string, noOfColorNeeded = 15): string[] {
|
function plotColorPaletteGenerator(baseColor: string, noOfColorNeeded = 15): string[] {
|
||||||
const colors = [];
|
const colors = [];
|
||||||
const MAX_HUE_VALUE = 360;
|
const MAX_HUE_VALUE = 360;
|
||||||
@@ -110,20 +129,6 @@ function getChartDefalutData(): XYChartData {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let xyChartConfig: XYChartConfig = getChartDefaultConfig();
|
|
||||||
let xyChartThemeConfig: XYChartThemeConfig = getChartDefaultThemeConfig();
|
|
||||||
let xyChartData: XYChartData = getChartDefalutData();
|
|
||||||
let plotColorPalette = Array.isArray(xyChartThemeConfig.plotBaseColor)
|
|
||||||
? xyChartThemeConfig.plotBaseColor
|
|
||||||
: plotColorPaletteGenerator(xyChartThemeConfig.plotBaseColor);
|
|
||||||
let hasSetXAxis = false;
|
|
||||||
let hasSetYAxis = false;
|
|
||||||
|
|
||||||
interface NormalTextType {
|
|
||||||
type: 'text';
|
|
||||||
text: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function textSanitizer(text: string) {
|
function textSanitizer(text: string) {
|
||||||
return sanitizeText(text.trim(), config);
|
return sanitizeText(text.trim(), config);
|
||||||
}
|
}
|
||||||
@@ -133,6 +138,9 @@ function parseDirective(statement: string, context: string, type: string) {
|
|||||||
mermaidAPI.parseDirective(this, statement, context, type);
|
mermaidAPI.parseDirective(this, statement, context, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setTmpSVGG(SVGG: SVGGType) {
|
||||||
|
tmpSVGGElem = SVGG;
|
||||||
|
}
|
||||||
function setOrientation(oriantation: string) {
|
function setOrientation(oriantation: string) {
|
||||||
if (oriantation === 'horizontal') {
|
if (oriantation === 'horizontal') {
|
||||||
xyChartConfig.chartOrientation = 'horizontal';
|
xyChartConfig.chartOrientation = 'horizontal';
|
||||||
@@ -177,7 +185,7 @@ function setYAxisRangeFromPlotData(data: number[]) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function transformDataWithOutCategory(data: number[]): SimplePlotDataType {
|
function transformDataWithoutCategory(data: number[]): SimplePlotDataType {
|
||||||
let retData: SimplePlotDataType = [];
|
let retData: SimplePlotDataType = [];
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
return retData;
|
return retData;
|
||||||
@@ -214,7 +222,7 @@ function getPlotColorFromPalette(plotIndex: number): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setLineData(title: NormalTextType, data: number[]) {
|
function setLineData(title: NormalTextType, data: number[]) {
|
||||||
const plotData = transformDataWithOutCategory(data);
|
const plotData = transformDataWithoutCategory(data);
|
||||||
xyChartData.plots.push({
|
xyChartData.plots.push({
|
||||||
type: 'line',
|
type: 'line',
|
||||||
strokeFill: getPlotColorFromPalette(plotIndex),
|
strokeFill: getPlotColorFromPalette(plotIndex),
|
||||||
@@ -225,7 +233,7 @@ function setLineData(title: NormalTextType, data: number[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setBarData(title: NormalTextType, data: number[]) {
|
function setBarData(title: NormalTextType, data: number[]) {
|
||||||
const plotData = transformDataWithOutCategory(data);
|
const plotData = transformDataWithoutCategory(data);
|
||||||
xyChartData.plots.push({
|
xyChartData.plots.push({
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
fill: getPlotColorFromPalette(plotIndex),
|
fill: getPlotColorFromPalette(plotIndex),
|
||||||
@@ -239,7 +247,7 @@ function getDrawableElem(): DrawableElem[] {
|
|||||||
throw Error('No Plot to render, please provide a plot with some data');
|
throw Error('No Plot to render, please provide a plot with some data');
|
||||||
}
|
}
|
||||||
xyChartData.title = getDiagramTitle();
|
xyChartData.title = getDiagramTitle();
|
||||||
return XYChartBuilder.build(xyChartConfig, xyChartData, xyChartThemeConfig);
|
return XYChartBuilder.build(xyChartConfig, xyChartData, xyChartThemeConfig, tmpSVGGElem);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setHeight(height: number) {
|
function setHeight(height: number) {
|
||||||
@@ -283,4 +291,5 @@ export default {
|
|||||||
setYAxisRangeData,
|
setYAxisRangeData,
|
||||||
setLineData,
|
setLineData,
|
||||||
setBarData,
|
setBarData,
|
||||||
|
setTmpSVGG,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,5 +8,4 @@ export const diagram: DiagramDefinition = {
|
|||||||
parser,
|
parser,
|
||||||
db,
|
db,
|
||||||
renderer,
|
renderer,
|
||||||
styles: () => '',
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
TextHorizontalPos,
|
TextHorizontalPos,
|
||||||
TextVerticalPos,
|
TextVerticalPos,
|
||||||
} from './chartBuilder/Interfaces.js';
|
} from './chartBuilder/Interfaces.js';
|
||||||
|
import XYChartDB from './xychartDb.js';
|
||||||
|
|
||||||
export const draw = (txt: string, id: string, _version: string, diagObj: Diagram) => {
|
export const draw = (txt: string, id: string, _version: string, diagObj: Diagram) => {
|
||||||
function getDominantBaseLine(horizontalPos: TextHorizontalPos) {
|
function getDominantBaseLine(horizontalPos: TextHorizontalPos) {
|
||||||
@@ -46,13 +47,13 @@ export const draw = (txt: string, id: string, _version: string, diagObj: Diagram
|
|||||||
|
|
||||||
svg.attr('viewBox', '0 0 ' + width + ' ' + height);
|
svg.attr('viewBox', '0 0 ' + width + ' ' + height);
|
||||||
|
|
||||||
// @ts-ignore: TODO Fix ts errors
|
const db = diagObj.db as typeof XYChartDB;
|
||||||
diagObj.db.setHeight(height);
|
|
||||||
// @ts-ignore: TODO Fix ts errors
|
|
||||||
diagObj.db.setWidth(width);
|
|
||||||
|
|
||||||
// @ts-ignore: TODO Fix ts errors
|
db.setHeight(height);
|
||||||
const shapes: DrawableElem[] = diagObj.db.getDrawableElem();
|
db.setWidth(width);
|
||||||
|
db.setTmpSVGG(svg.append('g').attr('class', 'mermaid-tmp-group'));
|
||||||
|
|
||||||
|
const shapes: DrawableElem[] = db.getDrawableElem();
|
||||||
|
|
||||||
const groups: Record<string, any> = {};
|
const groups: Record<string, any> = {};
|
||||||
|
|
||||||
|
|||||||
@@ -94,6 +94,22 @@ function computeWidthOfText(parentNode, lineHeight, text) {
|
|||||||
return textLength;
|
return textLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the width of rendered text
|
||||||
|
* @param {object} parentNode
|
||||||
|
* @param {number} lineHeight
|
||||||
|
* @param {string} text
|
||||||
|
* @returns {{width: number, height: number}}
|
||||||
|
*/
|
||||||
|
export function computeDimensionOfText(parentNode, lineHeight, text) {
|
||||||
|
const testElement = parentNode.append('text');
|
||||||
|
const testSpan = createTspan(testElement, 1, lineHeight);
|
||||||
|
updateTextContentAndStyles(testSpan, [{ content: text, type: 'normal' }]);
|
||||||
|
const textDimension = testSpan.node().getBoundingClientRect();
|
||||||
|
testElement.remove();
|
||||||
|
return textDimension;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a formatted text element by breaking lines and applying styles based on
|
* Creates a formatted text element by breaking lines and applying styles based on
|
||||||
* the given structuredText.
|
* the given structuredText.
|
||||||
|
|||||||
Reference in New Issue
Block a user