@visactor/vrender-core
Version:
## Description
173 lines (161 loc) • 10.6 kB
JavaScript
import { pi2, sin, epsilon, abs, asin, clampAngleByRadian, isNumber, cos, sqrt, isArray } from "@visactor/vutils";
import { Graphic, GRAPHIC_UPDATE_TAG_KEY, NOWORK_ANIMATE_ATTR } from "./graphic";
import { CustomPath2D } from "../common/custom-path2d";
import { circleBounds } from "../common/utils";
import { getTheme } from "./theme";
import { application } from "../application";
import { ARC_NUMBER_TYPE } from "./constants";
import { updateBoundsOfCommonOuterBorder } from "./graphic-service/common-outer-boder-bounds";
const ARC_UPDATE_TAG_KEY = [ "innerRadius", "outerRadius", "startAngle", "endAngle", "cornerRadius", "padAngle", "padRadius", "cap", ...GRAPHIC_UPDATE_TAG_KEY ];
export class Arc extends Graphic {
constructor(params) {
super(params), this.type = "arc", this.numberType = ARC_NUMBER_TYPE;
}
isValid() {
return super.isValid() && this._isValid();
}
_isValid() {
const {startAngle: startAngle, endAngle: endAngle, outerRadius: outerRadius, innerRadius: innerRadius} = this.attribute;
return this._validNumber(startAngle) && this._validNumber(endAngle) && this._validNumber(outerRadius) && this._validNumber(innerRadius);
}
getParsedCornerRadius() {
const arcTheme = this.getGraphicTheme(), {cornerRadius: cornerRadius = arcTheme.cornerRadius, innerPadding: innerPadding = arcTheme.innerPadding, outerPadding: outerPadding = arcTheme.outerPadding} = this.attribute;
let {outerRadius: outerRadius = arcTheme.outerRadius, innerRadius: innerRadius = arcTheme.innerRadius} = this.attribute;
if (outerRadius += outerPadding, innerRadius -= innerPadding, 0 === cornerRadius || "0%" === cornerRadius) return 0;
const deltaRadius = Math.abs(outerRadius - innerRadius), parseCR = cornerRadius => Math.min(isNumber(cornerRadius, !0) ? cornerRadius : deltaRadius * parseFloat(cornerRadius) / 100, deltaRadius / 2);
if (isArray(cornerRadius)) {
const crList = cornerRadius.map((cr => parseCR(cr) || 0));
return 0 === crList.length ? [ crList[0], crList[0], crList[0], crList[0] ] : 2 === crList.length ? [ crList[0], crList[1], crList[0], crList[1] ] : (3 === crList.length && crList.push(0),
crList);
}
return parseCR(cornerRadius);
}
getParsedAngle() {
const arcTheme = this.getGraphicTheme();
let {startAngle: startAngle = arcTheme.startAngle, endAngle: endAngle = arcTheme.endAngle} = this.attribute;
const {cap: cap = arcTheme.cap} = this.attribute, sign = endAngle - startAngle >= 0 ? 1 : -1, deltaAngle = endAngle - startAngle;
if (startAngle = clampAngleByRadian(startAngle), endAngle = startAngle + deltaAngle,
cap && abs(deltaAngle) < pi2 - epsilon) {
let startCap = 1, endCap = 1;
cap.length && (startCap = Number(cap[0]), endCap = Number(cap[1]));
let {outerRadius: outerRadius = arcTheme.outerRadius, innerRadius: innerRadius = arcTheme.innerRadius} = this.attribute;
const {outerPadding: outerPadding = arcTheme.outerPadding, innerPadding: innerPadding = arcTheme.innerPadding} = this.attribute;
outerRadius += outerPadding, innerRadius -= innerPadding;
const capWidth = Math.abs(outerRadius - innerRadius) / 2, capAngle = capWidth / outerRadius;
if (capWidth > epsilon && outerRadius > epsilon) return {
startAngle: startAngle - sign * capAngle * startCap,
endAngle: endAngle + sign * capAngle * endCap,
sc: sign * capAngle * startCap,
ec: sign * capAngle * endCap
};
}
return {
startAngle: startAngle,
endAngle: endAngle
};
}
getParsePadAngle(startAngle, endAngle) {
const arcTheme = this.getGraphicTheme(), {innerPadding: innerPadding = arcTheme.innerPadding, outerPadding: outerPadding = arcTheme.outerPadding, padAngle: padAngle = arcTheme.padAngle} = this.attribute;
let {outerRadius: outerRadius = arcTheme.outerRadius, innerRadius: innerRadius = arcTheme.innerRadius} = this.attribute;
outerRadius += outerPadding, innerRadius -= innerPadding;
const {padRadius: padRadius = sqrt(outerRadius * outerRadius + innerRadius * innerRadius)} = this.attribute, deltaAngle = abs(endAngle - startAngle);
let outerStartAngle = startAngle, outerEndAngle = endAngle, innerStartAngle = startAngle, innerEndAngle = endAngle;
const halfPadAngle = padAngle / 2;
let innerDeltaAngle = deltaAngle, outerDeltaAngle = deltaAngle;
if (halfPadAngle > epsilon && padRadius > epsilon) {
const sign = endAngle > startAngle ? 1 : -1;
let p0 = asin(Number(padRadius) / innerRadius * sin(halfPadAngle)), p1 = asin(Number(padRadius) / outerRadius * sin(halfPadAngle));
return (innerDeltaAngle -= 2 * p0) > epsilon ? (p0 *= sign, innerStartAngle += p0,
innerEndAngle -= p0) : (innerDeltaAngle = 0, innerStartAngle = innerEndAngle = (startAngle + endAngle) / 2),
(outerDeltaAngle -= 2 * p1) > epsilon ? (p1 *= sign, outerStartAngle += p1, outerEndAngle -= p1) : (outerDeltaAngle = 0,
outerStartAngle = outerEndAngle = (startAngle + endAngle) / 2), {
outerStartAngle: outerStartAngle,
outerEndAngle: outerEndAngle,
innerStartAngle: innerStartAngle,
innerEndAngle: innerEndAngle,
innerDeltaAngle: innerDeltaAngle,
outerDeltaAngle: outerDeltaAngle
};
}
return {
outerStartAngle: outerStartAngle,
outerEndAngle: outerEndAngle,
innerStartAngle: innerStartAngle,
innerEndAngle: innerEndAngle,
innerDeltaAngle: innerDeltaAngle,
outerDeltaAngle: outerDeltaAngle
};
}
getGraphicTheme() {
return getTheme(this).arc;
}
updateAABBBounds(attribute, arcTheme, aabbBounds, full) {
this.updatePathProxyAABBBounds(aabbBounds) || (full ? this.updateArcAABBBoundsImprecise(attribute, arcTheme, aabbBounds) : this.updateArcAABBBoundsAccurate(attribute, arcTheme, aabbBounds));
const {tb1: tb1, tb2: tb2} = application.graphicService.updateTempAABBBounds(aabbBounds);
updateBoundsOfCommonOuterBorder(attribute, arcTheme, tb1), aabbBounds.union(tb1),
tb1.setValue(tb2.x1, tb2.y1, tb2.x2, tb2.y2);
const {lineJoin: lineJoin = arcTheme.lineJoin} = attribute;
return application.graphicService.transformAABBBounds(attribute, aabbBounds, arcTheme, "miter" === lineJoin, this),
aabbBounds;
}
updateArcAABBBoundsImprecise(attribute, arcTheme, aabbBounds) {
let {outerRadius: outerRadius = arcTheme.outerRadius, innerRadius: innerRadius = arcTheme.innerRadius} = attribute;
const {outerPadding: outerPadding = arcTheme.outerPadding, innerPadding: innerPadding = arcTheme.innerPadding} = attribute;
return outerRadius += outerPadding, innerRadius -= innerPadding, outerRadius < innerRadius && (outerRadius = innerRadius),
aabbBounds.set(-outerRadius, -outerRadius, outerRadius, outerRadius), aabbBounds;
}
updateArcAABBBoundsAccurate(attribute, arcTheme, aabbBounds) {
let {outerRadius: outerRadius = arcTheme.outerRadius, innerRadius: innerRadius = arcTheme.innerRadius} = attribute;
const {outerPadding: outerPadding = arcTheme.outerPadding, innerPadding: innerPadding = arcTheme.innerPadding} = attribute;
if (outerRadius += outerPadding, innerRadius -= innerPadding, outerRadius < innerRadius) {
const temp = outerRadius;
outerRadius = innerRadius, innerRadius = temp;
}
let {endAngle: endAngle = arcTheme.endAngle, startAngle: startAngle = arcTheme.startAngle} = attribute;
if (startAngle > endAngle) {
const temp = startAngle;
startAngle = endAngle, endAngle = temp;
}
return outerRadius <= epsilon ? aabbBounds.set(0, 0, 0, 0) : Math.abs(endAngle - startAngle) > pi2 - epsilon ? aabbBounds.set(-outerRadius, -outerRadius, outerRadius, outerRadius) : (circleBounds(startAngle, endAngle, outerRadius, aabbBounds),
circleBounds(startAngle, endAngle, innerRadius, aabbBounds)), aabbBounds;
}
needUpdateTags(keys) {
return super.needUpdateTags(keys, ARC_UPDATE_TAG_KEY);
}
needUpdateTag(key) {
return super.needUpdateTag(key, ARC_UPDATE_TAG_KEY);
}
toCustomPath() {
var _a, _b, _c, _d;
const attribute = this.attribute, {startAngle: startAngle, endAngle: endAngle} = this.getParsedAngle();
let innerRadius = (null !== (_a = attribute.innerRadius) && void 0 !== _a ? _a : 0) - (null !== (_b = attribute.innerPadding) && void 0 !== _b ? _b : 0), outerRadius = (null !== (_c = attribute.outerRadius) && void 0 !== _c ? _c : 0) - (null !== (_d = attribute.outerPadding) && void 0 !== _d ? _d : 0);
const deltaAngle = abs(endAngle - startAngle), clockwise = endAngle > startAngle;
if (outerRadius < innerRadius) {
const temp = outerRadius;
outerRadius = innerRadius, innerRadius = temp;
}
const path = new CustomPath2D;
if (outerRadius <= epsilon) path.moveTo(0, 0); else if (deltaAngle >= pi2 - epsilon) path.moveTo(0 + outerRadius * cos(startAngle), 0 + outerRadius * sin(startAngle)),
path.arc(0, 0, outerRadius, startAngle, endAngle, !clockwise), innerRadius > epsilon && (path.moveTo(0 + innerRadius * cos(endAngle), 0 + innerRadius * sin(endAngle)),
path.arc(0, 0, innerRadius, endAngle, startAngle, clockwise)); else {
const xors = outerRadius * cos(startAngle), yors = outerRadius * sin(startAngle), xire = innerRadius * cos(endAngle), yire = innerRadius * sin(endAngle);
path.moveTo(0 + xors, 0 + yors), path.arc(0, 0, outerRadius, startAngle, endAngle, !clockwise),
path.lineTo(0 + xire, 0 + yire), path.arc(0, 0, innerRadius, endAngle, startAngle, clockwise),
path.closePath();
}
return path;
}
clone() {
return new Arc(Object.assign({}, this.attribute));
}
getNoWorkAnimateAttr() {
return Arc.NOWORK_ANIMATE_ATTR;
}
}
Arc.NOWORK_ANIMATE_ATTR = Object.assign({
cap: 1
}, NOWORK_ANIMATE_ATTR);
export function createArc(attributes) {
return new Arc(attributes);
}
//# sourceMappingURL=arc.js.map