echarts symbol 源码
echarts symbol 代码
文件路径:/src/util/symbol.ts
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
// Symbol factory
import { each, isArray, retrieve2 } from 'zrender/src/core/util';
import * as graphic from './graphic';
import BoundingRect from 'zrender/src/core/BoundingRect';
import { calculateTextPosition } from 'zrender/src/contain/text';
import { Dictionary } from 'zrender/src/core/types';
import { SymbolOptionMixin, ZRColor } from './types';
import { parsePercent } from './number';
export type ECSymbol = graphic.Path & {
__isEmptyBrush?: boolean
setColor: (color: ZRColor, innerColor?: ZRColor) => void
getColor: () => ZRColor
};
type SymbolCtor = { new(): ECSymbol };
type SymbolShapeMaker = (x: number, y: number, w: number, h: number, shape: Dictionary<any>) => void;
/**
* Triangle shape
* @inner
*/
const Triangle = graphic.Path.extend({
type: 'triangle',
shape: {
cx: 0,
cy: 0,
width: 0,
height: 0
},
buildPath: function (path, shape) {
const cx = shape.cx;
const cy = shape.cy;
const width = shape.width / 2;
const height = shape.height / 2;
path.moveTo(cx, cy - height);
path.lineTo(cx + width, cy + height);
path.lineTo(cx - width, cy + height);
path.closePath();
}
});
/**
* Diamond shape
* @inner
*/
const Diamond = graphic.Path.extend({
type: 'diamond',
shape: {
cx: 0,
cy: 0,
width: 0,
height: 0
},
buildPath: function (path, shape) {
const cx = shape.cx;
const cy = shape.cy;
const width = shape.width / 2;
const height = shape.height / 2;
path.moveTo(cx, cy - height);
path.lineTo(cx + width, cy);
path.lineTo(cx, cy + height);
path.lineTo(cx - width, cy);
path.closePath();
}
});
/**
* Pin shape
* @inner
*/
const Pin = graphic.Path.extend({
type: 'pin',
shape: {
// x, y on the cusp
x: 0,
y: 0,
width: 0,
height: 0
},
buildPath: function (path, shape) {
const x = shape.x;
const y = shape.y;
const w = shape.width / 5 * 3;
// Height must be larger than width
const h = Math.max(w, shape.height);
const r = w / 2;
// Dist on y with tangent point and circle center
const dy = r * r / (h - r);
const cy = y - h + r + dy;
const angle = Math.asin(dy / r);
// Dist on x with tangent point and circle center
const dx = Math.cos(angle) * r;
const tanX = Math.sin(angle);
const tanY = Math.cos(angle);
const cpLen = r * 0.6;
const cpLen2 = r * 0.7;
path.moveTo(x - dx, cy + dy);
path.arc(
x, cy, r,
Math.PI - angle,
Math.PI * 2 + angle
);
path.bezierCurveTo(
x + dx - tanX * cpLen, cy + dy + tanY * cpLen,
x, y - cpLen2,
x, y
);
path.bezierCurveTo(
x, y - cpLen2,
x - dx + tanX * cpLen, cy + dy + tanY * cpLen,
x - dx, cy + dy
);
path.closePath();
}
});
/**
* Arrow shape
* @inner
*/
const Arrow = graphic.Path.extend({
type: 'arrow',
shape: {
x: 0,
y: 0,
width: 0,
height: 0
},
buildPath: function (ctx, shape) {
const height = shape.height;
const width = shape.width;
const x = shape.x;
const y = shape.y;
const dx = width / 3 * 2;
ctx.moveTo(x, y);
ctx.lineTo(x + dx, y + height);
ctx.lineTo(x, y + height / 4 * 3);
ctx.lineTo(x - dx, y + height);
ctx.lineTo(x, y);
ctx.closePath();
}
});
/**
* Map of path contructors
*/
// TODO Use function to build symbol path.
const symbolCtors: Dictionary<SymbolCtor> = {
line: graphic.Line as unknown as SymbolCtor,
rect: graphic.Rect as unknown as SymbolCtor,
roundRect: graphic.Rect as unknown as SymbolCtor,
square: graphic.Rect as unknown as SymbolCtor,
circle: graphic.Circle as unknown as SymbolCtor,
diamond: Diamond as unknown as SymbolCtor,
pin: Pin as unknown as SymbolCtor,
arrow: Arrow as unknown as SymbolCtor,
triangle: Triangle as unknown as SymbolCtor
};
const symbolShapeMakers: Dictionary<SymbolShapeMaker> = {
line: function (x, y, w, h, shape: graphic.Line['shape']) {
shape.x1 = x;
shape.y1 = y + h / 2;
shape.x2 = x + w;
shape.y2 = y + h / 2;
},
rect: function (x, y, w, h, shape: graphic.Rect['shape']) {
shape.x = x;
shape.y = y;
shape.width = w;
shape.height = h;
},
roundRect: function (x, y, w, h, shape: graphic.Rect['shape']) {
shape.x = x;
shape.y = y;
shape.width = w;
shape.height = h;
shape.r = Math.min(w, h) / 4;
},
square: function (x, y, w, h, shape: graphic.Rect['shape']) {
const size = Math.min(w, h);
shape.x = x;
shape.y = y;
shape.width = size;
shape.height = size;
},
circle: function (x, y, w, h, shape: graphic.Circle['shape']) {
// Put circle in the center of square
shape.cx = x + w / 2;
shape.cy = y + h / 2;
shape.r = Math.min(w, h) / 2;
},
diamond: function (x, y, w, h, shape: InstanceType<typeof Diamond>['shape']) {
shape.cx = x + w / 2;
shape.cy = y + h / 2;
shape.width = w;
shape.height = h;
},
pin: function (x, y, w, h, shape: InstanceType<typeof Pin>['shape']) {
shape.x = x + w / 2;
shape.y = y + h / 2;
shape.width = w;
shape.height = h;
},
arrow: function (x, y, w, h, shape: InstanceType<typeof Arrow>['shape']) {
shape.x = x + w / 2;
shape.y = y + h / 2;
shape.width = w;
shape.height = h;
},
triangle: function (x, y, w, h, shape: InstanceType<typeof Triangle>['shape']) {
shape.cx = x + w / 2;
shape.cy = y + h / 2;
shape.width = w;
shape.height = h;
}
};
export const symbolBuildProxies: Dictionary<ECSymbol> = {};
each(symbolCtors, function (Ctor, name) {
symbolBuildProxies[name] = new Ctor();
});
const SymbolClz = graphic.Path.extend({
type: 'symbol',
shape: {
symbolType: '',
x: 0,
y: 0,
width: 0,
height: 0
},
calculateTextPosition(out, config, rect) {
const res = calculateTextPosition(out, config, rect);
const shape = this.shape;
if (shape && shape.symbolType === 'pin' && config.position === 'inside') {
res.y = rect.y + rect.height * 0.4;
}
return res;
},
buildPath(ctx, shape, inBundle) {
let symbolType = shape.symbolType;
if (symbolType !== 'none') {
let proxySymbol = symbolBuildProxies[symbolType];
if (!proxySymbol) {
// Default rect
symbolType = 'rect';
proxySymbol = symbolBuildProxies[symbolType];
}
symbolShapeMakers[symbolType](
shape.x, shape.y, shape.width, shape.height, proxySymbol.shape
);
proxySymbol.buildPath(ctx, proxySymbol.shape, inBundle);
}
}
});
// Provide setColor helper method to avoid determine if set the fill or stroke outside
function symbolPathSetColor(this: ECSymbol, color: ZRColor, innerColor?: ZRColor) {
if (this.type !== 'image') {
const symbolStyle = this.style;
if (this.__isEmptyBrush) {
symbolStyle.stroke = color;
symbolStyle.fill = innerColor || '#fff';
// TODO Same width with lineStyle in LineView
symbolStyle.lineWidth = 2;
}
else if (this.shape.symbolType === 'line') {
symbolStyle.stroke = color;
}
else {
symbolStyle.fill = color;
}
this.markRedraw();
}
}
/**
* Create a symbol element with given symbol configuration: shape, x, y, width, height, color
*/
export function createSymbol(
symbolType: string,
x: number,
y: number,
w: number,
h: number,
color?: ZRColor,
// whether to keep the ratio of w/h,
keepAspect?: boolean
) {
// TODO Support image object, DynamicImage.
const isEmpty = symbolType.indexOf('empty') === 0;
if (isEmpty) {
symbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6);
}
let symbolPath: ECSymbol | graphic.Image;
if (symbolType.indexOf('image://') === 0) {
symbolPath = graphic.makeImage(
symbolType.slice(8),
new BoundingRect(x, y, w, h),
keepAspect ? 'center' : 'cover'
);
}
else if (symbolType.indexOf('path://') === 0) {
symbolPath = graphic.makePath(
symbolType.slice(7),
{},
new BoundingRect(x, y, w, h),
keepAspect ? 'center' : 'cover'
) as unknown as ECSymbol;
}
else {
symbolPath = new SymbolClz({
shape: {
symbolType: symbolType,
x: x,
y: y,
width: w,
height: h
}
}) as unknown as ECSymbol;
}
(symbolPath as ECSymbol).__isEmptyBrush = isEmpty;
// TODO Should deprecate setColor
(symbolPath as ECSymbol).setColor = symbolPathSetColor;
if (color) {
(symbolPath as ECSymbol).setColor(color);
}
return symbolPath as ECSymbol;
}
export function normalizeSymbolSize(symbolSize: number | number[]): [number, number] {
if (!isArray(symbolSize)) {
symbolSize = [+symbolSize, +symbolSize];
}
return [symbolSize[0] || 0, symbolSize[1] || 0];
}
export function normalizeSymbolOffset(
symbolOffset: SymbolOptionMixin['symbolOffset'],
symbolSize: number[]
): [number, number] {
if (symbolOffset == null) {
return;
}
if (!isArray(symbolOffset)) {
symbolOffset = [symbolOffset, symbolOffset];
}
return [
parsePercent(symbolOffset[0], symbolSize[0]) || 0,
parsePercent(retrieve2(symbolOffset[1], symbolOffset[0]), symbolSize[1]) || 0
];
}
相关信息
相关文章
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