@visactor/vgrammar-wordcloud
Version:
WordCloud layout transform for VGrammar
102 lines (94 loc) • 5.18 kB
JavaScript
import { CloudLayout } from "./cloud-layout";
import { isFunction, isNumber, isString, toNumber, Logger, isArray } from "@visactor/vutils";
import { GridLayout } from "./grid-layout";
import { FastLayout } from "./fast-layout";
const OUTPUT = {
x: "x",
y: "y",
z: "z",
fontFamily: "fontFamily",
fontSize: "fontSize",
fontStyle: "fontStyle",
fontWeight: "fontWeight",
angle: "angle"
};
export const transform = (options, upstreamData) => {
var _a, _b, _c, _d, _e, _f;
if (options.size && (options.size[0] <= 0 || options.size[1] <= 0)) {
return Logger.getInstance().info("Wordcloud size dimensions must be greater than 0"),
[];
}
const data = upstreamData, canvasSize = (null !== (_a = options.size) && void 0 !== _a ? _a : [ 500, 500 ]).slice();
canvasSize[0] = Math.floor(canvasSize[0]), canvasSize[1] = Math.floor(canvasSize[1]);
const fontFamily = options.fontFamily ? field(options.fontFamily) : "sans-serif", fontStyle = options.fontStyle ? field(options.fontStyle) : "normal", fontWeight = options.fontWeight ? field(options.fontWeight) : "normal", rotate = options.rotate ? field(options.rotate) : 0, text = field(options.text), spiral = null !== (_b = options.spiral) && void 0 !== _b ? _b : "archimedean", padding = options.padding ? field(options.padding) : 1, shape = null !== (_c = options.shape) && void 0 !== _c ? _c : "square", shrink = null !== (_d = options.shrink) && void 0 !== _d && _d, enlarge = null !== (_e = options.enlarge) && void 0 !== _e && _e, clip = null !== (_f = options.clip) && void 0 !== _f && _f, minFontSize = options.minFontSize, randomVisible = options.randomVisible, as = options.as ? Object.assign(Object.assign({}, OUTPUT), options.as) : OUTPUT, depth_3d = options.depth_3d, postProjection = options.postProjection;
let fontSize = options.fontSize ? field(options.fontSize) : 14;
const fontSizeRange = options.fontSizeRange;
if (fontSizeRange && !isNumber(fontSize)) {
const fsize = fontSize, fontSizeSqrtScale = generateScale(extent(fsize, data), fontSizeRange);
fontSize = datum => fontSizeSqrtScale(fsize(datum));
}
let Layout = CloudLayout;
"fast" === options.layoutType ? Layout = FastLayout : "grid" === options.layoutType && (Layout = GridLayout);
const layout = new Layout(Object.assign(Object.assign({}, options), {
text: text,
padding: padding,
spiral: spiral,
shape: shape,
rotate: rotate,
fontFamily: fontFamily,
fontStyle: fontStyle,
fontWeight: fontWeight,
fontSize: fontSize,
shrink: shrink,
clip: clip,
enlarge: enlarge,
minFontSize: minFontSize,
random: randomVisible,
outputCallback: words => {
const res = [];
let t, w;
for (let i = 0, len = words.length; i < len; i++) w = words[i], t = w.datum, t[as.x] = w.x,
t[as.y] = w.y, t[as.fontFamily] = w.fontFamily, t[as.fontSize] = w.fontSize, t[as.fontStyle] = w.fontStyle,
t[as.fontWeight] = w.fontWeight, t[as.angle] = w.angle, "StereographicProjection" === postProjection && stereographicProjection(canvasSize, w, t, as, depth_3d),
options.dataIndexKey && (t[options.dataIndexKey] = `${i}`), res.push(t);
return res;
}
}));
return layout.layout(data, {
width: canvasSize[0],
height: canvasSize[1]
}), options.progressiveStep > 0 || options.progressiveTime > 0 ? {
progressive: layout
} : layout.output();
};
const field = option => isString(option) || isNumber(option) || isFunction(option) || isArray(option) ? option : datum => datum[option.field], sqrt = x => x < 0 ? -Math.sqrt(-x) : Math.sqrt(x), generateScale = (domain, range, type) => {
if (domain[0] === domain[1]) return datum => range[0];
const s0 = sqrt(domain[0]), s1 = sqrt(domain[1]), min = Math.min(s0, s1), max = Math.max(s0, s1);
return datum => (sqrt(datum) - min) / (max - min) * (range[1] - range[0]) + range[0];
}, extent = (field, data) => {
let min = 1 / 0, max = -1 / 0;
const n = data.length;
let v;
for (let i = 0; i < n; ++i) v = toNumber(field(data[i])), v < min && (min = v),
v > max && (max = v);
return 1 === data.length && min === max && (min -= 1e4), [ min, max ];
};
function stereographicProjection(canvasSize, w, t, as, depth_3d) {
const r = Math.max(canvasSize[0], canvasSize[1]) / 2, out = _StereographicProjection(canvasSize[0], canvasSize[1], r, {
x: r,
y: r,
z: null != depth_3d ? depth_3d : r
}, w);
t[as.x] = out.x, t[as.y] = out.y, t[as.z] = out.z;
}
function _StereographicProjection(w, h, r, center, word) {
const {x: x, y: y} = word, theta = x / w * Math.PI * 2;
let phi = Math.PI - y / h * Math.PI;
phi += (phi < Math.PI / 2 ? 1 : -1) * Math.pow(Math.min(phi - Math.PI / 2, 1), 2) / 5;
return {
x: r * Math.sin(phi) * Math.cos(theta) + center.x,
y: r * Math.cos(phi) + center.y,
z: r * Math.sin(phi) * Math.sin(theta) + center.z
};
}
//# sourceMappingURL=wordcloud.js.map