344 lines
8.9 KiB
JavaScript
344 lines
8.9 KiB
JavaScript
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
var zrUtil = require("zrender/lib/core/util");
|
|
|
|
var graphic = require("./graphic");
|
|
|
|
var BoundingRect = require("zrender/lib/core/BoundingRect");
|
|
|
|
var _text = require("zrender/lib/contain/text");
|
|
|
|
var calculateTextPosition = _text.calculateTextPosition;
|
|
|
|
/*
|
|
* 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
|
|
|
|
/**
|
|
* Triangle shape
|
|
* @inner
|
|
*/
|
|
var Triangle = graphic.extendShape({
|
|
type: 'triangle',
|
|
shape: {
|
|
cx: 0,
|
|
cy: 0,
|
|
width: 0,
|
|
height: 0
|
|
},
|
|
buildPath: function (path, shape) {
|
|
var cx = shape.cx;
|
|
var cy = shape.cy;
|
|
var width = shape.width / 2;
|
|
var 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
|
|
*/
|
|
|
|
var Diamond = graphic.extendShape({
|
|
type: 'diamond',
|
|
shape: {
|
|
cx: 0,
|
|
cy: 0,
|
|
width: 0,
|
|
height: 0
|
|
},
|
|
buildPath: function (path, shape) {
|
|
var cx = shape.cx;
|
|
var cy = shape.cy;
|
|
var width = shape.width / 2;
|
|
var 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
|
|
*/
|
|
|
|
var Pin = graphic.extendShape({
|
|
type: 'pin',
|
|
shape: {
|
|
// x, y on the cusp
|
|
x: 0,
|
|
y: 0,
|
|
width: 0,
|
|
height: 0
|
|
},
|
|
buildPath: function (path, shape) {
|
|
var x = shape.x;
|
|
var y = shape.y;
|
|
var w = shape.width / 5 * 3; // Height must be larger than width
|
|
|
|
var h = Math.max(w, shape.height);
|
|
var r = w / 2; // Dist on y with tangent point and circle center
|
|
|
|
var dy = r * r / (h - r);
|
|
var cy = y - h + r + dy;
|
|
var angle = Math.asin(dy / r); // Dist on x with tangent point and circle center
|
|
|
|
var dx = Math.cos(angle) * r;
|
|
var tanX = Math.sin(angle);
|
|
var tanY = Math.cos(angle);
|
|
var cpLen = r * 0.6;
|
|
var 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
|
|
*/
|
|
|
|
var Arrow = graphic.extendShape({
|
|
type: 'arrow',
|
|
shape: {
|
|
x: 0,
|
|
y: 0,
|
|
width: 0,
|
|
height: 0
|
|
},
|
|
buildPath: function (ctx, shape) {
|
|
var height = shape.height;
|
|
var width = shape.width;
|
|
var x = shape.x;
|
|
var y = shape.y;
|
|
var 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
|
|
* @type {Object.<string, module:zrender/graphic/Path>}
|
|
*/
|
|
|
|
var symbolCtors = {
|
|
line: graphic.Line,
|
|
rect: graphic.Rect,
|
|
roundRect: graphic.Rect,
|
|
square: graphic.Rect,
|
|
circle: graphic.Circle,
|
|
diamond: Diamond,
|
|
pin: Pin,
|
|
arrow: Arrow,
|
|
triangle: Triangle
|
|
};
|
|
var symbolShapeMakers = {
|
|
line: function (x, y, w, h, shape) {
|
|
// FIXME
|
|
shape.x1 = x;
|
|
shape.y1 = y + h / 2;
|
|
shape.x2 = x + w;
|
|
shape.y2 = y + h / 2;
|
|
},
|
|
rect: function (x, y, w, h, shape) {
|
|
shape.x = x;
|
|
shape.y = y;
|
|
shape.width = w;
|
|
shape.height = h;
|
|
},
|
|
roundRect: function (x, y, w, h, 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) {
|
|
var size = Math.min(w, h);
|
|
shape.x = x;
|
|
shape.y = y;
|
|
shape.width = size;
|
|
shape.height = size;
|
|
},
|
|
circle: function (x, y, w, h, 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) {
|
|
shape.cx = x + w / 2;
|
|
shape.cy = y + h / 2;
|
|
shape.width = w;
|
|
shape.height = h;
|
|
},
|
|
pin: function (x, y, w, h, shape) {
|
|
shape.x = x + w / 2;
|
|
shape.y = y + h / 2;
|
|
shape.width = w;
|
|
shape.height = h;
|
|
},
|
|
arrow: function (x, y, w, h, shape) {
|
|
shape.x = x + w / 2;
|
|
shape.y = y + h / 2;
|
|
shape.width = w;
|
|
shape.height = h;
|
|
},
|
|
triangle: function (x, y, w, h, shape) {
|
|
shape.cx = x + w / 2;
|
|
shape.cy = y + h / 2;
|
|
shape.width = w;
|
|
shape.height = h;
|
|
}
|
|
};
|
|
var symbolBuildProxies = {};
|
|
zrUtil.each(symbolCtors, function (Ctor, name) {
|
|
symbolBuildProxies[name] = new Ctor();
|
|
});
|
|
var SymbolClz = graphic.extendShape({
|
|
type: 'symbol',
|
|
shape: {
|
|
symbolType: '',
|
|
x: 0,
|
|
y: 0,
|
|
width: 0,
|
|
height: 0
|
|
},
|
|
calculateTextPosition: function (out, style, rect) {
|
|
var res = calculateTextPosition(out, style, rect);
|
|
var shape = this.shape;
|
|
|
|
if (shape && shape.symbolType === 'pin' && style.textPosition === 'inside') {
|
|
res.y = rect.y + rect.height * 0.4;
|
|
}
|
|
|
|
return res;
|
|
},
|
|
buildPath: function (ctx, shape, inBundle) {
|
|
var symbolType = shape.symbolType;
|
|
|
|
if (symbolType !== 'none') {
|
|
var 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(color, innerColor) {
|
|
if (this.type !== 'image') {
|
|
var symbolStyle = this.style;
|
|
var symbolShape = this.shape;
|
|
|
|
if (symbolShape && symbolShape.symbolType === 'line') {
|
|
symbolStyle.stroke = color;
|
|
} else if (this.__isEmptyBrush) {
|
|
symbolStyle.stroke = color;
|
|
symbolStyle.fill = innerColor || '#fff';
|
|
} else {
|
|
// FIXME 判断图形默认是填充还是描边,使用 onlyStroke ?
|
|
symbolStyle.fill && (symbolStyle.fill = color);
|
|
symbolStyle.stroke && (symbolStyle.stroke = color);
|
|
}
|
|
|
|
this.dirty(false);
|
|
}
|
|
}
|
|
/**
|
|
* Create a symbol element with given symbol configuration: shape, x, y, width, height, color
|
|
* @param {string} symbolType
|
|
* @param {number} x
|
|
* @param {number} y
|
|
* @param {number} w
|
|
* @param {number} h
|
|
* @param {string} color
|
|
* @param {boolean} [keepAspect=false] whether to keep the ratio of w/h,
|
|
* for path and image only.
|
|
*/
|
|
|
|
|
|
function createSymbol(symbolType, x, y, w, h, color, keepAspect) {
|
|
// TODO Support image object, DynamicImage.
|
|
var isEmpty = symbolType.indexOf('empty') === 0;
|
|
|
|
if (isEmpty) {
|
|
symbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6);
|
|
}
|
|
|
|
var symbolPath;
|
|
|
|
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');
|
|
} else {
|
|
symbolPath = new SymbolClz({
|
|
shape: {
|
|
symbolType: symbolType,
|
|
x: x,
|
|
y: y,
|
|
width: w,
|
|
height: h
|
|
}
|
|
});
|
|
}
|
|
|
|
symbolPath.__isEmptyBrush = isEmpty;
|
|
symbolPath.setColor = symbolPathSetColor;
|
|
symbolPath.setColor(color);
|
|
return symbolPath;
|
|
}
|
|
|
|
exports.createSymbol = createSymbol; |