@visactor/vgrammar-wordcloud
Version:
WordCloud layout transform for VGrammar
65 lines (60 loc) • 3.11 kB
JavaScript
import { getTextBounds } from "@visactor/vrender-core";
import { BaseLayout } from "./base";
import { merge } from "@visactor/vutils";
export class FastLayout extends BaseLayout {
constructor(options) {
super(merge({}, FastLayout.defaultOptions, options)), this.random = this.options.random ? Math.random : () => 0,
this.aspectRatio = 1;
}
fit(word) {
for (let i = 0, len = this.result.length; i < len; i++) if (isOverlap(word, this.result[i])) return !1;
return !0;
}
getTextInfo(datum, index) {
const info = {
datum: datum,
fontSize: this.getTextFontSize(datum),
fontWeight: this.getTextFontWeight(datum),
fontStyle: this.getTextFontStyle(datum),
fontFamily: this.getTextFontFamily(datum),
angle: this.getTextRotate(datum, index),
text: this.getText(datum) + "",
x: this.center[0],
y: this.center[1]
}, bounds = getTextBounds(info);
return info.width = bounds.width(), info.height = bounds.height(), info.top = this.center[1] - info.height + .21 * info.height,
info.left = this.center[0] - info.width / 2, info;
}
layoutWord(index) {
const info = this.getTextInfo(this.data[index], index);
let angle = 2 * Math.PI, radius = 0, left = info.left, top = info.top;
const width = info.width, height = info.height;
let rx = 1, isFit = this.fit(info);
for (;!isFit && radius < this.maxRadius; ) radius += .5, rx = this.shape(radius / this.maxRadius * 2 * Math.PI),
angle += .5 * (this.options.random ? this.random() > .5 ? 1 : -1 : index % 2 == 0 ? 1 : -1),
left = this.center[0] - width / 2 + radius * rx * Math.cos(angle) * this.aspectRatio,
top = this.center[1] - height / 2 + radius * rx * Math.sin(angle), info.left = left,
info.top = top, info.x = left + width / 2, info.y = top + height / 2, isFit = this.fit(info);
return !!isFit && (!!(this.options.clip || info.left >= 0 && info.left + info.width <= this.width && info.top >= 0 && info.top + info.height <= this.height) && (this.result.push(info),
!0));
}
layout(data, config) {
if (!(null == data ? void 0 : data.length)) return [];
this.initProgressive(), this.result = [], this.maxRadius = Math.sqrt(config.width * config.width + config.height * config.height) / 2,
this.center = [ config.width / 2, config.height / 2 ], this.width = config.width,
this.height = config.height, this.data = data.sort(((a, b) => this.getTextFontSize(b) - this.getTextFontSize(a)));
let i = 0;
for (;i < data.length; ) {
this.layoutWord(i);
if (i++, this.progressiveIndex = i, this.exceedTime()) break;
}
return this.result;
}
}
function isOverlap(a, b) {
return !(a.left + a.width < b.left || a.top + a.height < b.top || a.left > b.left + b.width || a.top > b.top + b.height);
}
//# sourceMappingURL=fast-layout.js.map
FastLayout.defaultOptions = {
enlarge: !1
};