diff --git a/packages/react-vega-demo/stories/dimensions.stories.tsx b/packages/react-vega-demo/stories/dimensions.stories.tsx
new file mode 100644
index 00000000..74c189ac
--- /dev/null
+++ b/packages/react-vega-demo/stories/dimensions.stories.tsx
@@ -0,0 +1,38 @@
+import React from 'react';
+// eslint-disable-next-line import/no-extraneous-dependencies
+import { storiesOf } from '@storybook/react';
+import { VegaLite } from '../../react-vega/src';
+
+const DATA = {
+ myData: [
+ { a: 'A', b: 20 },
+ { a: 'B', b: 34 },
+ { a: 'C', b: 55 },
+ { a: 'D', b: 19 },
+ { a: 'E', b: 40 },
+ { a: 'F', b: 34 },
+ { a: 'G', b: 91 },
+ { a: 'H', b: 78 },
+ { a: 'I', b: 25 },
+ ],
+};
+
+const SPEC = {
+ description: 'A simple bar chart with embedded data.',
+ layer: [
+ {
+ data: { name: 'myData' },
+ encoding: {
+ x: { field: 'a', type: 'ordinal' },
+ y: { field: 'b', type: 'quantitative' },
+ },
+ mark: 'bar',
+ },
+ ],
+};
+
+storiesOf('react-vega', module).add('width=300', () => (
+
+)).add('height=300', () => (
+
+));
diff --git a/packages/react-vega/src/VegaEmbed.tsx b/packages/react-vega/src/VegaEmbed.tsx
index cadf83c6..88cc8926 100644
--- a/packages/react-vega/src/VegaEmbed.tsx
+++ b/packages/react-vega/src/VegaEmbed.tsx
@@ -7,6 +7,7 @@ import { NOOP } from './constants';
import addSignalListenersToView from './utils/addSignalListenersToView';
import computeSpecChanges from './utils/computeSpecChanges';
import removeSignalListenersFromView from './utils/removeSignalListenersFromView';
+import combineSpecWithDimension from './utils/combineSpecWithDimension';
export type VegaEmbedProps = {
className?: string;
@@ -32,13 +33,18 @@ export default class VegaEmbed extends React.PureComponent {
fieldSet.delete('signalListeners');
fieldSet.delete('spec');
fieldSet.delete('style');
+ fieldSet.delete('width');
+ fieldSet.delete('height');
// Only create a new view if necessary
if (Array.from(fieldSet).some(f => this.props[f] !== prevProps[f])) {
this.clearView();
this.createView();
} else {
- const specChanges = computeSpecChanges(this.props.spec, prevProps.spec);
+ const specChanges = computeSpecChanges(
+ combineSpecWithDimension(this.props),
+ combineSpecWithDimension(prevProps),
+ );
const { signalListeners: newSignalListeners } = this.props;
const { signalListeners: oldSignalListeners } = prevProps;
@@ -68,18 +74,14 @@ export default class VegaEmbed extends React.PureComponent {
view.run();
});
}
- } else {
- const areSignalListenersChanged = !shallowEqual(newSignalListeners, oldSignalListeners);
+ } else if (!shallowEqual(newSignalListeners, oldSignalListeners)) {
this.modifyView(view => {
- if (areSignalListenersChanged) {
- if (oldSignalListeners) {
- removeSignalListenersFromView(view, oldSignalListeners);
- }
- if (newSignalListeners) {
- addSignalListenersToView(view, newSignalListeners);
- }
+ if (oldSignalListeners) {
+ removeSignalListenersFromView(view, oldSignalListeners);
+ }
+ if (newSignalListeners) {
+ addSignalListenersToView(view, newSignalListeners);
}
-
view.run();
});
}
@@ -114,9 +116,10 @@ export default class VegaEmbed extends React.PureComponent {
};
createView() {
- const { spec, onNewView, signalListeners = {}, ...options } = this.props;
+ const { spec, onNewView, signalListeners = {}, width, height, ...options } = this.props;
if (this.containerRef.current) {
- this.viewPromise = vegaEmbed(this.containerRef.current, spec, options)
+ const finalSpec = combineSpecWithDimension(this.props);
+ this.viewPromise = vegaEmbed(this.containerRef.current, finalSpec, options)
.then(({ view }) => {
if (addSignalListenersToView(view, signalListeners)) {
view.run();
@@ -143,9 +146,7 @@ export default class VegaEmbed extends React.PureComponent {
render() {
const { className, style } = this.props;
- return (
- // Create the container Vega draws inside
-
- );
+ // Create the container Vega draws inside
+ return ;
}
}
diff --git a/packages/react-vega/src/utils/combineSpecWithDimension.ts b/packages/react-vega/src/utils/combineSpecWithDimension.ts
new file mode 100644
index 00000000..a07f92a9
--- /dev/null
+++ b/packages/react-vega/src/utils/combineSpecWithDimension.ts
@@ -0,0 +1,16 @@
+import { VisualizationSpec } from 'vega-embed';
+import { VegaEmbedProps } from '../VegaEmbed';
+
+export default function combineSpecWithDimension(props: VegaEmbedProps): VisualizationSpec {
+ const { spec, width, height } = props;
+ if (typeof width !== 'undefined' && typeof height !== 'undefined') {
+ return { ...spec, width, height };
+ }
+ if (typeof width !== 'undefined') {
+ return { ...spec, width };
+ }
+ if (typeof height !== 'undefined') {
+ return { ...spec, height };
+ }
+ return spec;
+}
diff --git a/packages/react-vega/src/utils/getUniqueFieldNames.ts b/packages/react-vega/src/utils/getUniqueFieldNames.ts
index 2455b64c..cc9c6432 100644
--- a/packages/react-vega/src/utils/getUniqueFieldNames.ts
+++ b/packages/react-vega/src/utils/getUniqueFieldNames.ts
@@ -1,7 +1,4 @@
-import { VisualizationSpec } from 'vega-embed';
-import { PlainObject } from '../types';
-
-export default function getUniqueFieldNames(objects: (PlainObject | VisualizationSpec)[]) {
+export default function getUniqueFieldNames(objects: T[]) {
const fields = new Set();
objects.forEach(o => {
Object.keys(o).forEach(field => {
diff --git a/packages/react-vega/test/utils/combineSpecWithDimension.test.ts b/packages/react-vega/test/utils/combineSpecWithDimension.test.ts
new file mode 100644
index 00000000..6de11da2
--- /dev/null
+++ b/packages/react-vega/test/utils/combineSpecWithDimension.test.ts
@@ -0,0 +1,77 @@
+import combineSpecWithDimension from '../../src/utils/combineSpecWithDimension';
+
+describe('combineSpecWithDimension(props)', () => {
+ const spec = {
+ $schema: 'https://vega.github.io/schema/vega-lite/v4.json',
+ data: {
+ values: [],
+ name: 'source',
+ },
+ mark: 'bar',
+ encoding: {
+ y: {
+ field: 'b',
+ type: 'quantitative',
+ },
+ },
+ } as const;
+
+ it('adds width and height', () => {
+ expect(combineSpecWithDimension({ spec, width: 100, height: 100 })).toEqual({
+ $schema: 'https://vega.github.io/schema/vega-lite/v4.json',
+ width: 100,
+ height: 100,
+ data: {
+ values: [],
+ name: 'source',
+ },
+ mark: 'bar',
+ encoding: {
+ y: {
+ field: 'b',
+ type: 'quantitative',
+ },
+ },
+ });
+ });
+
+ it('adds width', () => {
+ expect(combineSpecWithDimension({ spec, width: 100 })).toEqual({
+ $schema: 'https://vega.github.io/schema/vega-lite/v4.json',
+ width: 100,
+ data: {
+ values: [],
+ name: 'source',
+ },
+ mark: 'bar',
+ encoding: {
+ y: {
+ field: 'b',
+ type: 'quantitative',
+ },
+ },
+ });
+ });
+
+ it('adds height', () => {
+ expect(combineSpecWithDimension({ spec, height: 100 })).toEqual({
+ $schema: 'https://vega.github.io/schema/vega-lite/v4.json',
+ height: 100,
+ data: {
+ values: [],
+ name: 'source',
+ },
+ mark: 'bar',
+ encoding: {
+ y: {
+ field: 'b',
+ type: 'quantitative',
+ },
+ },
+ });
+ });
+
+ it('returns original if no width or height are defined', () => {
+ expect(combineSpecWithDimension({ spec })).toBe(spec);
+ });
+});