From db213873e2959b7c24c44f1330ec86af801406e8 Mon Sep 17 00:00:00 2001 From: Jae Sung Park Date: Tue, 8 Oct 2024 18:41:51 +0900 Subject: [PATCH] feat(resize): Intent to ship resize.auto='viewBox' Implement auto resize based on viewBox attribute Fix #3893 Co-authored-by: netil --- demo/chart.js | 10 ++++---- demo/demo.js | 36 ++++++++++++++++++++++++++++- src/ChartInternal/ChartInternal.ts | 8 ++++--- src/ChartInternal/internals/size.ts | 13 +++++++---- src/config/Options/common/main.ts | 20 +++++++++++----- test/internals/bb-spec.ts | 18 +++++++++++++++ types/options.d.ts | 6 ++++- 7 files changed, 92 insertions(+), 19 deletions(-) diff --git a/demo/chart.js b/demo/chart.js index ed28988f6..123f0d566 100644 --- a/demo/chart.js +++ b/demo/chart.js @@ -116,10 +116,12 @@ var billboardDemo = { Object.keys(demos).forEach(function(key) { html.push("
  • " + key + "

    "); - Object.keys(demos[key]).sort().forEach(function (v, i) { - i === 0 && html.push("
      "); - html.push("
    • " + v + "
    • "); - }); + Object.keys(demos[key]) + .sort(Intl.Collator().compare) + .forEach(function (v, i) { + i === 0 && html.push("
        "); + html.push("
      • " + v + "
      • "); + }); html.push("
      "); }); diff --git a/demo/demo.js b/demo/demo.js index b701bfbdc..60bec6c96 100644 --- a/demo/demo.js +++ b/demo/demo.js @@ -5691,7 +5691,41 @@ d3.select(".chart_area") }, clipPath: false } - } + }, + resizeViewBox: [ + { + options: { + data: { + columns: [ + ["sample", 70, 200, 120, 400, 300, 250] + ], + type: "bar" + }, + resize: { + auto: "viewBox" + } + } + }, + { + options: { + size: { + width: 480, + height: 240 + }, + data: { + columns: [ + ["data1", 70], + ["data2", 170], + ["data3", 120] + ], + type: "pie" + }, + resize: { + auto: "viewBox" + } + } + } + ] }, DonutChartOptions: { DonutCornerRadius: { diff --git a/src/ChartInternal/ChartInternal.ts b/src/ChartInternal/ChartInternal.ts index be2fcc8e9..186e7b84b 100644 --- a/src/ChartInternal/ChartInternal.ts +++ b/src/ChartInternal/ChartInternal.ts @@ -10,7 +10,7 @@ import { utcFormat as d3UtcFormat, utcParse as d3UtcParse } from "d3-time-format"; -import type {d3Selection} from "../../types/types"; +import type {d3Selection, d3Transition} from "../../types/types"; import {$CIRCLE, $COMMON, $TEXT} from "../config/classes"; import Options from "../config/Options/Options"; import Store from "../config/Store/Store"; @@ -139,7 +139,8 @@ export default class ChartInternal { * @returns {d3Selection} * @private */ - $T(selection: SVGElement | d3Selection, force?: boolean, name?: string): d3Selection { + $T(selection: SVGElement | d3Selection | d3Transition, force?: boolean, + name?: string): d3Selection { const {config, state} = this; const duration = config.transition_duration; const subchart = config.subchart_show; @@ -162,6 +163,7 @@ export default class ChartInternal { state.rendered && !subchart; + // @ts-ignore t = (transit ? t.transition(name).duration(duration) : t) as d3Selection; } @@ -791,7 +793,7 @@ export default class ChartInternal { list.push(() => callFn(config.onresize, $$.api)); - if (config.resize_auto) { + if (config.resize_auto === true) { list.push(() => { state.resizing = true; diff --git a/src/ChartInternal/internals/size.ts b/src/ChartInternal/internals/size.ts index e9fd6bfd2..668a73a86 100644 --- a/src/ChartInternal/internals/size.ts +++ b/src/ChartInternal/internals/size.ts @@ -132,11 +132,16 @@ export default { updateSvgSize(): void { const $$ = this; - const {state: {clip, current, hasAxis, width, height}, $el: {svg}} = $$; + const {config, state: {clip, current, hasAxis, width, height}, $el: {svg}} = $$; - svg - .attr("width", current.width) - .attr("height", current.height); + if (config.resize_auto === "viewBox") { + svg + .attr("viewBox", `0 0 ${current.width} ${current.height}`); + } else { + svg + .attr("width", current.width) + .attr("height", current.height); + } if (hasAxis) { const brush = svg.select(`.${$SUBCHART.brush} .overlay`); diff --git a/src/config/Options/common/main.ts b/src/config/Options/common/main.ts index bef0a5b27..b08ea3cea 100644 --- a/src/config/Options/common/main.ts +++ b/src/config/Options/common/main.ts @@ -162,28 +162,36 @@ export default { * @memberof Options * @type {object} * @property {object} [resize] resize object - * @property {boolean} [resize.auto=true] Set chart resize automatically on viewport changes. + * @property {boolean|string} [resize.auto=true] Set chart resize automatically on viewport changes. + * - **NOTE:** Available options + * - true: Enables automatic resize. + * - false: Disables automatic resize. + * - "viewBox": Enables automatic resize, and size will be fixed based on the viewbox. * @property {boolean|number} [resize.timer=true] Set resize timer option. - * - **NOTE:** + * - **NOTE:** Available options * - The resize function will be called using: * - true: `setTimeout()` * - false: `requestIdleCallback()` - * - Given number(delay in ms) value, resize function will be triggered using `setTimer()` with given delay. + * - Given number(delay in ms) value, resize function will be triggered using `setTimeout()` with given delay. + * @see [Demo](https://naver.github.io/billboard.js/demo/#ChartOptions.resizeViewBox) * @example * resize: { * auto: false, * - * // set resize function will be triggered using `setTimer()` + * // set resize based on viewBox value + * auto: "viewBox", + * + * // set resize function will be triggered using `setTimeout()` * timer: true, * * // set resize function will be triggered using `requestIdleCallback()` * timer: false, * - * // set resize function will be triggered using `setTimer()` with a delay of `100ms`. + * // set resize function will be triggered using `setTimeout()` with a delay of `100ms`. * timer: 100 * } */ - resize_auto: true, + resize_auto: true, resize_timer: true, /** diff --git a/test/internals/bb-spec.ts b/test/internals/bb-spec.ts index cf586962c..2976e87e7 100644 --- a/test/internals/bb-spec.ts +++ b/test/internals/bb-spec.ts @@ -303,6 +303,24 @@ describe("Interface & initialization", () => { expect(chart.$.chart.node().getBoundingClientRect().height).to.be.equal(height); }); + + it("check if viewBox attribute set", () => { + chart = util.generate({ + resize: { + auto: "viewBox" + }, + data: { + columns: [ + ["data1", 300, 350, 300, 120, 100, 200], + ], + type: "bar" + } + }); + + const {svg} = chart.$; + + expect(svg.attr("viewBox")).to.be.equal("0 0 640 480"); + }); }); describe("set defaults options", () => { diff --git a/types/options.d.ts b/types/options.d.ts index f87c99e93..e84d7fc72 100644 --- a/types/options.d.ts +++ b/types/options.d.ts @@ -160,8 +160,12 @@ export interface ChartOptions { resize?: { /** * Indicate if the chart should automatically get resized when the window gets resized. + * - **NOTE:** Available options + * - true: Enables automatic resize. + * - false: Disables automatic resize. + * - "viewBox": Enables automatic resize, and size will be fixed based on the viewbox. */ - auto?: boolean; + auto?: boolean | "viewBox"; /** * Set resize timer option.