mstr-viz
Version:
A new dev tool for creating custom visualizations
119 lines (106 loc) • 3.92 kB
JavaScript
import * as d3 from 'd3';
import cloud from 'd3-cloud';
// mojo module
mstrmojo.requiresCls('mstrmojo.CustomVisBase');
const { GraphicModel } = mstrmojo.customviz;
const { ENUM_RAW_DATA_FORMAT } = mstrmojo.models.template.DataInterface;
mstrmojo.plugins.<%= pluginName %>.<%= pluginName %> = mstrmojo.declare(
mstrmojo.CustomVisBase,
null,
{
scriptClass: 'mstrmojo.plugins.<%= pluginName %>.<%= pluginName %>',
cssClass: '<% print(_.toLower(pluginName)) %>',
errorMessage: 'Either there is not enough data to display the visualization or the visualization configuration is incomplete.',
errorDetails: 'This visualization requires one or more attributes and one metric.',
useRichTooltip: false,
reuseDOMNode: false,
draggable: false,
supportNEE: true,
init(props) {
this._super(props);
this.setDefaultPropertyValues({
minFont: 10,
maxFont: 70,
numOfWords: 200,
spiral: { ellipse: 'true', rectangular: 'false' },
textFont: { fontFamily: 'Arial' },
});
},
createGraphicModels() {
const rawData = this.dataInterface.getRawData(ENUM_RAW_DATA_FORMAT.ROWS_ADV, {
hasSelection: true,
hasTitleName: true,
hasThreshold: true,
additionalAttrIds: this.additionalAttrIds,
});
return rawData.map(row => {
const { values, headers } = row;
const graphicModel = new GraphicModel();
graphicModel.idValueMapping = row.idValueMapping;
graphicModel.setCustomProperties({
text: headers[0].name,
value: values[0].rv,
});
graphicModel.setId(this.getSelectorHash(row.metricSelector));
graphicModel.setSelector(row.metricSelector, true);
return graphicModel;
});
},
plot() {
const graphicModels = this.getGraphicModels();
if (graphicModels.length === 0) {
return;
}
const minFont = this.getProperty('minFont');
const maxFont = this.getProperty('maxFont');
const numOfWords = this.getProperty('numOfWords');
const spiral = this.getProperty('spiral');
const textFont = this.getProperty('textFont');
let data = graphicModels
.sort((a, b) => b.value - a.value)
.slice(0, Math.max(graphicModels.length, numOfWords));
const scaleFont = d3.scaleLinear()
.domain([data[0].value, data[data.length - 1].value])
.range([maxFont, minFont]);
const width = parseInt(this.width, 10);
const height = parseInt(this.height, 10);
const container = d3.select(this.domNode);
data = data.map(d => ({ ...d, size: scaleFont(d.value) }));
cloud()
.size([width, height])
.timeInterval(1000)
.words(data)
.padding(1)
.font(textFont.fontFamily)
.fontSize(d => d.size)
.spiral(spiral.ellipse === 'true' ? 'archimedean' : 'rectangular')
.on('end', words => {
const hashStr2Color = str => {
let num = 0;
for (let i = 0; i < str.length; i++) {
num += str.charCodeAt(i);
}
return d3.schemePaired[num % d3.schemePaired.length];
};
container
.html(null)
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', `translate(${width / 2},${height / 2})`)
.selectAll('text')
.data(words)
.enter()
.append('text')
.style('font-size', d => `${d.size}px`)
.style('font-family', textFont.fontFamily)
.style('fill', d => hashStr2Color(d.text))
.attr('text-anchor', 'middle')
.attr('transform', d => `translate(${[d.x, d.y]})rotate(${d.rotate})`)
.text(d => d.text);
})
.start();
},
},
);