diff --git a/__tests__/integration/api-chart-auto-fit-height.spec.ts b/__tests__/integration/api-chart-auto-fit-height.spec.ts
new file mode 100644
index 0000000000..bdd512b269
--- /dev/null
+++ b/__tests__/integration/api-chart-auto-fit-height.spec.ts
@@ -0,0 +1,24 @@
+import { chartAutoFitHeight as render } from '../plots/api';
+import { createNodeGCanvas } from './utils/createNodeGCanvas';
+import { sleep } from './utils/sleep';
+import { kebabCase } from './utils/kebabCase';
+import './utils/useSnapshotMatchers';
+
+describe('chart.options.autoFit', () => {
+ const dir = `${__dirname}/snapshots/api/${kebabCase(render.name)}`;
+ const canvas = createNodeGCanvas(800, 500);
+
+ it('chart({ autoFit: true, height: 200 }) should fit parent container width and custom height', async () => {
+ const { finished } = render({
+ canvas,
+ container: document.createElement('div'),
+ });
+ await finished;
+ await sleep(20);
+ await expect(canvas).toMatchDOMSnapshot(dir, 'step0');
+ });
+
+ afterAll(() => {
+ canvas?.destroy();
+ });
+});
diff --git a/__tests__/integration/api-chart-auto-fit-width.spec.ts b/__tests__/integration/api-chart-auto-fit-width.spec.ts
new file mode 100644
index 0000000000..f178fb2526
--- /dev/null
+++ b/__tests__/integration/api-chart-auto-fit-width.spec.ts
@@ -0,0 +1,25 @@
+import { chartAutoFitWidth as render } from '../plots/api';
+import { createNodeGCanvas } from './utils/createNodeGCanvas';
+import { sleep } from './utils/sleep';
+import { kebabCase } from './utils/kebabCase';
+import './utils/useSnapshotMatchers';
+
+describe('chart.options.autoFit', () => {
+ const dir = `${__dirname}/snapshots/api/${kebabCase(render.name)}`;
+ const canvas = createNodeGCanvas(800, 500);
+
+ it('chart({ autoFit: true, width: 200 }) should fit parent container height and custom width', async () => {
+ const { finished } = render({
+ canvas,
+ container: document.createElement('div'),
+ });
+
+ await finished;
+ await sleep(20);
+ await expect(canvas).toMatchDOMSnapshot(dir, 'step0');
+ });
+
+ afterAll(() => {
+ canvas?.destroy();
+ });
+});
diff --git a/__tests__/integration/snapshots/api/chart-auto-fit-height/step0.svg b/__tests__/integration/snapshots/api/chart-auto-fit-height/step0.svg
new file mode 100644
index 0000000000..4c998e6e87
--- /dev/null
+++ b/__tests__/integration/snapshots/api/chart-auto-fit-height/step0.svg
@@ -0,0 +1,1577 @@
+
\ No newline at end of file
diff --git a/__tests__/integration/snapshots/api/chart-auto-fit-width/step0.svg b/__tests__/integration/snapshots/api/chart-auto-fit-width/step0.svg
new file mode 100644
index 0000000000..043f7bf86b
--- /dev/null
+++ b/__tests__/integration/snapshots/api/chart-auto-fit-width/step0.svg
@@ -0,0 +1,1572 @@
+
\ No newline at end of file
diff --git a/__tests__/plots/api/chart-auto-fit-height.ts b/__tests__/plots/api/chart-auto-fit-height.ts
new file mode 100644
index 0000000000..01a908a4a4
--- /dev/null
+++ b/__tests__/plots/api/chart-auto-fit-height.ts
@@ -0,0 +1,51 @@
+import { Chart } from '../../../src';
+
+export function chartAutoFitHeight(context) {
+ const { container, canvas } = context;
+
+ // button
+ const button = document.createElement('button');
+ button.innerText = 'Change Wrapper Container';
+ container.appendChild(button);
+
+ // wrapperDiv
+ const wrapperDiv = document.createElement('div');
+ wrapperDiv.style.width = '800px';
+ wrapperDiv.style.height = '500px';
+ container.appendChild(wrapperDiv);
+
+ const chart = new Chart({
+ container: wrapperDiv,
+ autoFit: true,
+ height: 200,
+ canvas,
+ });
+
+ chart.data([
+ { genre: 'Sports', sold: 275 },
+ { genre: 'Strategy', sold: 115 },
+ { genre: 'Action', sold: 120 },
+ { genre: 'Shooter', sold: 350 },
+ { genre: 'Other', sold: 150 },
+ ]);
+
+ chart
+ .interval()
+ .encode('x', 'genre')
+ .encode('y', 'sold')
+ .encode('color', 'genre')
+ .axis({ x: { animate: false }, y: { animate: false } });
+
+ const finished = chart.render();
+
+ let resolve;
+ const fitted = new Promise((r) => (resolve = r));
+
+ button.onclick = () => {
+ wrapperDiv.style.width = '400px';
+ wrapperDiv.style.height = '500px';
+ chart.forceFit().then(resolve);
+ };
+
+ return { chart, button, finished, fitted };
+}
diff --git a/__tests__/plots/api/chart-auto-fit-width.ts b/__tests__/plots/api/chart-auto-fit-width.ts
new file mode 100644
index 0000000000..21f77b7ff8
--- /dev/null
+++ b/__tests__/plots/api/chart-auto-fit-width.ts
@@ -0,0 +1,51 @@
+import { Chart } from '../../../src';
+
+export function chartAutoFitWidth(context) {
+ const { container, canvas } = context;
+
+ // button
+ const button = document.createElement('button');
+ button.innerText = 'Change Wrapper Container';
+ container.appendChild(button);
+
+ // wrapperDiv
+ const wrapperDiv = document.createElement('div');
+ wrapperDiv.style.width = '800px';
+ wrapperDiv.style.height = '500px';
+ container.appendChild(wrapperDiv);
+
+ const chart = new Chart({
+ container: wrapperDiv,
+ autoFit: true,
+ width: 200,
+ canvas,
+ });
+
+ chart.data([
+ { genre: 'Sports', sold: 275 },
+ { genre: 'Strategy', sold: 115 },
+ { genre: 'Action', sold: 120 },
+ { genre: 'Shooter', sold: 350 },
+ { genre: 'Other', sold: 150 },
+ ]);
+
+ chart
+ .interval()
+ .encode('x', 'genre')
+ .encode('y', 'sold')
+ .encode('color', 'genre')
+ .axis({ x: { animate: false }, y: { animate: false } });
+
+ const finished = chart.render();
+
+ let resolve;
+ const fitted = new Promise((r) => (resolve = r));
+
+ button.onclick = () => {
+ wrapperDiv.style.width = '400px';
+ wrapperDiv.style.height = '500px';
+ chart.forceFit().then(resolve);
+ };
+
+ return { chart, button, finished, fitted };
+}
diff --git a/__tests__/plots/api/index.ts b/__tests__/plots/api/index.ts
index 362aefa220..52223578ce 100644
--- a/__tests__/plots/api/index.ts
+++ b/__tests__/plots/api/index.ts
@@ -48,4 +48,6 @@ export { chartOptionsCallbackChildren } from './chart-options-callback-children'
export { chartAutoFitSlider } from './chart-auto-fit-slider';
export { chart3d } from './chart-3d';
export { chartOnScrollbarFilter } from './chart-on-scrollbar-filter';
+export { chartAutoFitHeight } from './chart-auto-fit-height';
+export { chartAutoFitWidth } from './chart-auto-fit-width';
export { chartOnLabelClick } from './chart-on-label-click';
diff --git a/src/api/utils.ts b/src/api/utils.ts
index f466625658..e243201a16 100644
--- a/src/api/utils.ts
+++ b/src/api/utils.ts
@@ -76,9 +76,9 @@ export function valueOf(node: Node): Record {
}
export function sizeOf(options, container) {
- const { width = 640, height = 480, autoFit, depth = 0 } = options;
- let effectiveWidth = width;
- let effectiveHeight = height;
+ const { width, height, autoFit, depth = 0 } = options;
+ let effectiveWidth = 640;
+ let effectiveHeight = 480;
if (autoFit) {
const { width: containerWidth, height: containerHeight } =
@@ -87,6 +87,9 @@ export function sizeOf(options, container) {
effectiveHeight = containerHeight || effectiveHeight;
}
+ effectiveWidth = width || effectiveWidth;
+ effectiveHeight = height || effectiveHeight;
+
return {
width: Math.max(
isNumber(effectiveWidth) ? effectiveWidth : MIN_CHART_WIDTH,