Skip to content
This repository has been archived by the owner on Jun 25, 2020. It is now read-only.

feat(plugin-chart-word-cloud): convert word cloud to use encodable #258

Merged
merged 11 commits into from
Nov 20, 2019
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/superset-ui-plugin-chart-word-cloud/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
"@types/d3-scale": "^2.0.2",
"@types/react": "^16.3.0",
"d3-cloud": "^1.2.5",
"d3-scale": "^3.0.1"
"d3-scale": "^3.0.1",
"encodable": "^0.0.7"
},
"peerDependencies": {
"@superset-ui/chart": "^0.12.0",
Expand Down
116 changes: 0 additions & 116 deletions packages/superset-ui-plugin-chart-word-cloud/src/WordCloud.tsx

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { buildQueryContext } from '@superset-ui/query';
import WordCloudFormData from './WordCloudFormData';
import { WordCloudFormData } from './types';

export default function buildQuery(formData: WordCloudFormData) {
// Set the single QueryObject's groupby field with series in formData
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { createEncoderFactory } from 'encodable';
import { DeriveEncoding } from 'encodable/lib/types/Encoding';

type WordCloudEncodingConfig = {
color: ['Color', string];
fontFamily: ['Category', string];
fontSize: ['Numeric', number];
fontWeight: ['Category', string | number];
text: ['Text', string];
};

// eslint-disable-next-line import/prefer-default-export
export const wordCloudEncoderFactory = createEncoderFactory<WordCloudEncodingConfig>({
channelTypes: {
color: 'Color',
fontFamily: 'Category',
fontSize: 'Numeric',
fontWeight: 'Category',
text: 'Text',
},
defaultEncoding: {
color: { value: 'black' },
fontFamily: { value: 'Helvetica' },
fontSize: { value: 20 },
fontWeight: { value: 'bold' },
text: { value: '' },
},
});

export type WordCloudEncoding = DeriveEncoding<WordCloudEncodingConfig>;
128 changes: 128 additions & 0 deletions packages/superset-ui-plugin-chart-word-cloud/src/chart/WordCloud.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import React from 'react';
import cloudLayout, { Word } from 'd3-cloud';
import { PlainObject } from 'encodable/lib/types/Data';
import { WordCloudEncoding, wordCloudEncoderFactory } from './Encoder';

export const ROTATION = {
flat: () => 0,
/* eslint-disable-next-line no-magic-numbers */
random: () => Math.floor(Math.random() * 6 - 3) * 30,
Copy link

@espressoroaster espressoroaster Nov 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe leave a comment to explain that this calculates a random rotation between -90 and 90 degrees. I'm assuming the unit is degrees since square is * 90, but it would be helpful to read it explicitly when skimming the code.

/* eslint-disable-next-line no-magic-numbers */
square: () => Math.floor(Math.random() * 2) * 90,
};

export type RotationType = keyof typeof ROTATION;

/**
* These props should be stored when saving the chart.
*/
export interface WordCloudVisualProps {
encoding?: Partial<WordCloudEncoding>;
rotation?: RotationType;
}

export interface WordCloudProps extends WordCloudVisualProps {
data: PlainObject[];
height: number;
width: number;
}

interface State {
words: Word[];
}

const defaultProps = {
encoding: {},
rotation: 'flat',
};

export default class WordCloud extends React.PureComponent<
WordCloudProps & typeof defaultProps,
State
> {
isMounted: boolean = false;
state: State = {
words: [],
};

createEncoder = wordCloudEncoderFactory.createSelector();

static defaultProps = defaultProps;

componentDidMount() {
this.isMounted = true;
this.update();
}

componentDidUpdate(prevProps: WordCloudProps) {
const { data, encoding, width, height, rotation } = this.props;

if (
prevProps.data !== data ||
prevProps.encoding !== encoding ||
prevProps.width !== width ||
prevProps.height !== height ||
prevProps.rotation !== rotation
) {
this.update();
}
}

componentWillUnmount() {
this.isMounted = false;
}

setWords = (words: Word[]) => {
if (this.isMounted) {
this.setState({ words });
}
};

update() {
const { data, width, height, rotation, encoding } = this.props;

const encoder = this.createEncoder(encoding);
encoder.channels.fontSize.setDomainFromDataset(data);

cloudLayout()
.size([width, height])
.words(data)
/* eslint-disable-next-line no-magic-numbers */
.padding(5)
.rotate(ROTATION[rotation] || ROTATION.flat)
.text(d => encoder.channels.text.getValueFromDatum(d))
.font(d => encoder.channels.fontFamily.encodeDatum(d, 'Helvetica'))
.fontWeight(d => encoder.channels.fontWeight.encodeDatum(d, 'normal'))
.fontSize(d => encoder.channels.fontSize.encodeDatum(d, 0))
.on('end', this.setWords)
.start();
}

render() {
const { width, height, encoding } = this.props;
const { words } = this.state;

const encoder = this.createEncoder(encoding);
encoder.channels.color.setDomainFromDataset(words);

return (
<svg width={width} height={height}>
<g transform={`translate(${width / 2},${height / 2})`}>
{words.map(w => (
<text
key={w.text}
fontSize={`${w.size}px`}
fontWeight={w.weight}
fontFamily={w.font}
fill={encoder.channels.color.encodeDatum(w, '')}
textAnchor="middle"
transform={`translate(${w.x}, ${w.y}) rotate(${w.rotate})`}
>
{w.text}
</text>
))}
</g>
</svg>
);
}
}
4 changes: 2 additions & 2 deletions packages/superset-ui-plugin-chart-word-cloud/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { t } from '@superset-ui/translation';
import { ChartMetadata, ChartPlugin } from '@superset-ui/chart';
import buildQuery from './buildQuery';
import WordCloudFormData from './WordCloudFormData';
import { WordCloudFormData } from './types';
import transformProps from './transformProps';
import thumbnail from './images/thumbnail.png';

Expand All @@ -16,7 +16,7 @@ export default class WordCloudChartPlugin extends ChartPlugin<WordCloudFormData>
constructor() {
super({
buildQuery,
loadChart: () => import('./WordCloud'),
loadChart: () => import('./chart/WordCloud'),
metadata,
transformProps,
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { t } from '@superset-ui/translation';
import { ChartMetadata, ChartPlugin } from '@superset-ui/chart';
import buildQuery from '../buildQuery';
import transformProps from './transformProps';
import thumbnail from '../images/thumbnail.png';
import { LegacyWordCloudFormData } from './types';

const metadata = new ChartMetadata({
credits: ['https://github.com/jasondavies/d3-cloud'],
description: '',
name: t('Word Cloud'),
thumbnail,
useLegacyApi: true,
});

export default class WordCloudChartPlugin extends ChartPlugin<LegacyWordCloudFormData> {
constructor() {
super({
buildQuery,
loadChart: () => import('../chart/WordCloud'),
metadata,
transformProps,
});
}
}
Loading