diff --git a/src/charts/LineChart/LineChart.stories.ts b/src/charts/LineChart/LineChart.stories.ts index 90cf0386..95fd7967 100644 --- a/src/charts/LineChart/LineChart.stories.ts +++ b/src/charts/LineChart/LineChart.stories.ts @@ -623,3 +623,42 @@ export function PathAnimation() { return root; } + +export function ViewBox() { + const root = document.createElement('div'); + + new LineChart( + root, + { + labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], + series: [ + [12, 9, 7, 8, 5], + [2, 1, 3.5, 7, 3], + [1, 3, 4, 5, 6] + ] + }, + { + fullWidth: true, + chartPadding: { + right: 40 + }, + viewBox: { + width: 800, + height: 400 + } + }, + [ + [ + 'screen and (max-width: 575px)', + { + viewBox: { + width: 400, + height: 300 + } + } + ] + ] + ); + + return root; +} diff --git a/src/charts/LineChart/LineChart.ts b/src/charts/LineChart/LineChart.ts index e0eb9691..ce0bd80d 100644 --- a/src/charts/LineChart/LineChart.ts +++ b/src/charts/LineChart/LineChart.ts @@ -261,7 +261,8 @@ export class LineChart extends BaseChart { this.container, options.width, options.height, - options.classNames.chart + options.classNames.chart, + options.viewBox ); this.svg = svg; diff --git a/src/core/creation.ts b/src/core/creation.ts index f35836c8..b6c7b957 100644 --- a/src/core/creation.ts +++ b/src/core/creation.ts @@ -5,7 +5,8 @@ import type { Label, GridDrawEvent, GridBackgroundDrawEvent, - LabelDrawEvent + LabelDrawEvent, + ViewBox } from './types'; import type { EventEmitter } from '../event'; import type { Axis } from '../axes'; @@ -25,7 +26,8 @@ export function createSvg( container: Element, width: number | string = '100%', height: number | string = '100%', - className?: string + className?: string, + viewBox?: ViewBox ) { if (!container) { throw new Error('Container element is not found'); @@ -52,6 +54,10 @@ export function createSvg( svg.addClass(className); } + if (viewBox) { + svg.attr({ viewBox: `0 0 ${viewBox.width} ${viewBox.height}` }); + } + // Add the DOM node to our container container.appendChild(svg.getNode()); @@ -97,8 +103,13 @@ export function createChartRect(svg: Svg, options: Options) { const yAxisPosition = options.axisY?.position; const xAxisPosition = options.axisX?.position; // If width or height results in invalid value (including 0) we fallback to the unitless settings or even 0 - let width = svg.width() || quantity(options.width).value || 0; - let height = svg.height() || quantity(options.height).value || 0; + let width = + options.viewBox?.width || svg.width() || quantity(options.width).value || 0; + let height = + options.viewBox?.height || + svg.height() || + quantity(options.height).value || + 0; const normalizedPadding = normalizePadding(options.chartPadding); // If settings were to small to cope with offset (legacy) and padding, we'll adjust diff --git a/src/core/types.ts b/src/core/types.ts index 53d3b4f3..a6fbefb1 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -25,6 +25,11 @@ export type Plugin = (chart: any, options?: any) => void; // eslint-disable-next-line @typescript-eslint/no-explicit-any export type Meta = any; +export interface ViewBox { + width: number; + height: number; +} + export interface Options< TXAxisOptions = AxisOptions, TYAxisOptions = TXAxisOptions @@ -67,6 +72,10 @@ export interface Options< classNames?: Record; // eslint-disable-next-line @typescript-eslint/no-explicit-any plugins?: (Plugin | [Plugin, any])[]; + /** + * Define the ViewBox for an SVG, this is optional and only required if you need a scalable chart. This should be used together with responsive options to ensure a proper text size. + */ + viewBox?: ViewBox; } export interface AxisOptions {