Simplify a bit arc calculation

This commit is contained in:
barsdeveloper
2025-01-24 19:32:24 +02:00
parent c356878e3f
commit 15a1769b95
10 changed files with 67 additions and 104 deletions

View File

@@ -192,7 +192,7 @@ ueb-link > svg {
width: 100% !important; width: 100% !important;
height: 100% !important; height: 100% !important;
min-height: 1px !important; min-height: 1px !important;
transform: scaleY(var(--ueb-link-scale-y)); transform: scaleX(var(--ueb-link-scale-x)) scaleY(var(--ueb-link-scale-y));
z-index: 1; z-index: 1;
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

78
dist/ueblueprint.js vendored
View File

@@ -105,7 +105,9 @@ class Configuration {
*/ */
static linkRightSVGPath = (start, c1, c2, arc = false) => { static linkRightSVGPath = (start, c1, c2, arc = false) => {
const end = 100 - start; const end = 100 - start;
const mid = arc ? 100 : 50; const mid = arc
? 50 + (c2 - start)
: 50;
const fin = arc ? end + c1 - start : end - c1 + start; const fin = arc ? end + c1 - start : end - c1 + start;
return `M ${start} 0 C ${c1.toFixed(2)} 0, ${c2.toFixed(2)} 0, ${mid} 50 S ${fin.toFixed(2)} 100, ` return `M ${start} 0 C ${c1.toFixed(2)} 0, ${c2.toFixed(2)} 0, ${mid} 50 S ${fin.toFixed(2)} 100, `
+ `${end.toFixed(3)} 100` + `${end.toFixed(3)} 100`
@@ -7638,35 +7640,13 @@ class LinkTemplate extends IFromToPositionedTemplate {
return x => a / x + q return x => a / x + q
} }
/** static clampedLine = x => Math.min(Math.max(0, x), 1)
* Returns a function providing a clamped line passing through two points. It is clamped after and before the
* points. It is easier explained with the following ascii draw.
* b ______
* /
* /
* /
* ______/ a
*/
static clampedLine(a, b) {
if (a[0] > b[0]) {
const temp = a;
a = b;
b = temp;
}
const m = (b[1] - a[1]) / (b[0] - a[0]);
const q = a[1] - m * a[0];
return x => x < a[0]
? a[1]
: x > b[0]
? b[1]
: m * x + q
}
static c1DecreasingValue = LinkTemplate.decreasingValue(-0.15, [100, 15]) static c1DecreasingValue = LinkTemplate.decreasingValue(-0.15, [100, 15])
static c2DecreasingValue = LinkTemplate.decreasingValue(-0.05, [500, 130]) static c2DecreasingValue = LinkTemplate.decreasingValue(-0.05, [500, 130])
static c2Clamped = LinkTemplate.clampedLine([0, 80], [200, 40]) static c2Clamped = x => -40 * LinkTemplate.clampedLine(x / 200) + 80
#uniqueId = `ueb-id-${Math.floor(Math.random() * 1E12)}` #uniqueId = `ueb-id-${Math.floor(Math.random() * 1E12)}`
@@ -7755,7 +7735,7 @@ class LinkTemplate extends IFromToPositionedTemplate {
knotTemplate.switchDirectionsVisually = rightPinsLocation < leftPinsLocation; knotTemplate.switchDirectionsVisually = rightPinsLocation < leftPinsLocation;
} }
} }
let sameDirection = originPin?.isInputVisually() == targetPin?.isInputVisually(); let sameDirection = originPin?.isOutputVisually() == targetPin?.isOutputVisually();
// Actual computation // Actual computation
const dx = Math.max(Math.abs(this.element.fromX - this.element.toX), 1); const dx = Math.max(Math.abs(this.element.fromX - this.element.toX), 1);
@@ -7768,23 +7748,28 @@ class LinkTemplate extends IFromToPositionedTemplate {
this.element.startPixels = dx < width // If under minimum width this.element.startPixels = dx < width // If under minimum width
? (width - dx) / 2 // Start from half the empty space ? (width - dx) / 2 // Start from half the empty space
: 0; // Otherwise start from the beginning : 0; // Otherwise start from the beginning
this.element.startPercentage = xInverted ? this.element.startPixels + fillRatio * 100 : this.element.startPixels; const startPercentage = xInverted ? this.element.startPixels + fillRatio * 100 : this.element.startPixels;
const c1 = this.element.startPercentage = startPercentage;
this.element.startPercentage const c1 = startPercentage + (sameDirection
+ (xInverted ? 5
? LinkTemplate.c1DecreasingValue(width) : (
: 10 (xInverted
? LinkTemplate.c1DecreasingValue(width)
: 10
)
* fillRatio
) )
* fillRatio; );
const aspectRatio = dy / Math.max(30, dx); const aspectRatio = dy / Math.max(30, dx);
const c2 = sameDirection const c2 = sameDirection
? (this.element.startPercentage + 50) // ? 100 - Math.abs(100 - 2 * startPercentage) + 15
? 100 * LinkTemplate.clampedLine(startPercentage / 50) + 15
: ( : (
LinkTemplate.c2Clamped(dx) LinkTemplate.c2Clamped(dx)
* LinkTemplate.sigmoidPositive(fillRatio * 1.2 + aspectRatio * 0.5, 1.5, 1.8) * LinkTemplate.sigmoidPositive(fillRatio * 1.2 + aspectRatio * 0.5, 1.5, 1.8)
+ this.element.startPercentage + startPercentage
); );
this.element.svgPathD = Configuration.linkRightSVGPath(this.element.startPercentage, c1, c2, sameDirection); this.element.svgPathD = Configuration.linkRightSVGPath(startPercentage, c1, c2, sameDirection);
} }
createInputObjects() { createInputObjects() {
@@ -7835,8 +7820,11 @@ class LinkTemplate extends IFromToPositionedTemplate {
this.element.style.setProperty("--ueb-start-percentage", `${Math.round(this.element.startPercentage)}%`); this.element.style.setProperty("--ueb-start-percentage", `${Math.round(this.element.startPercentage)}%`);
this.element.style.setProperty("--ueb-link-start", `${Math.round(this.element.startPixels)}`); this.element.style.setProperty("--ueb-link-start", `${Math.round(this.element.startPixels)}`);
const mirrorV = (this.element.fromY > this.element.toY ? -1 : 1) // If from is below to => mirror const mirrorV = (this.element.fromY > this.element.toY ? -1 : 1) // If from is below to => mirror
* (this.element.originatesFromInput ? -1 : 1); // Unless from refers to an input pin * (this.element.originatesFromInput ? -1 : 1) // Unless fro refers to an input pin
* (this.element.source?.isInputVisually() && this.element.destination?.isInputVisually() ? -1 : 1);
const mirrorH = (this.element.source?.isInputVisually() && this.element.destination?.isInputVisually() ? -1 : 1);
this.element.style.setProperty("--ueb-link-scale-y", `${mirrorV}`); this.element.style.setProperty("--ueb-link-scale-y", `${mirrorV}`);
this.element.style.setProperty("--ueb-link-scale-x", `${mirrorH}`);
} }
render() { render() {
@@ -9713,7 +9701,7 @@ class PinTemplate extends ITemplate {
getLinkLocation() { getLinkLocation() {
const rect = this.iconElement.getBoundingClientRect(); const rect = this.iconElement.getBoundingClientRect();
/** @type {[Number, Number]} */ /** @type {[Number, Number]} */
const boundingLocation = [this.element.isInput() ? rect.left : rect.right + 1, (rect.top + rect.bottom) / 2]; const boundingLocation = [this.element.isInputVisually() ? rect.left : rect.right + 1, (rect.top + rect.bottom) / 2];
const location = Utility.convertLocation(boundingLocation, this.blueprint.template.gridElement); const location = Utility.convertLocation(boundingLocation, this.blueprint.template.gridElement);
return this.blueprint.compensateTranslation(location[0], location[1]) return this.blueprint.compensateTranslation(location[0], location[1])
} }
@@ -9827,16 +9815,10 @@ class KnotPinTemplate extends MinimalPinTemplate {
} }
getLinkLocation() { getLinkLocation() {
const rect = ( if (this.element.isInput()) {
this.element.isInput() return this.oppositePin().getLinkLocation()
? /** @type {KnotNodeTemplate} */(this.element.nodeElement.template).outputPin.template }
: this return super.getLinkLocation()
)
.iconElement.getBoundingClientRect();
/** @type {Coordinates} */
const boundingLocation = [this.element.isInput() ? rect.left : rect.right + 1, (rect.top + rect.bottom) / 2];
const location = Utility.convertLocation(boundingLocation, this.blueprint.template.gridElement);
return this.blueprint.compensateTranslation(location[0], location[1])
} }
} }

File diff suppressed because one or more lines are too long

View File

@@ -81,7 +81,9 @@ export default class Configuration {
*/ */
static linkRightSVGPath = (start, c1, c2, arc = false) => { static linkRightSVGPath = (start, c1, c2, arc = false) => {
const end = 100 - start const end = 100 - start
const mid = arc ? 100 : 50 const mid = arc
? 50 + (c2 - start)
: 50
const fin = arc ? end + c1 - start : end - c1 + start const fin = arc ? end + c1 - start : end - c1 + start
return `M ${start} 0 C ${c1.toFixed(2)} 0, ${c2.toFixed(2)} 0, ${mid} 50 S ${fin.toFixed(2)} 100, ` return `M ${start} 0 C ${c1.toFixed(2)} 0, ${c2.toFixed(2)} 0, ${mid} 50 S ${fin.toFixed(2)} 100, `
+ `${end.toFixed(3)} 100` + `${end.toFixed(3)} 100`

View File

@@ -33,35 +33,13 @@ export default class LinkTemplate extends IFromToPositionedTemplate {
return x => a / x + q return x => a / x + q
} }
/** static clampedLine = x => Math.min(Math.max(0, x), 1)
* Returns a function providing a clamped line passing through two points. It is clamped after and before the
* points. It is easier explained with the following ascii draw.
* b ______
* /
* /
* /
* ______/ a
*/
static clampedLine(a, b) {
if (a[0] > b[0]) {
const temp = a
a = b
b = temp
}
const m = (b[1] - a[1]) / (b[0] - a[0])
const q = a[1] - m * a[0]
return x => x < a[0]
? a[1]
: x > b[0]
? b[1]
: m * x + q
}
static c1DecreasingValue = LinkTemplate.decreasingValue(-0.15, [100, 15]) static c1DecreasingValue = LinkTemplate.decreasingValue(-0.15, [100, 15])
static c2DecreasingValue = LinkTemplate.decreasingValue(-0.05, [500, 130]) static c2DecreasingValue = LinkTemplate.decreasingValue(-0.05, [500, 130])
static c2Clamped = LinkTemplate.clampedLine([0, 80], [200, 40]) static c2Clamped = x => -40 * LinkTemplate.clampedLine(x / 200) + 80
#uniqueId = `ueb-id-${Math.floor(Math.random() * 1E12)}` #uniqueId = `ueb-id-${Math.floor(Math.random() * 1E12)}`
@@ -150,7 +128,7 @@ export default class LinkTemplate extends IFromToPositionedTemplate {
knotTemplate.switchDirectionsVisually = rightPinsLocation < leftPinsLocation knotTemplate.switchDirectionsVisually = rightPinsLocation < leftPinsLocation
} }
} }
let sameDirection = originPin?.isInputVisually() == targetPin?.isInputVisually() let sameDirection = originPin?.isOutputVisually() == targetPin?.isOutputVisually()
// Actual computation // Actual computation
const dx = Math.max(Math.abs(this.element.fromX - this.element.toX), 1) const dx = Math.max(Math.abs(this.element.fromX - this.element.toX), 1)
@@ -163,23 +141,28 @@ export default class LinkTemplate extends IFromToPositionedTemplate {
this.element.startPixels = dx < width // If under minimum width this.element.startPixels = dx < width // If under minimum width
? (width - dx) / 2 // Start from half the empty space ? (width - dx) / 2 // Start from half the empty space
: 0 // Otherwise start from the beginning : 0 // Otherwise start from the beginning
this.element.startPercentage = xInverted ? this.element.startPixels + fillRatio * 100 : this.element.startPixels const startPercentage = xInverted ? this.element.startPixels + fillRatio * 100 : this.element.startPixels
const c1 = this.element.startPercentage = startPercentage
this.element.startPercentage const c1 = startPercentage + (sameDirection
+ (xInverted ? 5
? LinkTemplate.c1DecreasingValue(width) : (
: 10 (xInverted
? LinkTemplate.c1DecreasingValue(width)
: 10
)
* fillRatio
) )
* fillRatio )
const aspectRatio = dy / Math.max(30, dx) const aspectRatio = dy / Math.max(30, dx)
const c2 = sameDirection const c2 = sameDirection
? (this.element.startPercentage + 50) // ? 100 - Math.abs(100 - 2 * startPercentage) + 15
? 100 * LinkTemplate.clampedLine(startPercentage / 50) + 15
: ( : (
LinkTemplate.c2Clamped(dx) LinkTemplate.c2Clamped(dx)
* LinkTemplate.sigmoidPositive(fillRatio * 1.2 + aspectRatio * 0.5, 1.5, 1.8) * LinkTemplate.sigmoidPositive(fillRatio * 1.2 + aspectRatio * 0.5, 1.5, 1.8)
+ this.element.startPercentage + startPercentage
) )
this.element.svgPathD = Configuration.linkRightSVGPath(this.element.startPercentage, c1, c2, sameDirection) this.element.svgPathD = Configuration.linkRightSVGPath(startPercentage, c1, c2, sameDirection)
} }
createInputObjects() { createInputObjects() {
@@ -230,8 +213,11 @@ export default class LinkTemplate extends IFromToPositionedTemplate {
this.element.style.setProperty("--ueb-start-percentage", `${Math.round(this.element.startPercentage)}%`) this.element.style.setProperty("--ueb-start-percentage", `${Math.round(this.element.startPercentage)}%`)
this.element.style.setProperty("--ueb-link-start", `${Math.round(this.element.startPixels)}`) this.element.style.setProperty("--ueb-link-start", `${Math.round(this.element.startPixels)}`)
const mirrorV = (this.element.fromY > this.element.toY ? -1 : 1) // If from is below to => mirror const mirrorV = (this.element.fromY > this.element.toY ? -1 : 1) // If from is below to => mirror
* (this.element.originatesFromInput ? -1 : 1) // Unless from refers to an input pin * (this.element.originatesFromInput ? -1 : 1) // Unless fro refers to an input pin
* (this.element.source?.isInputVisually() && this.element.destination?.isInputVisually() ? -1 : 1)
const mirrorH = (this.element.source?.isInputVisually() && this.element.destination?.isInputVisually() ? -1 : 1)
this.element.style.setProperty("--ueb-link-scale-y", `${mirrorV}`) this.element.style.setProperty("--ueb-link-scale-y", `${mirrorV}`)
this.element.style.setProperty("--ueb-link-scale-x", `${mirrorH}`)
} }
render() { render() {

View File

@@ -1,5 +1,4 @@
import { html } from "lit" import { html } from "lit"
import Utility from "../../Utility.js"
import MinimalPinTemplate from "./MinimalPinTemplate.js" import MinimalPinTemplate from "./MinimalPinTemplate.js"
/** @extends MinimalPinTemplate<KnotEntity> */ /** @extends MinimalPinTemplate<KnotEntity> */
@@ -15,15 +14,9 @@ export default class KnotPinTemplate extends MinimalPinTemplate {
} }
getLinkLocation() { getLinkLocation() {
const rect = ( if (this.element.isInput()) {
this.element.isInput() return this.oppositePin().getLinkLocation()
? /** @type {KnotNodeTemplate} */(this.element.nodeElement.template).outputPin.template }
: this return super.getLinkLocation()
)
.iconElement.getBoundingClientRect()
/** @type {Coordinates} */
const boundingLocation = [this.element.isInput() ? rect.left : rect.right + 1, (rect.top + rect.bottom) / 2]
const location = Utility.convertLocation(boundingLocation, this.blueprint.template.gridElement)
return this.blueprint.compensateTranslation(location[0], location[1])
} }
} }

