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

365 lines
9.1 KiB
Java

var Util = require('../util/index');
var Shape = require('../core/shape');
var PathSegment = require('./util/path-segment');
var Format = require('../util/format');
var Arrow = require('./util/arrow');
var PathUtil = require('../util/path');
var CubicMath = require('./math/cubic');
var Path = function Path(cfg) {
Path.superclass.constructor.call(this, cfg);
};
Path.ATTRS = {
path: null,
lineWidth: 1,
startArrow: false,
endArrow: false
};
Util.extend(Path, Shape);
Util.augment(Path, {
canFill: true,
canStroke: true,
type: 'path',
getDefaultAttrs: function getDefaultAttrs() {
return {
lineWidth: 1,
startArrow: false,
endArrow: false
};
},
_afterSetAttrPath: function _afterSetAttrPath(path) {
var self = this;
if (Util.isNil(path)) {
self.setSilent('segments', null);
self.setSilent('box', undefined);
return;
}
var pathArray = Format.parsePath(path);
var preSegment;
var segments = [];
if (!Util.isArray(pathArray) || pathArray.length === 0 || pathArray[0][0] !== 'M' && pathArray[0][0] !== 'm') {
return;
}
var count = pathArray.length;
for (var i = 0; i < pathArray.length; i++) {
var item = pathArray[i];
preSegment = new PathSegment(item, preSegment, i === count - 1);
segments.push(preSegment);
}
self.setSilent('segments', segments);
self.setSilent('tCache', null);
self.setSilent('totalLength', null);
self.setSilent('box', null);
},
calculateBox: function calculateBox() {
var self = this;
var segments = self.get('segments');
if (!segments) {
return null;
}
var lineWidth = this.getHitLineWidth();
var minX = Infinity;
var maxX = -Infinity;
var minY = Infinity;
var maxY = -Infinity;
Util.each(segments, function (segment) {
segment.getBBox(lineWidth);
var box = segment.box;
if (box) {
if (box.minX < minX) {
minX = box.minX;
}
if (box.maxX > maxX) {
maxX = box.maxX;
}
if (box.minY < minY) {
minY = box.minY;
}
if (box.maxY > maxY) {
maxY = box.maxY;
}
}
});
if (minX === Infinity || minY === Infinity) {
return {
minX: 0,
minY: 0,
maxX: 0,
maxY: 0
};
}
return {
minX: minX,
minY: minY,
maxX: maxX,
maxY: maxY
};
},
_setTcache: function _setTcache() {
var totalLength = 0;
var tempLength = 0;
var tCache = [];
var segmentT;
var segmentL;
var segmentN;
var l;
var curve = this._cfg.curve;
if (!curve) {
return;
}
Util.each(curve, function (segment, i) {
segmentN = curve[i + 1];
l = segment.length;
if (segmentN) {
totalLength += CubicMath.len(segment[l - 2], segment[l - 1], segmentN[1], segmentN[2], segmentN[3], segmentN[4], segmentN[5], segmentN[6]);
}
});
this._cfg.totalLength = totalLength;
if (totalLength === 0) {
this._cfg.tCache = [];
return;
}
Util.each(curve, function (segment, i) {
segmentN = curve[i + 1];
l = segment.length;
if (segmentN) {
segmentT = [];
segmentT[0] = tempLength / totalLength;
segmentL = CubicMath.len(segment[l - 2], segment[l - 1], segmentN[1], segmentN[2], segmentN[3], segmentN[4], segmentN[5], segmentN[6]);
tempLength += segmentL;
segmentT[1] = tempLength / totalLength;
tCache.push(segmentT);
}
});
this._cfg.tCache = tCache;
},
getTotalLength: function getTotalLength() {
var totalLength = this.get('totalLength');
if (!Util.isNil(totalLength)) {
return totalLength;
}
this._calculateCurve();
this._setTcache();
return this.get('totalLength');
},
_calculateCurve: function _calculateCurve() {
var self = this;
var attrs = self._attrs;
var path = attrs.path;
this._cfg.curve = PathUtil.pathTocurve(path);
},
getStartTangent: function getStartTangent() {
var segments = this.get('segments');
var startPoint, endPoint, tangent, result;
if (segments.length > 1) {
startPoint = segments[0].endPoint;
endPoint = segments[1].endPoint;
tangent = segments[1].startTangent;
result = [];
if (Util.isFunction(tangent)) {
var v = tangent();
result.push([startPoint.x - v[0], startPoint.y - v[1]]);
result.push([startPoint.x, startPoint.y]);
} else {
result.push([endPoint.x, endPoint.y]);
result.push([startPoint.x, startPoint.y]);
}
}
return result;
},
getEndTangent: function getEndTangent() {
var segments = this.get('segments');
var segmentsLen = segments.length;
var startPoint, endPoint, tangent, result;
if (segmentsLen > 1) {
startPoint = segments[segmentsLen - 2].endPoint;
endPoint = segments[segmentsLen - 1].endPoint;
tangent = segments[segmentsLen - 1].endTangent;
result = [];
if (Util.isFunction(tangent)) {
var v = tangent();
result.push([endPoint.x - v[0], endPoint.y - v[1]]);
result.push([endPoint.x, endPoint.y]);
} else {
result.push([startPoint.x, startPoint.y]);
result.push([endPoint.x, endPoint.y]);
}
}
return result;
},
getPoint: function getPoint(t) {
var tCache = this._cfg.tCache;
var subt;
var index;
if (!tCache) {
this._calculateCurve();
this._setTcache();
tCache = this._cfg.tCache;
}
var curve = this._cfg.curve;
if (!tCache || tCache.length === 0) {
if (curve) {
return {
x: curve[0][1],
y: curve[0][2]
};
}
return null;
}
Util.each(tCache, function (v, i) {
if (t >= v[0] && t <= v[1]) {
subt = (t - v[0]) / (v[1] - v[0]);
index = i;
}
});
var seg = curve[index];
if (Util.isNil(seg) || Util.isNil(index)) {
return null;
}
var l = seg.length;
var nextSeg = curve[index + 1];
return {
x: CubicMath.at(seg[l - 2], nextSeg[1], nextSeg[3], nextSeg[5], 1 - subt),
y: CubicMath.at(seg[l - 1], nextSeg[2], nextSeg[4], nextSeg[6], 1 - subt)
};
},
createPath: function createPath(context) {
var self = this;
var attrs = self._attrs;
var segments = self.get('segments');
if (!Util.isArray(segments)) {
return;
}
var segmentsLen = segments.length;
if (segmentsLen === 0) {
return;
}
context = context || self.get('context');
context.beginPath();
if (attrs.startArrow && attrs.startArrow.d) {
// 如果 startArrow 需要做偏移,为了保证 path 长度一定,需要向内缩进一定距离
// 如果直接修改 PathSegment 的 params 会导致画布每重绘一次线条便缩短一截
// 所以在绘制时计算要缩进的距离,直接绘制出来
var tangent = self.getStartTangent();
var dist = Arrow.getShortenOffset(tangent[0][0], tangent[0][1], tangent[1][0], tangent[1][1], attrs.startArrow.d);
segments[0].shortenDraw(context, dist.dx, dist.dy);
} else {
segments[0].draw(context);
}
for (var i = 1; i < segmentsLen - 2; i++) {
segments[i].draw(context);
}
if (attrs.endArrow && attrs.endArrow.d) {
// 如果 endArrow 需要做偏移,跟 startArrow 一样处理
// 为了防止结尾为 'Z' 的 segment 缩短不起效,需要取最后两个 segment 特殊处理
var _tangent = self.getEndTangent();
var _dist = Arrow.getShortenOffset(_tangent[0][0], _tangent[0][1], _tangent[1][0], _tangent[1][1], attrs.endArrow.d);
var segment = segments[segmentsLen - 1];
if (segment.command.toUpperCase() === 'Z') {
if (segments[segmentsLen - 2]) {
segments[segmentsLen - 2].shortenDraw(context, _dist.dx, _dist.dy);
}
segment.draw(context);
} else {
if (segmentsLen > 2) {
segments[segmentsLen - 2].draw(context);
}
segment.shortenDraw(context, _dist.dx, _dist.dy);
}
} else {
if (segments[segmentsLen - 2]) {
segments[segmentsLen - 2].draw(context);
}
segments[segmentsLen - 1].draw(context);
}
},
afterPath: function afterPath(context) {
var self = this;
var attrs = self._attrs;
var segments = self.get('segments');
var path = attrs.path;
context = context || self.get('context');
if (!Util.isArray(segments)) {
return;
}
if (segments.length === 1) {
return;
}
if (!attrs.startArrow && !attrs.endArrow) {
return;
}
if (path[path.length - 1] === 'z' || path[path.length - 1] === 'Z' || attrs.fill) {
// 闭合路径不绘制箭头
return;
}
var startPoints = self.getStartTangent();
Arrow.addStartArrow(context, attrs, startPoints[0][0], startPoints[0][1], startPoints[1][0], startPoints[1][1]);
var endPoints = self.getEndTangent();
Arrow.addEndArrow(context, attrs, endPoints[0][0], endPoints[0][1], endPoints[1][0], endPoints[1][1]);
}
});
module.exports = Path;