Improved parsing to work for minimal configuration possible.

This commit is contained in:
Subhash Halder
2023-07-05 11:35:57 +05:30
parent 1c8497474a
commit 958f63ecd2
3 changed files with 96 additions and 29 deletions

View File

@@ -39,11 +39,9 @@
<hr /> <hr />
<h1>XY Charts demos</h1> <h1>XY Charts demos</h1>
<pre class="mermaid"> <pre class="mermaid">
xychart-beta horizontal xychart-beta
title Basic xychart
x-axis "this is x axis" [category1, "category 2", category3, category4]
y-axis yaxisText 10 --> 150
line [23, 46, 75, 43] line [23, 46, 75, 43]
bar "sample bat" [52, 96, 35, 10]
</pre> </pre>
<hr /> <hr />

View File

@@ -4,7 +4,7 @@ export interface ChartComponent {
getDrawableElements(): DrawableElem[]; getDrawableElements(): DrawableElem[];
} }
export type SimplePlotDataType = [string | number, number][]; export type SimplePlotDataType = [string, number][];
export interface LinePlotData { export interface LinePlotData {
type: 'line'; type: 'line';
@@ -26,11 +26,13 @@ export function isBarPlot(data: PlotData): data is BarPlotData {
} }
export interface BandAxisDataType { export interface BandAxisDataType {
type: 'band';
title: string; title: string;
categories: string[]; categories: string[];
} }
export interface LinearAxisDataType { export interface LinearAxisDataType {
type: 'linear';
title: string; title: string;
min: number; min: number;
max: number; max: number;
@@ -38,8 +40,12 @@ export interface LinearAxisDataType {
export type AxisDataType = LinearAxisDataType | BandAxisDataType; export type AxisDataType = LinearAxisDataType | BandAxisDataType;
export function isBandAxisData(data: any): data is BandAxisDataType { export function isBandAxisData(data: AxisDataType): data is BandAxisDataType {
return data.categories && Array.isArray(data.categories); return data.type === 'band';
}
export function isLinearAxisData(data: AxisDataType): data is LinearAxisDataType {
return data.type === 'linear';
} }
export interface XYChartData { export interface XYChartData {

View File

@@ -12,7 +12,13 @@ import {
clear as commonClear, clear as commonClear,
} from '../../commonDb.js'; } from '../../commonDb.js';
import { XYChartBuilder } from './chartBuilder/index.js'; import { XYChartBuilder } from './chartBuilder/index.js';
import { DrawableElem, XYChartData, isBandAxisData } from './chartBuilder/Interfaces.js'; import {
DrawableElem,
SimplePlotDataType,
XYChartData,
isBandAxisData,
isLinearAxisData,
} from './chartBuilder/Interfaces.js';
import { XYChartConfig } from '../../config.type.js'; import { XYChartConfig } from '../../config.type.js';
const config = configApi.getConfig(); const config = configApi.getConfig();
@@ -64,12 +70,14 @@ function getChartDefaultConfig(): XYChartConfig {
function getChartDefalutData(): XYChartData { function getChartDefalutData(): XYChartData {
return { return {
yAxis: { yAxis: {
title: 'yAxis1', type: 'linear',
min: 0, title: '',
max: 100, min: Infinity,
max: -Infinity,
}, },
xAxis: { xAxis: {
title: 'xAxis', type: 'band',
title: '',
categories: [], categories: [],
}, },
title: '', title: '',
@@ -79,6 +87,8 @@ function getChartDefalutData(): XYChartData {
let xyChartConfig: XYChartConfig = getChartDefaultConfig(); let xyChartConfig: XYChartConfig = getChartDefaultConfig();
let xyChartData: XYChartData = getChartDefalutData(); let xyChartData: XYChartData = getChartDefalutData();
let hasSetXAxis = false;
let hasSetYAxis = false;
function textSanitizer(text: string) { function textSanitizer(text: string) {
return sanitizeText(text.trim(), config); return sanitizeText(text.trim(), config);
@@ -100,41 +110,92 @@ function setXAxisTitle(title: string) {
xyChartData.xAxis.title = textSanitizer(title); xyChartData.xAxis.title = textSanitizer(title);
} }
function setXAxisRangeData(min: number, max: number) { function setXAxisRangeData(min: number, max: number) {
xyChartData.xAxis = { title: xyChartData.xAxis.title, min, max }; xyChartData.xAxis = { type: 'linear', title: xyChartData.xAxis.title, min, max };
hasSetXAxis = true;
} }
function setXAxisBand(categories: string[]) { function setXAxisBand(categories: string[]) {
xyChartData.xAxis = { xyChartData.xAxis = {
type: 'band',
title: xyChartData.xAxis.title, title: xyChartData.xAxis.title,
categories: categories.map((c) => textSanitizer(c)), categories: categories.map((c) => textSanitizer(c)),
}; };
hasSetXAxis = true;
} }
function setYAxisTitle(title: string) { function setYAxisTitle(title: string) {
xyChartData.yAxis.title = textSanitizer(title); xyChartData.yAxis.title = textSanitizer(title);
} }
function setYAxisRangeData(min: number, max: number) { function setYAxisRangeData(min: number, max: number) {
xyChartData.yAxis = { title: xyChartData.yAxis.title, min, max }; xyChartData.yAxis = { type: 'linear', title: xyChartData.yAxis.title, min, max };
hasSetYAxis = true;
}
// this function does not set `hasSetYAxis` as there can be multiple data so we should calculate the range accordingly
function setYAxisRangeFromPlotData(data: number[]) {
const minValue = Math.min(...data);
const maxValue = Math.max(...data);
const prevMinValue = isLinearAxisData(xyChartData.yAxis) ? xyChartData.yAxis.min : Infinity;
const prevMaxValue = isLinearAxisData(xyChartData.yAxis) ? xyChartData.yAxis.max : -Infinity;
xyChartData.yAxis = {
type: 'linear',
title: xyChartData.yAxis.title,
min: Math.min(prevMinValue, minValue),
max: Math.max(prevMaxValue, maxValue),
};
}
function transformDataWithOutCategory(data: number[]): SimplePlotDataType {
let retData: SimplePlotDataType = [];
if (data.length === 0) {
return retData;
}
if (!hasSetXAxis) {
const prevMinValue = isLinearAxisData(xyChartData.xAxis) ? xyChartData.xAxis.min : Infinity;
const prevMaxValue = isLinearAxisData(xyChartData.xAxis) ? xyChartData.xAxis.max : -Infinity;
setXAxisRangeData(Math.min(prevMinValue, 1), Math.max(prevMaxValue, data.length));
}
if (!hasSetYAxis) {
setYAxisRangeFromPlotData(data);
}
if (isBandAxisData(xyChartData.xAxis)) {
retData = xyChartData.xAxis.categories.map((c, i) => [c, data[i]]);
}
if (isLinearAxisData(xyChartData.xAxis)) {
const min = xyChartData.xAxis.min;
const max = xyChartData.xAxis.max;
const step = (max - min + 1) / data.length;
const categories: string[] = [];
for (let i = min; i <= max; i += step) {
categories.push(`${i}`);
}
retData = categories.map((c, i) => [c, data[i]]);
}
return retData;
} }
function setLineData(title: string, data: number[]) { function setLineData(title: string, data: number[]) {
if (isBandAxisData(xyChartData.xAxis)) { const plotData = transformDataWithOutCategory(data);
xyChartData.plots.push({ xyChartData.plots.push({
type: 'line', type: 'line',
strokeFill: '#00ff00', strokeFill: '#00ff00',
strokeWidth: 2, strokeWidth: 2,
data: xyChartData.xAxis.categories.map((c, i) => [c, data[i]]), data: plotData,
}); });
}
} }
function setBarData(title: string, data: number[]) { function setBarData(title: string, data: number[]) {
if (isBandAxisData(xyChartData.xAxis)) { const plotData = transformDataWithOutCategory(data);
xyChartData.plots.push({ xyChartData.plots.push({
type: 'bar', type: 'bar',
fill: '#0000bb', fill: '#0000bb',
data: xyChartData.xAxis.categories.map((c, i) => [c, data[i]]), data: plotData,
}); });
}
} }
function getDrawableElem(): DrawableElem[] { function getDrawableElem(): DrawableElem[] {
if (xyChartData.plots.length === 0) {
throw Error('No Plot to render, please provide a plot with some data');
}
xyChartData.title = getDiagramTitle(); xyChartData.title = getDiagramTitle();
return XYChartBuilder.build(xyChartConfig, xyChartData); return XYChartBuilder.build(xyChartConfig, xyChartData);
} }
@@ -151,6 +212,8 @@ const clear = function () {
commonClear(); commonClear();
xyChartConfig = getChartDefaultConfig(); xyChartConfig = getChartDefaultConfig();
xyChartData = getChartDefalutData(); xyChartData = getChartDefalutData();
hasSetXAxis = false;
hasSetYAxis = false;
}; };
export default { export default {