UNPKG

light-chart

Version:

Charts for mobile visualization.

229 lines (204 loc) 5.8 kB
const Util = require('../../util/common'); const Shape = require('../shape'); let textWidthCacheCounter = 0; let textWidthCache = {}; const TEXT_CACHE_MAX = 5000; class Text extends Shape { _initProperties() { super._initProperties(); this._attrs.canFill = true; this._attrs.canStroke = true; this._attrs.type = 'text'; } getDefaultAttrs() { return { lineWidth: 0, lineCount: 1, fontSize: 12, fontFamily: 'sans-serif', fontStyle: 'normal', fontWeight: 'normal', fontVariant: 'normal', textAlign: 'start', textBaseline: 'bottom', lineHeight: null, textArr: null }; } _getFontStyle() { const attrs = this._attrs.attrs; const { fontSize, fontFamily, fontWeight, fontStyle, fontVariant } = attrs; return `${fontStyle} ${fontVariant} ${fontWeight} ${fontSize}px ${fontFamily}`; } _afterAttrsSet() { const attrs = this._attrs.attrs; attrs.font = this._getFontStyle(); if (attrs.text) { const text = attrs.text; let textArr = null; let lineCount = 1; if (Util.isString(text) && (text.indexOf('\n') !== -1)) { textArr = text.split('\n'); lineCount = textArr.length; } attrs.lineCount = lineCount; attrs.textArr = textArr; } this.set('attrs', attrs); } _getTextHeight() { const attrs = this._attrs.attrs; if (attrs.height) { return attrs.height; } const lineCount = attrs.lineCount; const fontSize = attrs.fontSize * 1; if (lineCount > 1) { const spaceingY = this._getSpaceingY(); return fontSize * lineCount + spaceingY * (lineCount - 1); } return fontSize; } _getSpaceingY() { const attrs = this._attrs.attrs; const lineHeight = attrs.lineHeight; const fontSize = attrs.fontSize * 1; return lineHeight ? (lineHeight - fontSize) : fontSize * 0.14; } drawInner(context) { const self = this; const attrs = self._attrs.attrs; const text = attrs.text; let x = attrs.x; let y = attrs.y; if (Util.isNil(text) || isNaN(x) || isNaN(y)) { // text will be 0 return; } const textArr = attrs.textArr; const fontSize = attrs.fontSize * 1; const spaceingY = self._getSpaceingY(); if (attrs.rotate) { // do rotation context.translate(x, y); context.rotate(attrs.rotate); x = 0; y = 0; } const textBaseline = attrs.textBaseline; let height; if (textArr) { height = self._getTextHeight(); } let subY; // context.beginPath(); if (self.hasFill()) { const fillOpacity = attrs.fillOpacity; if (!Util.isNil(fillOpacity) && fillOpacity !== 1) { context.globalAlpha = fillOpacity; } if (textArr) { for (let i = 0, len = textArr.length; i < len; i++) { const subText = textArr[i]; subY = y + i * (spaceingY + fontSize) - height + fontSize; // bottom; if (textBaseline === 'middle') { subY += height - fontSize - (height - fontSize) / 2; } if (textBaseline === 'top') { subY += height - fontSize; } context.fillText(subText, x, subY); } } else { context.fillText(text, x, y); } } if (self.hasStroke()) { if (textArr) { for (let i = 0, len = textArr.length; i < len; i++) { const subText = textArr[i]; subY = y + i * (spaceingY + fontSize) - height + fontSize; // bottom; if (textBaseline === 'middle') { subY += height - fontSize - (height - fontSize) / 2; } if (textBaseline === 'top') { subY += height - fontSize; } context.strokeText(subText, x, subY); } } else { context.strokeText(text, x, y); } } } calculateBox() { const self = this; const attrs = self._attrs.attrs; const { x, y, textAlign, textBaseline } = attrs; const width = self._getTextWidth(); // attrs.width if (!width) { return { minX: x, minY: y, maxX: x, maxY: y }; } const height = self._getTextHeight(); // attrs.height const point = { x, y: y - height }; // default textAlign: start, textBaseline: bottom if (textAlign) { if (textAlign === 'end' || textAlign === 'right') { point.x -= width; } else if (textAlign === 'center') { point.x -= width / 2; } } if (textBaseline) { if (textBaseline === 'top') { point.y += height; } else if (textBaseline === 'middle') { point.y += height / 2; } } return { minX: point.x, minY: point.y, maxX: point.x + width, maxY: point.y + height }; } _getTextWidth() { const attrs = this._attrs.attrs; if (attrs.width) { return attrs.width; } const text = attrs.text; const context = this.get('context'); if (Util.isNil(text)) return undefined; const font = attrs.font; const textArr = attrs.textArr; const key = text + '' + font; if (textWidthCache[key]) { return textWidthCache[key]; } let width = 0; if (textArr) { for (let i = 0, length = textArr.length; i < length; i++) { const subText = textArr[i]; width = Math.max(width, Util.measureText(subText, font, context).width); } } else { width = Util.measureText(text, font, context).width; } if (textWidthCacheCounter > TEXT_CACHE_MAX) { textWidthCacheCounter = 0; textWidthCache = {}; } textWidthCacheCounter++; textWidthCache[key] = width; return width; } } Shape.Text = Text; module.exports = Text;