NuclearDispersionSystem/ant-design-vue-jeecg/node_modules/@antv/g/lib/renderers/svg/painter.js
2023-09-14 14:47:11 +08:00

790 lines
19 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var Util = require('../../util');
var _require = require('../../util/format'),
parseRadius = _require.parseRadius;
var Marker = require('../../shapes/marker');
var Defs = require('./defs');
var SHAPE_TO_TAGS = {
rect: 'path',
circle: 'circle',
line: 'line',
path: 'path',
marker: 'path',
text: 'text',
polygon: 'polygon',
image: 'image',
ellipse: 'ellipse',
dom: 'foreignObject',
fan: 'path',
group: 'g'
};
var LETTER_SPACING = 0.3;
var SVG_ATTR_MAP = {
opacity: 'opacity',
fillStyle: 'fill',
strokeOpacity: 'stroke-opacity',
fillOpacity: 'fill-opacity',
strokeStyle: 'stroke',
x: 'x',
y: 'y',
r: 'r',
rx: 'rx',
ry: 'ry',
width: 'width',
height: 'height',
x1: 'x1',
x2: 'x2',
y1: 'y1',
y2: 'y2',
lineCap: 'stroke-linecap',
lineJoin: 'stroke-linejoin',
lineWidth: 'stroke-width',
lineDash: 'stroke-dasharray',
lineDashOffset: 'stroke-dashoffset',
miterLimit: 'stroke-miterlimit',
font: 'font',
fontSize: 'font-size',
fontStyle: 'font-style',
fontVariant: 'font-variant',
fontWeight: 'font-weight',
fontFamily: 'font-family',
startArrow: 'marker-start',
endArrow: 'marker-end',
path: 'd',
"class": 'class',
id: 'id',
style: 'style',
preserveAspectRatio: 'preserveAspectRatio'
};
var BASELINE_MAP = {
top: 'before-edge',
middle: 'central',
bottom: 'after-edge',
alphabetic: 'baseline',
hanging: 'hanging'
};
var ANCHOR_MAP = {
left: 'left',
start: 'left',
center: 'middle',
right: 'end',
end: 'end'
};
var Painter = /*#__PURE__*/function () {
function Painter(dom) {
if (!dom) {
return null;
}
var svgId = Util.uniqueId('canvas_');
var canvasDom = Util.createDom("<svg id=\"" + svgId + "\"></svg>");
dom.appendChild(canvasDom);
this.type = 'svg';
this.canvas = canvasDom;
this.context = new Defs(canvasDom);
this.toDraw = false;
return this;
}
var _proto = Painter.prototype;
_proto.draw = function draw(model) {
var self = this;
function drawInner() {
self.animateHandler = Util.requestAnimationFrame(function () {
self.animateHandler = undefined;
if (self.toDraw) {
drawInner();
}
});
try {
self._drawChildren(model);
} catch (ev) {
// 绘制时异常,中断重绘
console.warn('error in draw canvas, detail as:');
console.warn(ev);
} finally {
self.toDraw = false;
}
}
if (self.animateHandler) {
self.toDraw = true;
} else {
drawInner();
}
};
_proto.drawSync = function drawSync(model) {
this._drawChildren(model);
};
_proto._drawGroup = function _drawGroup(model, index) {
var cfg = model._cfg;
if (cfg.removed || cfg.destroyed) {
return;
}
if (cfg.tobeRemoved) {
Util.each(cfg.tobeRemoved, function (item) {
if (item.parentNode) {
item.parentNode.removeChild(item);
}
});
cfg.tobeRemoved = [];
}
this._drawShape(model, index);
if (cfg.children && cfg.children.length > 0) {
this._drawChildren(model);
}
};
_proto._drawChildren = function _drawChildren(parent) {
var self = this;
var children = parent._cfg.children;
var shape; // 防止在画children的时候父group已经被destroy
if (!children) {
return;
}
for (var i = 0; i < children.length; i++) {
shape = children[i];
if (shape.isGroup) {
self._drawGroup(shape, i);
} else {
self._drawShape(shape, i);
}
}
};
_proto._drawShape = function _drawShape(model, index) {
var self = this;
var attrs = model._attrs;
var cfg = model._cfg;
var el = cfg.el; // 删除
if (cfg.removed || cfg.destroyed) {
if (el) {
el.parentNode.removeChild(cfg.el);
}
return;
} // 新增节点
if (!el && cfg.parent) {
self._createDom(model, index);
self._updateShape(model);
}
el = cfg.el;
if (cfg.visible === false) {
el.setAttribute('visibility', 'hidden');
return;
}
if (cfg.visible && el.hasAttribute('visibility')) {
el.removeAttribute('visibility');
} // 更新
if (cfg.hasUpdate) {
self._updateShape(model);
}
if (attrs.clip && attrs.clip._cfg.hasUpdate) {
self._updateShape(attrs.clip);
}
};
_proto._updateShape = function _updateShape(model) {
var self = this;
var attrs = model._attrs;
var formerAttrs = model._cfg.attrs;
if (!formerAttrs) {
return;
}
if (!model._cfg.el) {
self._createDom(model);
}
if ('clip' in attrs) {
this._setClip(model, attrs.clip);
}
if ('shadowOffsetX' in attrs || 'shadowOffsetY' in attrs || 'shadowBlur' in attrs || 'shadowColor' in attrs) {
this._setShadow(model);
}
if (model.type === 'text') {
self._updateText(model);
return;
}
if (model.type === 'fan') {
self._updateFan(model);
}
if (model.type === 'marker') {
model._cfg.el.setAttribute('d', self._assembleMarker(attrs));
}
if (model.type === 'rect') {
model._cfg.el.setAttribute('d', self._assembleRect(attrs));
}
for (var key in attrs) {
if (attrs[key] !== formerAttrs[key]) {
self._setAttribute(model, key, attrs[key]);
}
}
model._cfg.attrs = Util.deepMix({}, model._attrs);
model._cfg.hasUpdate = false;
};
_proto._setAttribute = function _setAttribute(model, name, value) {
var type = model.type;
var attrs = model._attrs;
var el = model._cfg.el;
var defs = this.context; // 计算marker路径
if ((type === 'marker' || type === 'rect') && ~['x', 'y', 'radius', 'r'].indexOf(name)) {
return;
} // 圆和椭圆不是x, y 是cx, cy。 marker的x,y 用于计算marker的路径不需要写到dom
if (~['circle', 'ellipse'].indexOf(type) && ~['x', 'y'].indexOf(name)) {
el.setAttribute('c' + name, parseInt(value, 10));
return;
} // 多边形
if (type === 'polygon' && name === 'points') {
if (!value || value.length === 0) {
value = '';
}
if (Util.isArray(value)) {
value = value.map(function (point) {
return point[0] + ',' + point[1];
});
value = value.join(' ');
}
el.setAttribute('points', value);
return;
} // 设置path
if (name === 'path' && Util.isArray(value)) {
el.setAttribute('d', this._formatPath(value));
return;
} // 设置图片
if (name === 'img') {
this._setImage(model, value);
return;
}
if (name === 'transform') {
if (!value) {
el.removeAttribute('transform');
return;
}
this._setTransform(model);
return;
}
if (name === 'rotate') {
if (!value) {
el.removeAttribute('transform');
return;
}
this._setTransform(model);
return;
}
if (name === 'matrix') {
this._setTransform(model);
return;
}
if (name === 'fillStyle' || name === 'strokeStyle') {
this._setColor(model, name, value);
return;
}
if (name === 'clip') {
return;
}
if (~name.indexOf('Arrow')) {
name = SVG_ATTR_MAP[name];
if (!value) {
model._cfg[name] = null;
el.removeAttribute(name);
} else {
var id = null;
if (typeof value === 'boolean') {
id = defs.getDefaultArrow(attrs, name);
} else {
id = defs.addArrow(attrs, name);
}
el.setAttribute(name, "url(#" + id + ")");
model._cfg[name] = id;
}
return;
} // foreignObject
if (name === 'html') {
if (typeof value === 'string') {
el.innerHTML = value;
} else {
el.innerHTML = '';
el.appendChild(value);
}
}
if (SVG_ATTR_MAP[name]) {
el.setAttribute(SVG_ATTR_MAP[name], value);
}
};
_proto._createDom = function _createDom(model, index) {
var type = SHAPE_TO_TAGS[model.type];
var attrs = model._attrs;
var parent = model._cfg.parent;
if (!type) {
throw new Error('the type' + model.type + 'is not supported by svg');
}
var shape = document.createElementNS('http://www.w3.org/2000/svg', type);
if (model._cfg.id) {
shape.id = model._cfg.id;
}
model._cfg.el = shape;
if (parent) {
var parentNode = parent._cfg.el;
if (typeof index === 'undefined') {
parentNode.appendChild(shape);
} else {
var childNodes = parent._cfg.el.childNodes; // svg下天然有defs作为子节点svg下子元素index需要+1
if (parentNode.tagName === 'svg') {
index += 1;
}
if (childNodes.length <= index) {
parentNode.appendChild(shape);
} else {
parentNode.insertBefore(shape, childNodes[index]);
}
}
}
model._cfg.attrs = {};
if (model.type === 'text') {
shape.setAttribute('paint-order', 'stroke');
shape.setAttribute('style', 'stroke-linecap:butt; stroke-linejoin:miter;');
} else {
if (!attrs.stroke && !attrs.strokeStyle) {
shape.setAttribute('stroke', 'none');
}
if (!attrs.fill && !attrs.fillStyle) {
shape.setAttribute('fill', 'none');
}
}
return shape;
};
_proto._assembleMarker = function _assembleMarker(attrs) {
var r = attrs.r;
if (typeof attrs.r === 'undefined') {
r = attrs.radius;
}
if (isNaN(Number(attrs.x)) || isNaN(Number(attrs.y)) || isNaN(Number(r))) {
return '';
}
var d = '';
if (typeof attrs.symbol === 'function') {
d = attrs.symbol(attrs.x, attrs.y, r);
} else {
d = Marker.Symbols[attrs.symbol || 'circle'](attrs.x, attrs.y, r);
}
if (Util.isArray(d)) {
d = d.map(function (path) {
return path.join(' ');
}).join('');
}
return d;
};
_proto._assembleRect = function _assembleRect(attrs) {
var x = attrs.x;
var y = attrs.y;
var w = attrs.width;
var h = attrs.height;
var radius = attrs.radius;
if (!radius) {
return "M " + x + "," + y + " l " + w + ",0 l 0," + h + " l" + -w + " 0 z";
}
var r = parseRadius(radius);
if (Util.isArray(radius)) {
if (radius.length === 1) {
r.r1 = r.r2 = r.r3 = r.r4 = radius[0];
} else if (radius.length === 2) {
r.r1 = r.r3 = radius[0];
r.r2 = r.r4 = radius[1];
} else if (radius.length === 3) {
r.r1 = radius[0];
r.r2 = r.r4 = radius[1];
r.r3 = radius[2];
} else {
r.r1 = radius[0];
r.r2 = radius[1];
r.r3 = radius[2];
r.r4 = radius[3];
}
} else {
r.r1 = r.r2 = r.r3 = r.r4 = radius;
}
var d = [["M " + (x + r.r1) + "," + y], ["l " + (w - r.r1 - r.r2) + ",0"], ["a " + r.r2 + "," + r.r2 + ",0,0,1," + r.r2 + "," + r.r2], ["l 0," + (h - r.r2 - r.r3)], ["a " + r.r3 + "," + r.r3 + ",0,0,1," + -r.r3 + "," + r.r3], ["l " + (r.r3 + r.r4 - w) + ",0"], ["a " + r.r4 + "," + r.r4 + ",0,0,1," + -r.r4 + "," + -r.r4], ["l 0," + (r.r4 + r.r1 - h)], ["a " + r.r1 + "," + r.r1 + ",0,0,1," + r.r1 + "," + -r.r1], ['z']];
return d.join(' ');
};
_proto._formatPath = function _formatPath(value) {
value = value.map(function (path) {
return path.join(' ');
}).join('');
if (~value.indexOf('NaN')) {
return '';
}
return value;
};
_proto._setTransform = function _setTransform(model) {
var matrix = model._attrs.matrix;
var el = model._cfg.el;
var transform = [];
for (var i = 0; i < 9; i += 3) {
transform.push(matrix[i] + ',' + matrix[i + 1]);
}
transform = transform.join(',');
if (transform.indexOf('NaN') === -1) {
el.setAttribute('transform', "matrix(" + transform + ")");
} else {
console.warn('invalid matrix:', matrix);
}
};
_proto._setImage = function _setImage(model, img) {
var attrs = model._attrs;
var el = model._cfg.el;
if (Util.isString(img)) {
el.setAttribute('href', img);
} else if (img instanceof Image) {
if (!attrs.width) {
el.setAttribute('width', img.width);
model._attrs.width = img.width;
}
if (!attrs.height) {
el.setAttribute('height', img.height);
model._attrs.height = img.height;
}
el.setAttribute('href', img.src);
} else if (img instanceof HTMLElement && Util.isString(img.nodeName) && img.nodeName.toUpperCase() === 'CANVAS') {
el.setAttribute('href', img.toDataURL());
} else if (img instanceof ImageData) {
var canvas = document.createElement('canvas');
canvas.setAttribute('width', img.width);
canvas.setAttribute('height', img.height);
canvas.getContext('2d').putImageData(img, 0, 0);
if (!attrs.width) {
el.setAttribute('width', img.width);
model._attrs.width = img.width;
}
if (!attrs.height) {
el.setAttribute('height', img.height);
model._attrs.height = img.height;
}
el.setAttribute('href', canvas.toDataURL());
}
};
_proto._updateFan = function _updateFan(model) {
function getPoint(angle, radius, center) {
return {
x: radius * Math.cos(angle) + center.x,
y: radius * Math.sin(angle) + center.y
};
}
var attrs = model._attrs;
var cfg = model._cfg;
var center = {
x: attrs.x,
y: attrs.y
};
var d = [];
var startAngle = attrs.startAngle;
var endAngle = attrs.endAngle;
if (Util.isNumberEqual(endAngle - startAngle, Math.PI * 2)) {
endAngle -= 0.00001;
}
var outerStart = getPoint(startAngle, attrs.re, center);
var outerEnd = getPoint(endAngle, attrs.re, center);
var fa = endAngle > startAngle ? 1 : 0;
var fs = Math.abs(endAngle - startAngle) > Math.PI ? 1 : 0;
var rs = attrs.rs;
var re = attrs.re;
var innerStart = getPoint(startAngle, attrs.rs, center);
var innerEnd = getPoint(endAngle, attrs.rs, center);
if (attrs.rs > 0) {
d.push("M " + outerEnd.x + "," + outerEnd.y);
d.push("L " + innerEnd.x + "," + innerEnd.y);
d.push("A " + rs + "," + rs + ",0," + fs + "," + (fa === 1 ? 0 : 1) + "," + innerStart.x + "," + innerStart.y);
d.push("L " + outerStart.x + " " + outerStart.y);
} else {
d.push("M " + center.x + "," + center.y);
d.push("L " + outerStart.x + "," + outerStart.y);
}
d.push("A " + re + "," + re + ",0," + fs + "," + fa + "," + outerEnd.x + "," + outerEnd.y);
if (attrs.rs > 0) {
d.push("L " + innerEnd.x + "," + innerEnd.y);
} else {
d.push('Z');
}
cfg.el.setAttribute('d', d.join(' '));
};
_proto._updateText = function _updateText(model) {
var self = this;
var attrs = model._attrs;
var formerAttrs = model._cfg.attrs;
var el = model._cfg.el;
this._setFont(model);
for (var attr in attrs) {
if (attrs[attr] !== formerAttrs[attr]) {
if (attr === 'text') {
self._setText(model, "" + attrs[attr]);
continue;
}
if (attr === 'fillStyle' || attr === 'strokeStyle') {
this._setColor(model, attr, attrs[attr]);
continue;
}
if (attr === 'matrix') {
this._setTransform(model);
continue;
}
if (SVG_ATTR_MAP[attr]) {
el.setAttribute(SVG_ATTR_MAP[attr], attrs[attr]);
}
}
}
model._cfg.attrs = Object.assign({}, model._attrs);
model._cfg.hasUpdate = false;
};
_proto._setFont = function _setFont(model) {
var el = model.get('el');
var attrs = model._attrs;
var fontSize = attrs.fontSize;
el.setAttribute('alignment-baseline', BASELINE_MAP[attrs.textBaseline] || 'baseline');
el.setAttribute('text-anchor', ANCHOR_MAP[attrs.textAlign] || 'left');
if (fontSize && +fontSize < 12) {
// 小于 12 像素的文本进行 scale 处理
attrs.matrix = [1, 0, 0, 0, 1, 0, 0, 0, 1];
model.transform([['t', -attrs.x, -attrs.y], ['s', +fontSize / 12, +fontSize / 12], ['t', attrs.x, attrs.y]]);
}
};
_proto._setText = function _setText(model, text) {
var el = model._cfg.el;
var baseline = model._attrs.textBaseline || 'bottom';
if (!text) {
el.innerHTML = '';
} else if (~text.indexOf('\n')) {
var x = model._attrs.x;
var textArr = text.split('\n');
var textLen = textArr.length - 1;
var arr = '';
Util.each(textArr, function (segment, i) {
if (i === 0) {
if (baseline === 'alphabetic') {
arr += "<tspan x=\"" + x + "\" dy=\"" + -textLen + "em\">" + segment + "</tspan>";
} else if (baseline === 'top') {
arr += "<tspan x=\"" + x + "\" dy=\"0.9em\">" + segment + "</tspan>";
} else if (baseline === 'middle') {
arr += "<tspan x=\"" + x + "\" dy=\"" + -(textLen - 1) / 2 + "em\">" + segment + "</tspan>";
} else if (baseline === 'bottom') {
arr += "<tspan x=\"" + x + "\" dy=\"-" + (textLen + LETTER_SPACING) + "em\">" + segment + "</tspan>";
} else if (baseline === 'hanging') {
arr += "<tspan x=\"" + x + "\" dy=\"" + (-(textLen - 1) - LETTER_SPACING) + "em\">" + segment + "</tspan>";
}
} else {
arr += "<tspan x=\"" + x + "\" dy=\"1em\">" + segment + "</tspan>";
}
});
el.innerHTML = arr;
} else {
el.innerHTML = text;
}
};
_proto._setClip = function _setClip(model, value) {
var el = model._cfg.el;
if (!value) {
el.removeAttribute('clip-path');
return;
}
if (!el.hasAttribute('clip-path')) {
this._createDom(value);
this._updateShape(value);
var id = this.context.addClip(value);
el.setAttribute('clip-path', "url(#" + id + ")");
} else if (value._cfg.hasUpdate) {
this._updateShape(value);
}
};
_proto._setColor = function _setColor(model, name, value) {
var el = model._cfg.el;
var defs = this.context;
if (!value) {
el.setAttribute(SVG_ATTR_MAP[name], 'none');
return;
}
value = value.trim();
if (/^[r,R,L,l]{1}[\s]*\(/.test(value)) {
var id = defs.find('gradient', value);
if (!id) {
id = defs.addGradient(value);
}
el.setAttribute(SVG_ATTR_MAP[name], "url(#" + id + ")");
} else if (/^[p,P]{1}[\s]*\(/.test(value)) {
var _id = defs.find('pattern', value);
if (!_id) {
_id = defs.addPattern(value);
}
el.setAttribute(SVG_ATTR_MAP[name], "url(#" + _id + ")");
} else {
el.setAttribute(SVG_ATTR_MAP[name], value);
}
};
_proto._setShadow = function _setShadow(model) {
var el = model._cfg.el;
var attrs = model._attrs;
var cfg = {
dx: attrs.shadowOffsetX,
dy: attrs.shadowOffsetY,
blur: attrs.shadowBlur,
color: attrs.shadowColor
};
if (!cfg.dx && !cfg.dy && !cfg.blur && !cfg.color) {
el.removeAttribute('filter');
} else {
var id = this.context.find('filter', cfg);
if (!id) {
id = this.context.addShadow(cfg, this);
}
el.setAttribute('filter', "url(#" + id + ")");
}
};
return Painter;
}();
module.exports = Painter;