Skip to content

Commit

Permalink
feat: support top-level width and height (#144)
Browse files Browse the repository at this point in the history
* feat: support top-level width and height

* fix: omit width and height

* test: add tests
  • Loading branch information
kristw committed Mar 22, 2020
1 parent 94ba1f1 commit 1d75bc3
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 21 deletions.
38 changes: 38 additions & 0 deletions packages/react-vega-demo/stories/dimensions.stories.tsx
Original file line number Diff line number Diff line change
@@ -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', () => (
<VegaLite spec={SPEC} data={DATA} width={300} />
)).add('height=300', () => (
<VegaLite spec={SPEC} data={DATA} height={300} />
));
35 changes: 18 additions & 17 deletions packages/react-vega/src/VegaEmbed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -32,13 +33,18 @@ export default class VegaEmbed extends React.PureComponent<VegaEmbedProps> {
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;
Expand Down Expand Up @@ -68,18 +74,14 @@ export default class VegaEmbed extends React.PureComponent<VegaEmbedProps> {
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();
});
}
Expand Down Expand Up @@ -114,9 +116,10 @@ export default class VegaEmbed extends React.PureComponent<VegaEmbedProps> {
};

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();
Expand All @@ -143,9 +146,7 @@ export default class VegaEmbed extends React.PureComponent<VegaEmbedProps> {
render() {
const { className, style } = this.props;

return (
// Create the container Vega draws inside
<div ref={this.containerRef} className={className} style={style} />
);
// Create the container Vega draws inside
return <div ref={this.containerRef} className={className} style={style} />;
}
}
16 changes: 16 additions & 0 deletions packages/react-vega/src/utils/combineSpecWithDimension.ts
Original file line number Diff line number Diff line change
@@ -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;
}
5 changes: 1 addition & 4 deletions packages/react-vega/src/utils/getUniqueFieldNames.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import { VisualizationSpec } from 'vega-embed';
import { PlainObject } from '../types';

export default function getUniqueFieldNames(objects: (PlainObject | VisualizationSpec)[]) {
export default function getUniqueFieldNames<T>(objects: T[]) {
const fields = new Set<string>();
objects.forEach(o => {
Object.keys(o).forEach(field => {
Expand Down
77 changes: 77 additions & 0 deletions packages/react-vega/test/utils/combineSpecWithDimension.test.ts
Original file line number Diff line number Diff line change
@@ -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);
});
});

0 comments on commit 1d75bc3

Please sign in to comment.