UNPKG

@visactor/vrender-core

Version:
173 lines (161 loc) 10.6 kB
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