@amcharts/amcharts5
Version:
amCharts 5
231 lines • 10.3 kB
JavaScript
import { FlowLink } from "./FlowLink";
import * as $math from "../../core/util/Math";
export class SankeyLink extends FlowLink {
constructor() {
super(...arguments);
this._svgPath = document.createElementNS("http://www.w3.org/2000/svg", "path");
this._totalLength = 0;
}
_beforeChanged() {
super._beforeChanged();
if (this.isDirty("source")) {
if (this._sourceDp) {
this._sourceDp.dispose();
}
const source = this.get("source");
if (source) {
const sourceNode = source.get("node");
this._sourceDp = sourceNode.events.on("positionchanged", () => {
this.markDirty();
});
this._disposers.push(this._sourceDp);
}
}
if (this.isDirty("target")) {
if (this._targetDp) {
this._targetDp.dispose();
}
const target = this.get("target");
if (target) {
const targetNode = target.get("node");
this._targetDp = targetNode.events.on("positionchanged", () => {
this.markDirty();
});
this._disposers.push(this._targetDp);
}
}
if (this.isPrivateDirty("orientation")) {
const series = this.series;
const dataItem = this.dataItem;
if (dataItem && series) {
series._updateLinkColor(dataItem);
}
}
const target = this.get("target");
const source = this.get("source");
let sourceNode;
let targetNode;
if (source && target) {
this._clear = true;
sourceNode = source.get("node");
targetNode = target.get("node");
let x0 = 0;
let x1 = 0;
let y0 = 0;
let y1 = 0;
let xt0 = 0;
let yt0 = 0;
let xt1 = 0;
let yt1 = 0;
let xb0 = 0;
let xb1 = 0;
let yb0 = 0;
let yb1 = 0;
let xm0 = 0;
let xm1 = 0;
let ym0 = 0;
let ym1 = 0;
let angle0 = 0;
let angle1 = 0;
const dataItem = this.dataItem;
if (dataItem) {
const d3SankeyLink = dataItem.get("d3SankeyLink");
if (d3SankeyLink) {
let w = d3SankeyLink.width || 0;
let orientation = this.getPrivate("orientation");
if (orientation == "vertical") {
if (sourceNode) {
y0 = sourceNode.y() + sourceNode.get("dy", 0);
}
if (targetNode) {
y1 = targetNode.y() + targetNode.get("dy", 0);
}
angle0 = 90;
angle1 = 90;
x0 = d3SankeyLink.y0 || 0;
x1 = d3SankeyLink.y1 || 0;
x0 += sourceNode.get("dx", 0);
x1 += targetNode.get("dx", 0);
if (y1 < y0) {
[x0, x1] = [x1, x0];
[y0, y1] = [y1, y0];
}
if (source.get("unknown")) {
x0 = x1;
y0 = y0 + (y1 - y0) / 2;
}
if (target.get("unknown")) {
x1 = x0;
y1 = y0 + (y1 - y0) / 2;
}
xt0 = x0 - w / 2;
yt0 = y0;
xt1 = x1 - w / 2;
yt1 = y1;
xb0 = x0 + w / 2;
xb1 = x1 + w / 2;
yb0 = y0;
yb1 = y1;
xm0 = x0;
xm1 = x1;
ym0 = y0;
ym1 = y1;
}
else {
if (sourceNode) {
x0 = sourceNode.x() + sourceNode.get("dx", 0);
}
if (targetNode) {
x1 = targetNode.x() + targetNode.get("dx", 0);
}
y0 = d3SankeyLink.y0 || 0;
y1 = d3SankeyLink.y1 || 0;
y0 += sourceNode.get("dy", 0);
y1 += targetNode.get("dy", 0);
if (x1 < x0) {
[x0, x1] = [x1, x0];
[y0, y1] = [y1, y0];
}
if (source.get("unknown")) {
y0 = y1;
x0 = x0 + (x1 - x0) / 2;
}
if (target.get("unknown")) {
y1 = y0;
x1 = x0 + (x1 - x0) / 2;
}
xt0 = x0;
yt0 = y0 - w / 2;
xt1 = x1;
yt1 = y1 - w / 2;
xb0 = x0;
xb1 = x1;
yb0 = y0 + w / 2;
yb1 = y1 + w / 2;
xm0 = x0;
xm1 = x1;
ym0 = y0;
ym1 = y1;
}
if ($math.round(xt0, 3) == $math.round(xt1, 3)) {
xt1 += 0.01;
}
if ($math.round(yt0, 3) == $math.round(yt1, 3)) {
yt1 += 0.01;
}
if ($math.round(xb0, 3) == $math.round(xb1, 3)) {
xb1 += 0.01;
}
if ($math.round(yb0, 3) == $math.round(yb1, 3)) {
yb1 += 0.01;
}
let cpd = this.get("controlPointDistance", 0.2);
cpd = Math.min(0.4999, cpd);
let kxt0 = xt0 + (xt1 - xt0) * cpd * $math.cos(angle0);
let kyt0 = yt0 + (yt1 - yt0) * cpd * $math.sin(angle0);
let kxt1 = xt1 - (xt1 - xt0) * cpd * $math.cos(angle1);
let kyt1 = yt1 - (yt1 - yt0) * cpd * $math.sin(angle1);
let kxm0 = xm0 + (xm1 - xm0) * cpd * $math.cos(angle0);
let kym0 = ym0 + (ym1 - ym0) * cpd * $math.sin(angle0);
let kxm1 = xm1 - (xm1 - xm0) * cpd * $math.cos(angle1);
let kym1 = ym1 - (ym1 - ym0) * cpd * $math.sin(angle1);
let angle = $math.getAngle({ x: kxt0, y: kyt0 }, { x: kxt1, y: kyt1 });
let dx = (w / $math.cos(angle) - w) / $math.tan(angle) * $math.cos(angle0);
let dy = (w / $math.sin(angle) - w) * $math.tan(angle) * $math.sin(angle0);
let kxb0 = -dx / 2 + xb0 + (xb1 - xb0) * cpd * $math.cos(angle0);
let kyb0 = -dy / 2 + yb0 + (yb1 - yb0) * cpd * $math.sin(angle0);
let kxb1 = -dx / 2 + xb1 - (xb1 - xb0) * cpd * $math.cos(angle1);
let kyb1 = -dy / 2 + yb1 - (yb1 - yb0) * cpd * $math.sin(angle1);
kxt0 += dx / 2;
kyt0 += dy / 2;
kxt1 += dx / 2;
kyt1 += dy / 2;
if (orientation == "vertical") {
kyt0 = Math.min(yt1, Math.max(yt0 + 1, kyt0));
kyb0 = Math.min(yb1, Math.max(yb0 + 1, kyb0));
kyt1 = Math.max(yt0, Math.min(yt1 - 1, kyt1));
kyb1 = Math.max(yb0, Math.min(yb1 - 1, kyb1));
}
else {
kxt0 = Math.min(xt1, Math.max(xt0 + 1, kxt0));
kxb0 = Math.min(xb1, Math.max(xb0 + 1, kxb0));
kxt1 = Math.max(xt0, Math.min(xt1 - 1, kxt1));
kxb1 = Math.max(xb0, Math.min(xb1 - 1, kxb1));
}
let segment = [[xt0, yt0, xb0, yb0], [kxt0, kyt0, kxb0, kyb0], [kxt1, kyt1, kxb1, kyb1], [xt1, yt1, xb1, yb1]];
this.set("draw", (display) => {
const series = this.series;
series._fillGenerator.context(display);
series._fillGenerator(segment);
});
let middleSegment = [[xm0, ym0], [kxm0, kym0], [kxm1, kym1], [xm1, ym1]];
const path = this.series._strokeGenerator(middleSegment);
if (path) {
this._svgPath.setAttribute("d", path);
this._totalLength = this._svgPath.getTotalLength();
}
}
}
}
if (this.series && this.dataItem) {
this.series._positionBullets(this.dataItem);
}
}
getPoint(location) {
if (this._svgPath) {
if (this._svgPath.getAttribute("d")) {
let p0 = this._svgPath.getPointAtLength(location * this._totalLength - 0.1);
let p1 = this._svgPath.getPointAtLength(location * this._totalLength + 0.1);
let p = this.toGlobal(this._svgPath.getPointAtLength(location * this._totalLength));
return { x: p.x, y: p.y, angle: $math.getAngle(p0, p1) };
}
}
return { x: 0, y: 0, angle: 0 };
}
_getTooltipPoint() {
return this.toLocal(super._getTooltipPoint());
}
}
SankeyLink.className = "SankeyLink";
SankeyLink.classNames = FlowLink.classNames.concat([SankeyLink.className]);
//# sourceMappingURL=SankeyLink.js.map