@visactor/vtable
Version:
canvas table width high performance
164 lines (149 loc) • 7.24 kB
JavaScript
import { DefaultTextStyle, getTextBounds, DefaultTextMeasureContribution, TextMeasureContribution, ContainerModule, container, Text } from "./../../vrender";
import { isValid, TextMeasure } from "@visactor/vutils";
let customAlphabetCharSet = "", textMeasureMode = "quick";
const textMeasureModule = new ContainerModule(((bind, unbind, isBound, rebind) => {
isBound(TextMeasureContribution) ? rebind(TextMeasureContribution).to(FastTextMeasureContribution).inSingletonScope() : bind(TextMeasureContribution).to(FastTextMeasureContribution).inSingletonScope();
})), restoreTextMeasureModule = new ContainerModule(((bind, unbind, isBound, rebind) => {
isBound(TextMeasureContribution) ? rebind(TextMeasureContribution).to(DefaultTextMeasureContribution).inSingletonScope() : bind(TextMeasureContribution).to(DefaultTextMeasureContribution).inSingletonScope();
}));
export default textMeasureModule;
export const initTextMeasure = (textSpec, option, useNaiveCanvas) => new TextMeasure(Object.assign({
defaultFontParams: {
fontFamily: DefaultTextStyle.fontFamily,
fontSize: DefaultTextStyle.fontSize
},
getTextBounds: useNaiveCanvas ? void 0 : getTextBounds,
specialCharSet: `{}()//&-/: .,@%'"~…=——${TextMeasure.ALPHABET_CHAR_SET}${TextMeasure.ALPHABET_CHAR_SET.toUpperCase()}0123456789${customAlphabetCharSet}`
}, null != option ? option : {}), textSpec);
const fastTextMeasureCache = new Map;
function getFastTextMeasure(fontSize, fontWeight, fontFamily, fontStyle = "normal") {
const key = `${fontSize}-${fontWeight}-${fontFamily}-${fontStyle}`, cache = fastTextMeasureCache.get(key);
if (cache) return cache;
const fastTextMeasure = (textSpec = {
fontSize: fontSize,
fontFamily: fontFamily,
fontWeight: fontWeight,
fontStyle: fontStyle
}, new TextMeasure(Object.assign({
defaultFontParams: {
fontFamily: DefaultTextStyle.fontFamily,
fontSize: DefaultTextStyle.fontSize
},
getTextBounds: useNaiveCanvas ? void 0 : getTextBounds,
specialCharSet: `{}()//&-/: .,@%'"~…=——${TextMeasure.ALPHABET_CHAR_SET}${TextMeasure.ALPHABET_CHAR_SET.toUpperCase()}0123456789${customAlphabetCharSet}`
}, null != option ? option : {}), textSpec));
var textSpec, option, useNaiveCanvas;
return fastTextMeasureCache.set(key, fastTextMeasure), fastTextMeasure;
}
export class FastTextMeasureContribution extends DefaultTextMeasureContribution {
_fastMeasure(text, options) {
const {fontSize: fontSize, fontFamily: fontFamily = "Arial,sans-serif", fontWeight: fontWeight = "normal", fontStyle: fontStyle = "normal"} = options, textMeasure = getFastTextMeasure(fontSize, fontWeight, fontFamily, fontStyle).measure(text, textMeasureMode);
if (!isValid(textMeasure.fontBoundingBoxAscent) && !isValid(textMeasure.fontBoundingBoxDescent)) {
const {ascent: ascent, descent: descent} = this.measureTextBoundADscentEstimate(options);
textMeasure.fontBoundingBoxAscent = ascent, textMeasure.fontBoundingBoxDescent = descent;
}
return textMeasure;
}
measureTextWidth(text, options) {
return this._fastMeasure(text, options).width;
}
measureText(text, options) {
return this._fastMeasure(text, options);
}
_measureTextWithoutAlignBaseline(text, options, compatible) {
return this._fastMeasure(text, options);
}
_measureTextWithAlignBaseline(text, options, compatible) {
return this._fastMeasure(text, options);
}
}
export class TextMeasureTool {
measureText(text, options) {
const {fontSize: fontSize, fontFamily: fontFamily = "Arial,sans-serif", fontWeight: fontWeight = "normal", fontStyle: fontStyle = "normal"} = options;
return getFastTextMeasure(fontSize, fontWeight, fontFamily, fontStyle).measure(text, textMeasureMode);
}
measureTextWidth(text, options) {
const {fontSize: fontSize, fontFamily: fontFamily = "Arial,sans-serif", fontWeight: fontWeight = "normal", fontStyle: fontStyle = "normal"} = options;
return getFastTextMeasure(fontSize, fontWeight, fontFamily, fontStyle).measure(text, textMeasureMode).width;
}
clipText(text, options, width) {
if (0 === text.length) return {
str: "",
width: 0
};
let length = this.measureTextWidth(text, options);
return length <= width ? {
str: text,
width: length
} : (length = this.measureTextWidth(text[0], options), length > width ? {
str: "",
width: 0
} : this._clipText(text, options, width, 0, text.length - 1));
}
_clipText(text, options, width, leftIdx, rightIdx) {
const middleIdx = Math.floor((leftIdx + rightIdx) / 2), subText = text.substring(0, middleIdx + 1), strWidth = this.measureTextWidth(subText, options);
let length;
if (strWidth > width) {
if (subText.length <= 1) return {
str: "",
width: 0
};
const str = text.substring(0, middleIdx);
return length = this.measureTextWidth(str, options), length <= width ? {
str: str,
width: length
} : this._clipText(text, options, width, leftIdx, middleIdx);
}
if (strWidth < width) {
if (middleIdx >= text.length - 1) return {
str: text,
width: this.measureTextWidth(text, options)
};
const str = text.substring(0, middleIdx + 2);
return length = this.measureTextWidth(str, options), length >= width ? {
str: subText,
width: strWidth
} : this._clipText(text, options, width, middleIdx, rightIdx);
}
return {
str: subText,
width: strWidth
};
}
clipTextWithSuffix(text, options, width, suffix) {
if ("" === suffix) return this.clipText(text, options, width);
if (0 === text.length) return {
str: "",
width: 0
};
const length = this.measureTextWidth(text, options);
if (length <= width) return {
str: text,
width: length
};
const suffixWidth = this.measureTextWidth(suffix, options);
if (suffixWidth > width) return {
str: "",
width: 0
};
width -= suffixWidth;
const data = this._clipText(text, options, width, 0, text.length - 1);
return data.str += suffix, data.width += suffixWidth, data;
}
}
export const textMeasure = new TextMeasureTool;
export function setCustomAlphabetCharSet(str) {
customAlphabetCharSet = str, fastTextMeasureCache.clear();
}
export function restoreMeasureText() {
textMeasureMode = "canvas", container.load(restoreTextMeasureModule);
}
const utilTextMark = new Text({
ignoreBuf: !0
});
export function measureTextBounds(attribute) {
return utilTextMark.initAttributes(Object.assign(Object.assign({}, attribute), {
ignoreBuf: !0
})), utilTextMark.AABBBounds;
}
//# sourceMappingURL=text-measure.js.map