From 7de3a7dd6db641503f776b6f6197055815b00a9b Mon Sep 17 00:00:00 2001 From: Krist Wongsuphasawat Date: Tue, 21 Aug 2018 20:50:01 -0700 Subject: [PATCH] Repair and refactor Word Cloud (#5669) * 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 --- superset/assets/src/explore/controls.jsx | 5 +- superset/assets/src/explore/visTypes.jsx | 2 +- .../assets/src/visualizations/word_cloud.js | 136 +++++++++++------- 3 files changed, 93 insertions(+), 50 deletions(-) diff --git a/superset/assets/src/explore/controls.jsx b/superset/assets/src/explore/controls.jsx index 8fa36b2d19b55..f2f12e03080f2 100644 --- a/superset/assets/src/explore/controls.jsx +++ b/superset/assets/src/explore/controls.jsx @@ -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'), }, @@ -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'), }, @@ -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'), }, diff --git a/superset/assets/src/explore/visTypes.jsx b/superset/assets/src/explore/visTypes.jsx index d499c7a88d443..2686b2d345347 100644 --- a/superset/assets/src/explore/visTypes.jsx +++ b/superset/assets/src/explore/visTypes.jsx @@ -1042,9 +1042,9 @@ export const visTypes = { label: t('Query'), expanded: true, controlSetRows: [ + ['series'], ['metric'], ['adhoc_filters'], - ['series'], ['row_limit', null], ], }, diff --git a/superset/assets/src/visualizations/word_cloud.js b/superset/assets/src/visualizations/word_cloud.js index f09c16ecd3898..6fdd96237e1fa 100644 --- a/superset/assets/src/visualizations/word_cloud.js +++ b/superset/assets/src/visualizations/word_cloud.js @@ -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;