Skip to content
This repository has been archived by the owner on Nov 3, 2023. It is now read-only.

Commit

Permalink
Repair and refactor Word Cloud (apache#5669)
Browse files Browse the repository at this point in the history
* create reactize function

* update function signature

* adjust word cloud controls

* Fix broken word cloud logic

* Repair and refactor word cloud

* remove file

* Add PropTypes

* change module.exports to export default

* change order

* update proptypes
  • Loading branch information
kristw authored and mistercrunch committed Aug 22, 2018
1 parent 3929f0f commit 0a40149
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 50 deletions.
5 changes: 4 additions & 1 deletion superset/assets/src/explore/controls.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -1295,7 +1295,8 @@ export const controls = {
type: 'SelectControl',
label: t('Rotation'),
choices: formatSelectOptions(['random', 'flat', 'square']),
default: 'random',
renderTrigger: true,
default: 'square',
description: t('Rotation to apply to words in the cloud'),
},

Expand Down Expand Up @@ -1356,6 +1357,7 @@ export const controls = {
type: 'TextControl',
isInt: true,
label: t('Font Size From'),
renderTrigger: true,
default: '20',
description: t('Font size for the smallest value in the list'),
},
Expand All @@ -1364,6 +1366,7 @@ export const controls = {
type: 'TextControl',
isInt: true,
label: t('Font Size To'),
renderTrigger: true,
default: '150',
description: t('Font size for the biggest value in the list'),
},
Expand Down
2 changes: 1 addition & 1 deletion superset/assets/src/explore/visTypes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -1042,9 +1042,9 @@ export const visTypes = {
label: t('Query'),
expanded: true,
controlSetRows: [
['series'],
['metric'],
['adhoc_filters'],
['series'],
['row_limit', null],
],
},
Expand Down
136 changes: 88 additions & 48 deletions superset/assets/src/visualizations/word_cloud.js
Original file line number Diff line number Diff line change
@@ -1,63 +1,103 @@
/* eslint-disable no-use-before-define */
import d3 from 'd3';
import PropTypes from 'prop-types';
import cloudLayout from 'd3-cloud';
import { getColorFromScheme } from '../modules/colors';

function wordCloudChart(slice, payload) {
const chart = d3.select(slice.selector);
const data = payload.data;
const fd = slice.formData;
const range = [
fd.size_from,
fd.size_to,
];
const rotation = fd.rotation;
let fRotation;
if (rotation === 'square') {
fRotation = () => Math.floor((Math.random() * 2) * 90);
} else if (rotation === 'flat') {
fRotation = () => 0;
} else {
fRotation = () => Math.floor(((Math.random() * 6) - 3) * 30);
}
const size = [slice.width(), slice.height()];
const ROTATION = {
square: () => Math.floor((Math.random() * 2)) * 90,
flat: () => 0,
random: () => Math.floor(((Math.random() * 6) - 3)) * 30,
};

const propTypes = {
data: PropTypes.arrayOf(PropTypes.shape({
size: PropTypes.number,
text: PropTypes.string,
})),
width: PropTypes.number,
height: PropTypes.number,
rotation: PropTypes.string,
sizeRange: PropTypes.arrayOf(PropTypes.number),
colorScheme: PropTypes.string,
};

function wordCloud(element, props) {
PropTypes.checkPropTypes(propTypes, props, 'prop', 'WordCloud');

const {
data,
width,
height,
rotation,
sizeRange,
colorScheme,
} = props;

console.log('data', data);

const chart = d3.select(element);
const size = [width, height];
const rotationFn = ROTATION[rotation] || ROTATION.random;

const scale = d3.scale.linear()
.range(range)
.domain(d3.extent(data, function (d) {
return d.size;
}));
.range(sizeRange)
.domain(d3.extent(data, d => d.size));

const layout = cloudLayout()
.size(size)
.words(data)
.padding(5)
.rotate(rotationFn)
.font('Helvetica')
.fontWeight('bold')
.fontSize(d => scale(d.size));

function draw(words) {
chart.selectAll('*').remove();

const [w, h] = layout.size();

chart.append('svg')
.attr('width', layout.size()[0])
.attr('height', layout.size()[1])
.append('g')
.attr('transform', `translate(${layout.size()[0] / 2},${layout.size()[1] / 2})`)
.selectAll('text')
.data(words)
.enter()
.append('text')
.style('font-size', d => d.size + 'px')
.style('font-family', 'Impact')
.style('fill', d => getColorFromScheme(d.text, fd.color_scheme))
.attr('text-anchor', 'middle')
.attr('transform', d => `translate(${d.x}, ${d.y}) rotate(${d.rotate})`)
.text(d => d.text);
.attr('width', w)
.attr('height', h)
.append('g')
.attr('transform', `translate(${w / 2},${h / 2})`)
.selectAll('text')
.data(words)
.enter()
.append('text')
.style('font-size', d => `${d.size}px`)
.style('font-weight', 'bold')
.style('font-family', 'Helvetica')
.style('fill', d => getColorFromScheme(d.text, colorScheme))
.attr('text-anchor', 'middle')
.attr('transform', d => `translate(${d.x}, ${d.y}) rotate(${d.rotate})`)
.text(d => d.text);
}

const layout = cloudLayout()
.size(size)
.words(data)
.padding(5)
.rotate(fRotation)
.font('serif')
.fontSize(d => scale(d.size))
.on('end', draw);

layout.start();
layout.on('end', draw).start();
}

wordCloud.propTypes = propTypes;

function adaptor(slice, payload) {
const { selector, formData } = slice;
const {
rotation,
size_to: sizeTo,
size_from: sizeFrom,
color_scheme: colorScheme,
} = formData;
const element = document.querySelector(selector);

return wordCloud(element, {
data: payload.data,
width: slice.width(),
height: slice.height(),
rotation,
sizeRange: [sizeFrom, sizeTo],
colorScheme,
});
}

module.exports = wordCloudChart;
export default adaptor;

0 comments on commit 0a40149

Please sign in to comment.