Fixed some issue related to rendering and space management

This commit is contained in:
Subhash Halder 2023-07-04 19:55:12 +05:30
parent 553be985ae
commit 355263a4fb
9 changed files with 56 additions and 27 deletions

View File

@ -20,8 +20,8 @@
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
line [23, 46, 75, 43]
bar "sample bat" [52, 96, 35, 10] bar "sample bat" [52, 96, 35, 10]
line [23, 46, 75, 43]
</pre> </pre>
<hr /> <hr />
@ -32,11 +32,22 @@
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
line [23, 46, 75, 43]
bar "sample bat" [52, 96, 35, 10] bar "sample bat" [52, 96, 35, 10]
line [23, 46, 75, 43]
</pre> </pre>
<hr /> <hr />
<h1>XY Charts demos</h1>
<pre class="mermaid">
xychart-beta horizontal
title Basic xychart
x-axis "this is x axis" [category1, "category 2", category3, category4]
y-axis yaxisText 10 --> 150
line [23, 46, 75, 43]
</pre>
<hr />
<script type="module"> <script type="module">
import mermaid from './mermaid.esm.mjs'; import mermaid from './mermaid.esm.mjs';
mermaid.initialize({ mermaid.initialize({

View File

@ -26,6 +26,10 @@ export interface BarPlotData {
export type PlotData = LinePlotData | BarPlotData; export type PlotData = LinePlotData | BarPlotData;
export function isBarPlot(data: PlotData): data is BarPlotData {
return data.type === ChartPlotEnum.BAR;
}
export interface BandAxisDataType { export interface BandAxisDataType {
title: string; title: string;
categories: string[]; categories: string[];

View File

@ -1,5 +1,5 @@
import { log } from '../../../logger.js'; import { log } from '../../../logger.js';
import { DrawableElem, XYChartData } from './Interfaces.js'; import { DrawableElem, XYChartData, isBarPlot } 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 { IAxis, getAxis } from './components/axis/index.js';
@ -13,7 +13,7 @@ export class Orchestrator {
xAxis: IAxis; xAxis: IAxis;
yAxis: IAxis; yAxis: IAxis;
}; };
constructor(private chartConfig: XYChartConfig, chartData: XYChartData) { constructor(private chartConfig: XYChartConfig, private chartData: XYChartData) {
this.componentStore = { this.componentStore = {
title: getChartTitleComponent(chartConfig, chartData), title: getChartTitleComponent(chartConfig, chartData),
plot: getPlotComponent(chartConfig, chartData), plot: getPlotComponent(chartConfig, chartData),
@ -87,6 +87,9 @@ export class Orchestrator {
this.componentStore.xAxis.setBoundingBoxXY({ x: chartX, y: chartY + chartHeight }); this.componentStore.xAxis.setBoundingBoxXY({ x: chartX, y: chartY + chartHeight });
this.componentStore.yAxis.setRange([chartY, chartY + chartHeight]); this.componentStore.yAxis.setRange([chartY, chartY + chartHeight]);
this.componentStore.yAxis.setBoundingBoxXY({ x: 0, y: chartY }); this.componentStore.yAxis.setBoundingBoxXY({ x: 0, y: chartY });
if(this.chartData.plots.find(p => isBarPlot(p))) {
this.componentStore.xAxis.recalculateOuterPaddingToDrawBar();
}
} }
private calculateHorizonatalSpace() { private calculateHorizonatalSpace() {
@ -156,6 +159,9 @@ export class Orchestrator {
this.componentStore.yAxis.setBoundingBoxXY({ x: chartX, y: titleYEnd }); this.componentStore.yAxis.setBoundingBoxXY({ x: chartX, y: titleYEnd });
this.componentStore.xAxis.setRange([chartY, chartY + chartHeight]); this.componentStore.xAxis.setRange([chartY, chartY + chartHeight]);
this.componentStore.xAxis.setBoundingBoxXY({ x: 0, y: chartY }); this.componentStore.xAxis.setBoundingBoxXY({ x: 0, y: chartY });
if(this.chartData.plots.find(p => isBarPlot(p))) {
this.componentStore.xAxis.recalculateOuterPaddingToDrawBar();
}
} }
private calculateSpace() { private calculateSpace() {

View File

@ -1,15 +1,15 @@
import { ScaleBand, scaleBand } from 'd3'; import { ScaleBand, scaleBand } from 'd3';
import { AxisConfig } from '../../Interfaces.js'; import { XYChartAxisConfig } from '../../../../../config.type.js';
import { log } from '../../../../../logger.js';
import { ITextDimensionCalculator } from '../../TextDimensionCalculator.js'; import { ITextDimensionCalculator } from '../../TextDimensionCalculator.js';
import { BaseAxis } from './BaseAxis.js'; import { BaseAxis } from './BaseAxis.js';
import { log } from '../../../../../logger.js';
export class BandAxis extends BaseAxis { export class BandAxis extends BaseAxis {
private scale: ScaleBand<string>; private scale: ScaleBand<string>;
private categories: string[]; private categories: string[];
constructor( constructor(
axisConfig: AxisConfig, axisConfig: XYChartAxisConfig,
categories: string[], categories: string[],
title: string, title: string,
textDimensionCalculator: ITextDimensionCalculator textDimensionCalculator: ITextDimensionCalculator

View File

@ -1,7 +1,8 @@
import { Dimension, Point, DrawableElem, BoundingRect, AxisConfig } from '../../Interfaces.js'; import { XYChartAxisConfig } from '../../../../../config.type.js';
import { AxisPosition, IAxis } from './index.js';
import { ITextDimensionCalculator } from '../../TextDimensionCalculator.js';
import { log } from '../../../../../logger.js'; import { log } from '../../../../../logger.js';
import { BoundingRect, Dimension, DrawableElem, Point } from '../../Interfaces.js';
import { ITextDimensionCalculator } from '../../TextDimensionCalculator.js';
import { AxisPosition, IAxis } from './index.js';
export abstract class BaseAxis implements IAxis { export abstract class BaseAxis implements IAxis {
protected boundingRect: BoundingRect = { x: 0, y: 0, width: 0, height: 0 }; protected boundingRect: BoundingRect = { x: 0, y: 0, width: 0, height: 0 };
@ -10,10 +11,10 @@ export abstract class BaseAxis implements IAxis {
protected showTitle = false; protected showTitle = false;
protected showLabel = false; protected showLabel = false;
protected showTick = false; protected showTick = false;
protected innerPadding = 0; protected outerPadding = 0;
constructor( constructor(
protected axisConfig: AxisConfig, protected axisConfig: XYChartAxisConfig,
protected title: string, protected title: string,
protected textDimensionCalculator: ITextDimensionCalculator protected textDimensionCalculator: ITextDimensionCalculator
) { ) {
@ -28,7 +29,7 @@ export abstract class BaseAxis implements IAxis {
} }
getRange(): [number, number] { getRange(): [number, number] {
return [this.range[0] + this.innerPadding, this.range[1] - this.innerPadding]; return [this.range[0] + this.outerPadding, this.range[1] - this.outerPadding];
} }
setAxisPosition(axisPosition: AxisPosition): void { setAxisPosition(axisPosition: AxisPosition): void {
@ -45,9 +46,8 @@ export abstract class BaseAxis implements IAxis {
return Math.abs(this.range[0] - this.range[1]) / this.getTickValues().length; return Math.abs(this.range[0] - this.range[1]) / this.getTickValues().length;
} }
getTickInnerPadding(): number { getAxisOuterPadding(): number {
return this.innerPadding * 2; return this.outerPadding;
// return Math.abs(this.range[0] - this.range[1]) / this.getTickValues().length;
} }
private getLabelDimension(): Dimension { private getLabelDimension(): Dimension {
@ -57,11 +57,18 @@ export abstract class BaseAxis implements IAxis {
); );
} }
recalculateOuterPaddingToDrawBar(): void {
if((0.7 * this.getTickDistance()) > (this.outerPadding * 2) ) {
this.outerPadding = Math.floor((0.7 * this.getTickDistance())/2);
}
this.recalculateScale();
}
private calculateSpaceIfDrawnHorizontally(availableSpace: Dimension) { private calculateSpaceIfDrawnHorizontally(availableSpace: Dimension) {
let availableHeight = availableSpace.height; let availableHeight = availableSpace.height;
if (this.axisConfig.showLabel) { if (this.axisConfig.showLabel) {
const spaceRequired = this.getLabelDimension(); const spaceRequired = this.getLabelDimension();
this.innerPadding = spaceRequired.width / 2; this.outerPadding = spaceRequired.width / 2;
const heightRequired = spaceRequired.height + this.axisConfig.lablePadding * 2; const heightRequired = spaceRequired.height + this.axisConfig.lablePadding * 2;
log.trace('height required for axis label: ', heightRequired); log.trace('height required for axis label: ', heightRequired);
if (heightRequired <= availableHeight) { if (heightRequired <= availableHeight) {
@ -93,7 +100,7 @@ export abstract class BaseAxis implements IAxis {
let availableWidth = availableSpace.width; let availableWidth = availableSpace.width;
if (this.axisConfig.showLabel) { if (this.axisConfig.showLabel) {
const spaceRequired = this.getLabelDimension(); const spaceRequired = this.getLabelDimension();
this.innerPadding = spaceRequired.height / 2; this.outerPadding = spaceRequired.height / 2;
const widthRequired = spaceRequired.width + this.axisConfig.lablePadding * 2; const widthRequired = spaceRequired.width + this.axisConfig.lablePadding * 2;
log.trace('width required for axis label: ', widthRequired); log.trace('width required for axis label: ', widthRequired);
if (widthRequired <= availableWidth) { if (widthRequired <= availableWidth) {

View File

@ -1,6 +1,6 @@
import { ScaleLinear, scaleLinear } from 'd3'; import { ScaleLinear, scaleLinear } from 'd3';
import { XYChartAxisConfig } from '../../../../../config.type.js';
import { log } from '../../../../../logger.js'; import { log } from '../../../../../logger.js';
import { AxisConfig } from '../../Interfaces.js';
import { ITextDimensionCalculator } from '../../TextDimensionCalculator.js'; import { ITextDimensionCalculator } from '../../TextDimensionCalculator.js';
import { BaseAxis } from './BaseAxis.js'; import { BaseAxis } from './BaseAxis.js';
@ -9,7 +9,7 @@ export class LinearAxis extends BaseAxis {
private domain: [number, number]; private domain: [number, number];
constructor( constructor(
axisConfig: AxisConfig, axisConfig: XYChartAxisConfig,
domain: [number, number], domain: [number, number],
title: string, title: string,
textDimensionCalculator: ITextDimensionCalculator textDimensionCalculator: ITextDimensionCalculator

View File

@ -13,8 +13,9 @@ export type AxisPosition = 'left' | 'right' | 'top' | 'bottom';
export interface IAxis extends ChartComponent { export interface IAxis extends ChartComponent {
getScaleValue(value: string | number): number; getScaleValue(value: string | number): number;
setAxisPosition(axisPosition: AxisPosition): void; setAxisPosition(axisPosition: AxisPosition): void;
getTickInnerPadding(): number; getAxisOuterPadding(): number;
getTickDistance(): number; getTickDistance(): number;
recalculateOuterPaddingToDrawBar(): void;
setRange(range: [number, number]): void; setRange(range: [number, number]): void;
} }

View File

@ -24,7 +24,7 @@ export class BarPlot {
const barPaddingPercent = 5; const barPaddingPercent = 5;
const barWidth = const barWidth =
Math.min(this.xAxis.getTickInnerPadding(), this.xAxis.getTickDistance()) * Math.min(this.xAxis.getAxisOuterPadding() * 2, this.xAxis.getTickDistance()) *
(1 - barPaddingPercent / 100); (1 - barPaddingPercent / 100);
const barWidthHalf = barWidth / 2; const barWidthHalf = barWidth / 2;

View File

@ -125,8 +125,9 @@ function setYAxisRangeData(min: number, max: number) {
function setLineData(title: string, data: number[]) { function setLineData(title: string, data: number[]) {
if (isBandAxisData(xyChartData.xAxis)) { if (isBandAxisData(xyChartData.xAxis)) {
xyChartData.plots.push({ xyChartData.plots.push({
type: ChartPlotEnum.BAR, type: ChartPlotEnum.LINE,
fill: '#0000bb', strokeFill: '#00ff00',
strokeWidth: 2,
data: xyChartData.xAxis.categories.map((c, i) => [c, data[i]]), data: xyChartData.xAxis.categories.map((c, i) => [c, data[i]]),
}); });
} }
@ -134,9 +135,8 @@ function setLineData(title: string, data: number[]) {
function setBarData(title: string, data: number[]) { function setBarData(title: string, data: number[]) {
if (isBandAxisData(xyChartData.xAxis)) { if (isBandAxisData(xyChartData.xAxis)) {
xyChartData.plots.push({ xyChartData.plots.push({
type: ChartPlotEnum.LINE, type: ChartPlotEnum.BAR,
strokeFill: '#00ff00', fill: '#0000bb',
strokeWidth: 2,
data: xyChartData.xAxis.categories.map((c, i) => [c, data[i]]), data: xyChartData.xAxis.categories.map((c, i) => [c, data[i]]),
}); });
} }