[SIP-6] Add reactify function and convert world map to new directory structure. (#5893)
* reactify world map * add createAdaptor * fix typo * add schema * move directory * remove unnecessary lines * make setRef a function * convert keys to camelcase * add unit test * update formatting * add check for displayName * pass width and height as separate inputs
This commit is contained in:
parent
75bc501146
commit
8fff0d9e8f
|
|
@ -79,6 +79,7 @@
|
|||
"jed": "^1.1.1",
|
||||
"jquery": "3.1.1",
|
||||
"json-bigint": "^0.3.0",
|
||||
"lodash": "^4.17.11",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"mapbox-gl": "^0.45.0",
|
||||
"mathjs": "^3.20.2",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
import { it, describe } from 'mocha';
|
||||
import { expect } from 'chai';
|
||||
import convertKeysToCamelCase from '../../../src/utils/convertKeysToCamelCase';
|
||||
|
||||
describe.only('convertKeysToCamelCase(object)', () => {
|
||||
it('returns undefined for undefined input', () => {
|
||||
expect(convertKeysToCamelCase(undefined)).to.equal(undefined);
|
||||
});
|
||||
it('returns null for null input', () => {
|
||||
expect(convertKeysToCamelCase(null)).to.equal(null);
|
||||
});
|
||||
it('returns a new object that has all keys in camelCase', () => {
|
||||
const input = {
|
||||
is_happy: true,
|
||||
'is-angry': false,
|
||||
isHungry: false,
|
||||
};
|
||||
expect(convertKeysToCamelCase(input)).to.deep.equal({
|
||||
isHappy: true,
|
||||
isAngry: false,
|
||||
isHungry: false,
|
||||
});
|
||||
});
|
||||
it('throws error if input is not a plain object', () => {
|
||||
expect(() => { convertKeysToCamelCase({}); }).to.not.throw();
|
||||
expect(() => { convertKeysToCamelCase(''); }).to.throw();
|
||||
expect(() => { convertKeysToCamelCase(new Map()); }).to.throw();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { mapKeys, camelCase, isPlainObject } from 'lodash/fp';
|
||||
|
||||
export default function convertKeysToCamelCase(object) {
|
||||
if (object === null || object === undefined) {
|
||||
return object;
|
||||
}
|
||||
if (isPlainObject(object)) {
|
||||
return mapKeys(k => camelCase(k), object);
|
||||
}
|
||||
throw new Error(`Cannot convert input that is not a plain object: ${object}`);
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import BasicChartInput from '../visualizations/models/BasicChartInput';
|
||||
|
||||
const IDENTITY = x => x;
|
||||
|
||||
export default function createAdaptor(Component, transformProps = IDENTITY) {
|
||||
return function adaptor(slice, payload, setControlValue) {
|
||||
const basicChartInput = new BasicChartInput(slice, payload, setControlValue);
|
||||
ReactDOM.render(
|
||||
<Component
|
||||
width={slice.width()}
|
||||
height={slice.height()}
|
||||
{...transformProps(basicChartInput)}
|
||||
/>,
|
||||
document.querySelector(slice.selector),
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
import React from 'react';
|
||||
|
||||
export default function reactify(renderFn) {
|
||||
class ReactifiedComponent extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.setContainerRef = this.setContainerRef.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.execute();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.execute();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.container = null;
|
||||
}
|
||||
|
||||
setContainerRef(c) {
|
||||
this.container = c;
|
||||
}
|
||||
|
||||
execute() {
|
||||
if (this.container) {
|
||||
renderFn(this.container, this.props);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { id, className } = this.props;
|
||||
return (
|
||||
<div
|
||||
id={id}
|
||||
className={className}
|
||||
ref={this.setContainerRef}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (renderFn.displayName) {
|
||||
ReactifiedComponent.displayName = renderFn.displayName;
|
||||
}
|
||||
if (renderFn.propTypes) {
|
||||
ReactifiedComponent.propTypes = renderFn.propTypes;
|
||||
}
|
||||
if (renderFn.defaultProps) {
|
||||
ReactifiedComponent.defaultProps = renderFn.defaultProps;
|
||||
}
|
||||
return ReactifiedComponent;
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
import reactify from '../../utils/reactify';
|
||||
import WorldMap from './WorldMap';
|
||||
|
||||
export default reactify(WorldMap);
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import d3 from 'd3';
|
||||
import PropTypes from 'prop-types';
|
||||
import Datamap from 'datamaps';
|
||||
import './world_map.css';
|
||||
import './WorldMap.css';
|
||||
|
||||
const propTypes = {
|
||||
data: PropTypes.arrayOf(PropTypes.shape({
|
||||
|
|
@ -109,20 +109,4 @@ function WorldMap(element, props) {
|
|||
|
||||
WorldMap.propTypes = propTypes;
|
||||
|
||||
function adaptor(slice, payload) {
|
||||
const { selector, formData } = slice;
|
||||
const {
|
||||
max_bubble_size: maxBubbleSize,
|
||||
show_bubbles: showBubbles,
|
||||
} = formData;
|
||||
const element = document.querySelector(selector);
|
||||
|
||||
return WorldMap(element, {
|
||||
data: payload.data,
|
||||
height: slice.height(),
|
||||
maxBubbleSize: parseInt(maxBubbleSize, 10),
|
||||
showBubbles,
|
||||
});
|
||||
}
|
||||
|
||||
export default adaptor;
|
||||
export default WorldMap;
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import createAdaptor from '../../utils/createAdaptor';
|
||||
import WorldMap from './ReactWorldMap';
|
||||
import transformProps from './transformProps';
|
||||
|
||||
export default createAdaptor(WorldMap, transformProps);
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
export default function transformProps(basicChartInput) {
|
||||
const { formData, payload } = basicChartInput;
|
||||
const { maxBubbleSize, showBubbles } = formData;
|
||||
|
||||
return {
|
||||
data: payload.data,
|
||||
maxBubbleSize: parseInt(maxBubbleSize, 10),
|
||||
showBubbles,
|
||||
};
|
||||
}
|
||||
|
|
@ -108,7 +108,7 @@ const vizMap = {
|
|||
[VIZ_TYPES.word_cloud]: () =>
|
||||
loadVis(import(/* webpackChunkName: "word_cloud" */ './wordcloud/WordCloud.js')),
|
||||
[VIZ_TYPES.world_map]: () =>
|
||||
loadVis(import(/* webpackChunkName: "world_map" */ './world_map.js')),
|
||||
loadVis(import(/* webpackChunkName: "world_map" */ './WorldMap/adaptor.jsx')),
|
||||
[VIZ_TYPES.dual_line]: loadNvd3,
|
||||
[VIZ_TYPES.event_flow]: () =>
|
||||
loadVis(import(/* webpackChunkName: "EventFlow" */ './EventFlow.jsx')),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
import convertKeysToCamelCase from '../../utils/convertKeysToCamelCase';
|
||||
|
||||
export default class BasicChartInput {
|
||||
constructor(slice, payload, setControlValue) {
|
||||
this.annotationData = slice.annotationData;
|
||||
this.formData = convertKeysToCamelCase(slice.formData);
|
||||
this.payload = payload;
|
||||
this.setControlValue = setControlValue;
|
||||
}
|
||||
}
|
||||
|
|
@ -7487,6 +7487,10 @@ lodash@4.17.10, lodash@^4.0.1, lodash@^4.0.8, lodash@^4.13.1, lodash@^4.14.0, lo
|
|||
version "4.17.10"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
|
||||
|
||||
lodash@^4.17.11:
|
||||
version "4.17.11"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
|
||||
|
||||
log-symbols@2.2.0, log-symbols@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
|
||||
|
|
|
|||
Loading…
Reference in New Issue