171 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
		
			
		
	
	
			171 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
| 
								 | 
							
								import BoundingRect from '../core/BoundingRect.js';
							 | 
						||
| 
								 | 
							
								import LRU from '../core/LRU.js';
							 | 
						||
| 
								 | 
							
								import { DEFAULT_FONT, platformApi } from '../core/platform.js';
							 | 
						||
| 
								 | 
							
								var textWidthCache = {};
							 | 
						||
| 
								 | 
							
								export function getWidth(text, font) {
							 | 
						||
| 
								 | 
							
								    font = font || DEFAULT_FONT;
							 | 
						||
| 
								 | 
							
								    var cacheOfFont = textWidthCache[font];
							 | 
						||
| 
								 | 
							
								    if (!cacheOfFont) {
							 | 
						||
| 
								 | 
							
								        cacheOfFont = textWidthCache[font] = new LRU(500);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    var width = cacheOfFont.get(text);
							 | 
						||
| 
								 | 
							
								    if (width == null) {
							 | 
						||
| 
								 | 
							
								        width = platformApi.measureText(text, font).width;
							 | 
						||
| 
								 | 
							
								        cacheOfFont.put(text, width);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return width;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								export function innerGetBoundingRect(text, font, textAlign, textBaseline) {
							 | 
						||
| 
								 | 
							
								    var width = getWidth(text, font);
							 | 
						||
| 
								 | 
							
								    var height = getLineHeight(font);
							 | 
						||
| 
								 | 
							
								    var x = adjustTextX(0, width, textAlign);
							 | 
						||
| 
								 | 
							
								    var y = adjustTextY(0, height, textBaseline);
							 | 
						||
| 
								 | 
							
								    var rect = new BoundingRect(x, y, width, height);
							 | 
						||
| 
								 | 
							
								    return rect;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								export function getBoundingRect(text, font, textAlign, textBaseline) {
							 | 
						||
| 
								 | 
							
								    var textLines = ((text || '') + '').split('\n');
							 | 
						||
| 
								 | 
							
								    var len = textLines.length;
							 | 
						||
| 
								 | 
							
								    if (len === 1) {
							 | 
						||
| 
								 | 
							
								        return innerGetBoundingRect(textLines[0], font, textAlign, textBaseline);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								        var uniondRect = new BoundingRect(0, 0, 0, 0);
							 | 
						||
| 
								 | 
							
								        for (var i = 0; i < textLines.length; i++) {
							 | 
						||
| 
								 | 
							
								            var rect = innerGetBoundingRect(textLines[i], font, textAlign, textBaseline);
							 | 
						||
| 
								 | 
							
								            i === 0 ? uniondRect.copy(rect) : uniondRect.union(rect);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return uniondRect;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								export function adjustTextX(x, width, textAlign) {
							 | 
						||
| 
								 | 
							
								    if (textAlign === 'right') {
							 | 
						||
| 
								 | 
							
								        x -= width;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else if (textAlign === 'center') {
							 | 
						||
| 
								 | 
							
								        x -= width / 2;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return x;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								export function adjustTextY(y, height, verticalAlign) {
							 | 
						||
| 
								 | 
							
								    if (verticalAlign === 'middle') {
							 | 
						||
| 
								 | 
							
								        y -= height / 2;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else if (verticalAlign === 'bottom') {
							 | 
						||
| 
								 | 
							
								        y -= height;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return y;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								export function getLineHeight(font) {
							 | 
						||
| 
								 | 
							
								    return getWidth('国', font);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								export function measureText(text, font) {
							 | 
						||
| 
								 | 
							
								    return platformApi.measureText(text, font);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								export function parsePercent(value, maxValue) {
							 | 
						||
| 
								 | 
							
								    if (typeof value === 'string') {
							 | 
						||
| 
								 | 
							
								        if (value.lastIndexOf('%') >= 0) {
							 | 
						||
| 
								 | 
							
								            return parseFloat(value) / 100 * maxValue;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return parseFloat(value);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return value;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								export function calculateTextPosition(out, opts, rect) {
							 | 
						||
| 
								 | 
							
								    var textPosition = opts.position || 'inside';
							 | 
						||
| 
								 | 
							
								    var distance = opts.distance != null ? opts.distance : 5;
							 | 
						||
| 
								 | 
							
								    var height = rect.height;
							 | 
						||
| 
								 | 
							
								    var width = rect.width;
							 | 
						||
| 
								 | 
							
								    var halfHeight = height / 2;
							 | 
						||
| 
								 | 
							
								    var x = rect.x;
							 | 
						||
| 
								 | 
							
								    var y = rect.y;
							 | 
						||
| 
								 | 
							
								    var textAlign = 'left';
							 | 
						||
| 
								 | 
							
								    var textVerticalAlign = 'top';
							 | 
						||
| 
								 | 
							
								    if (textPosition instanceof Array) {
							 | 
						||
| 
								 | 
							
								        x += parsePercent(textPosition[0], rect.width);
							 | 
						||
| 
								 | 
							
								        y += parsePercent(textPosition[1], rect.height);
							 | 
						||
| 
								 | 
							
								        textAlign = null;
							 | 
						||
| 
								 | 
							
								        textVerticalAlign = null;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								        switch (textPosition) {
							 | 
						||
| 
								 | 
							
								            case 'left':
							 | 
						||
| 
								 | 
							
								                x -= distance;
							 | 
						||
| 
								 | 
							
								                y += halfHeight;
							 | 
						||
| 
								 | 
							
								                textAlign = 'right';
							 | 
						||
| 
								 | 
							
								                textVerticalAlign = 'middle';
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            case 'right':
							 | 
						||
| 
								 | 
							
								                x += distance + width;
							 | 
						||
| 
								 | 
							
								                y += halfHeight;
							 | 
						||
| 
								 | 
							
								                textVerticalAlign = 'middle';
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            case 'top':
							 | 
						||
| 
								 | 
							
								                x += width / 2;
							 | 
						||
| 
								 | 
							
								                y -= distance;
							 | 
						||
| 
								 | 
							
								                textAlign = 'center';
							 | 
						||
| 
								 | 
							
								                textVerticalAlign = 'bottom';
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            case 'bottom':
							 | 
						||
| 
								 | 
							
								                x += width / 2;
							 | 
						||
| 
								 | 
							
								                y += height + distance;
							 | 
						||
| 
								 | 
							
								                textAlign = 'center';
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            case 'inside':
							 | 
						||
| 
								 | 
							
								                x += width / 2;
							 | 
						||
| 
								 | 
							
								                y += halfHeight;
							 | 
						||
| 
								 | 
							
								                textAlign = 'center';
							 | 
						||
| 
								 | 
							
								                textVerticalAlign = 'middle';
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            case 'insideLeft':
							 | 
						||
| 
								 | 
							
								                x += distance;
							 | 
						||
| 
								 | 
							
								                y += halfHeight;
							 | 
						||
| 
								 | 
							
								                textVerticalAlign = 'middle';
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            case 'insideRight':
							 | 
						||
| 
								 | 
							
								                x += width - distance;
							 | 
						||
| 
								 | 
							
								                y += halfHeight;
							 | 
						||
| 
								 | 
							
								                textAlign = 'right';
							 | 
						||
| 
								 | 
							
								                textVerticalAlign = 'middle';
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            case 'insideTop':
							 | 
						||
| 
								 | 
							
								                x += width / 2;
							 | 
						||
| 
								 | 
							
								                y += distance;
							 | 
						||
| 
								 | 
							
								                textAlign = 'center';
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            case 'insideBottom':
							 | 
						||
| 
								 | 
							
								                x += width / 2;
							 | 
						||
| 
								 | 
							
								                y += height - distance;
							 | 
						||
| 
								 | 
							
								                textAlign = 'center';
							 | 
						||
| 
								 | 
							
								                textVerticalAlign = 'bottom';
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            case 'insideTopLeft':
							 | 
						||
| 
								 | 
							
								                x += distance;
							 | 
						||
| 
								 | 
							
								                y += distance;
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            case 'insideTopRight':
							 | 
						||
| 
								 | 
							
								                x += width - distance;
							 | 
						||
| 
								 | 
							
								                y += distance;
							 | 
						||
| 
								 | 
							
								                textAlign = 'right';
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            case 'insideBottomLeft':
							 | 
						||
| 
								 | 
							
								                x += distance;
							 | 
						||
| 
								 | 
							
								                y += height - distance;
							 | 
						||
| 
								 | 
							
								                textVerticalAlign = 'bottom';
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            case 'insideBottomRight':
							 | 
						||
| 
								 | 
							
								                x += width - distance;
							 | 
						||
| 
								 | 
							
								                y += height - distance;
							 | 
						||
| 
								 | 
							
								                textAlign = 'right';
							 | 
						||
| 
								 | 
							
								                textVerticalAlign = 'bottom';
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    out = out || {};
							 | 
						||
| 
								 | 
							
								    out.x = x;
							 | 
						||
| 
								 | 
							
								    out.y = y;
							 | 
						||
| 
								 | 
							
								    out.align = textAlign;
							 | 
						||
| 
								 | 
							
								    out.verticalAlign = textVerticalAlign;
							 | 
						||
| 
								 | 
							
								    return out;
							 | 
						||
| 
								 | 
							
								}
							 |