View File

@@ -174,7 +174,7 @@ export default class PinTemplate extends ITemplate {
getLinkLocation() { getLinkLocation() {
const rect = this.iconElement.getBoundingClientRect() const rect = this.iconElement.getBoundingClientRect()
/** @type {[Number, Number]} */ /** @type {[Number, Number]} */
const boundingLocation = [this.element.isInput() ? rect.left : rect.right + 1, (rect.top + rect.bottom) / 2] const boundingLocation = [this.element.isInputVisually() ? rect.left : rect.right + 1, (rect.top + rect.bottom) / 2]
const location = Utility.convertLocation(boundingLocation, this.blueprint.template.gridElement) const location = Utility.convertLocation(boundingLocation, this.blueprint.template.gridElement)
return this.blueprint.compensateTranslation(location[0], location[1]) return this.blueprint.compensateTranslation(location[0], location[1])
} }

View File

@@ -19,7 +19,7 @@ ueb-link>svg {
width: 100% !important; width: 100% !important;
height: 100% !important; height: 100% !important;
min-height: 1px !important; min-height: 1px !important;
transform: scaleY(var(--ueb-link-scale-y)); transform: scaleX(var(--ueb-link-scale-x)) scaleY(var(--ueb-link-scale-y));
z-index: 1; z-index: 1;
} }