itk-viewer-transfer-function-editor
Advanced tools
Comparing version 1.3.1 to 1.4.0
@@ -22,2 +22,3 @@ import { ColorRangeType } from './ColorRange'; | ||
root: HTMLDivElement; | ||
svg: SVGSVGElement; | ||
}; | ||
@@ -24,0 +25,0 @@ canvas: HTMLCanvasElement; |
@@ -12,3 +12,3 @@ import { Point } from './Point'; | ||
export type ColorRangeType = ReturnType<typeof ColorRange>; | ||
export declare const ColorRangeController: (container: ContainerType, colorRange: ColorRangeType) => { | ||
export declare const ColorRangeController: (container: ContainerType, colorRange: ColorRangeType, toDataSpace: (x: number) => number) => { | ||
points: ControlPoint[]; | ||
@@ -15,0 +15,0 @@ setColorTransferFunction: (colorTransferFunction: ColorTransferFunction) => void; |
@@ -18,3 +18,4 @@ export declare const PADDING = 10; | ||
root: HTMLDivElement; | ||
svg: SVGSVGElement; | ||
}; | ||
export type ContainerType = ReturnType<typeof Container>; |
@@ -18,4 +18,5 @@ export declare const makeTestableContainer: () => { | ||
root: HTMLDivElement; | ||
svg: SVGSVGElement; | ||
}; | ||
parent: HTMLDivElement; | ||
}; |
import { ContainerType } from './Container'; | ||
import { Point } from './Point'; | ||
import { addTooltip } from './addTooltip'; | ||
export declare const CONTROL_POINT_CLASS = "controlPoint"; | ||
@@ -7,2 +8,3 @@ export declare class ControlPoint { | ||
circle: SVGCircleElement; | ||
tooltip: ReturnType<typeof addTooltip>; | ||
private container; | ||
@@ -17,7 +19,9 @@ private isDragging; | ||
private grabY; | ||
constructor(container: ContainerType, point: Point, deleteEventCallback?: (event: CustomEvent) => void, isNewPointFromPointer?: boolean); | ||
private toDataSpace; | ||
static styleElement: HTMLStyleElement | undefined; | ||
constructor(container: ContainerType, point: Point, toDataSpace: (x: number) => number, deleteEventCallback?: (event: CustomEvent) => void, isNewPointFromPointer?: boolean); | ||
remove(): void; | ||
private positionElement; | ||
movePoint(e: PointerEvent): void; | ||
updateStrokeWidth(): void; | ||
update(): void; | ||
startInteraction(forceDragging?: boolean): void; | ||
@@ -24,0 +28,0 @@ setupInteraction(): void; |
@@ -9,3 +9,4 @@ import { ContainerType } from './Container'; | ||
private isNewPointFromPointer; | ||
constructor(container: ContainerType, points: Points); | ||
private toDataSpace; | ||
constructor(container: ContainerType, points: Points, toDataSpace: (x: number) => number); | ||
remove(): void; | ||
@@ -12,0 +13,0 @@ onPointerDown(event: PointerEvent): void; |
@@ -12,2 +12,3 @@ import { ColorTransferFunction } from './PiecewiseUtils'; | ||
private background; | ||
private dataSpaceConverter; | ||
constructor(root: HTMLElement); | ||
@@ -14,0 +15,0 @@ remove(): void; |
@@ -1,10 +0,10 @@ | ||
var K = Object.defineProperty; | ||
var Z = (n, t, e) => t in n ? K(n, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : n[t] = e; | ||
var r = (n, t, e) => (Z(n, typeof t != "symbol" ? t + "" : t, e), e); | ||
const D = (n) => Math.max(0, Math.min(1, n)); | ||
class I { | ||
var Z = Object.defineProperty; | ||
var q = (n, t, e) => t in n ? Z(n, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : n[t] = e; | ||
var a = (n, t, e) => (q(n, typeof t != "symbol" ? t + "" : t, e), e); | ||
const B = (n) => Math.max(0, Math.min(1, n)); | ||
class N { | ||
constructor(t, e) { | ||
r(this, "_x"); | ||
r(this, "_y"); | ||
r(this, "eventTarget", new EventTarget()); | ||
a(this, "_x"); | ||
a(this, "_y"); | ||
a(this, "eventTarget", new EventTarget()); | ||
this.x = t, this.y = e; | ||
@@ -16,3 +16,3 @@ } | ||
set x(t) { | ||
this._x = D(t), this.dispatchUpdatedEvent(); | ||
this._x = B(t), this.dispatchUpdatedEvent(); | ||
} | ||
@@ -23,3 +23,3 @@ get y() { | ||
set y(t) { | ||
this._y = D(t), this.dispatchUpdatedEvent(); | ||
this._y = B(t), this.dispatchUpdatedEvent(); | ||
} | ||
@@ -35,3 +35,3 @@ setPosition(t, e) { | ||
} | ||
const O = (n, t = !1) => { | ||
const X = (n, t = !1) => { | ||
if (n.length === 0) | ||
@@ -43,15 +43,15 @@ return [ | ||
if (n.length === 1) { | ||
const [, o] = n[0]; | ||
const [, i] = n[0]; | ||
return [ | ||
[0, o], | ||
[1, o] | ||
[0, i], | ||
[1, i] | ||
]; | ||
} | ||
const e = n[0], i = n[n.length - 1]; | ||
return t ? [[e[0], 0], ...n, [i[0], 0]] : [[0, e[1]], ...n, [1, i[1]]]; | ||
}, V = (n) => O(n.map(({ x: t, y: e }) => [t, e])); | ||
class q { | ||
const e = n[0], o = n[n.length - 1]; | ||
return t ? [[e[0], 0], ...n, [o[0], 0]] : [[0, e[1]], ...n, [1, o[1]]]; | ||
}, $ = (n) => X(n.map(({ x: t, y: e }) => [t, e])); | ||
class J { | ||
constructor() { | ||
r(this, "_points", []); | ||
r(this, "eventTarget", new EventTarget()); | ||
a(this, "_points", []); | ||
a(this, "eventTarget", new EventTarget()); | ||
} | ||
@@ -63,8 +63,8 @@ get points() { | ||
addPoint(t, e) { | ||
const i = this.createPoint(t, e); | ||
return this.dispatchUpdatedEvent(), i; | ||
const o = this.createPoint(t, e); | ||
return this.dispatchUpdatedEvent(), o; | ||
} | ||
// does not call this.dispatchUpdatedEvent() assuming setPoints() holds external point state and will update downstream function | ||
addPoints(t) { | ||
return t.map(([i, o]) => this.createPoint(i, o)); | ||
return t.map(([o, i]) => this.createPoint(o, i)); | ||
} | ||
@@ -83,6 +83,6 @@ setPoints(t) { | ||
createPoint(t, e) { | ||
const i = new I(t, e); | ||
return i.eventTarget.addEventListener("updated", () => { | ||
this._points.sort((o, a) => o.x - a.x), this.dispatchUpdatedEvent(); | ||
}), this._points.push(i), this._points.sort((o, a) => o.x - a.x), i; | ||
const o = new N(t, e); | ||
return o.eventTarget.addEventListener("updated", () => { | ||
this._points.sort((i, r) => i.x - r.x), this.dispatchUpdatedEvent(); | ||
}), this._points.push(o), this._points.sort((i, r) => i.x - r.x), o; | ||
} | ||
@@ -93,3 +93,3 @@ deletePoint(t) { | ||
} | ||
const J = (n, t, e, i = { | ||
const Q = (n, t, e, o = { | ||
lineWidth: 1, | ||
@@ -100,11 +100,11 @@ strokeStyle: "#000", | ||
}) => { | ||
const o = t[3], a = t[2] / (e.length - 1), d = o + t[1]; | ||
n.lineWidth = i.lineWidth, n.strokeStyle = i.strokeStyle, n.beginPath(), n.moveTo(t[0], t[1] + t[3]); | ||
const i = t[3], r = t[2] / (e.length - 1), l = i + t[1]; | ||
n.lineWidth = o.lineWidth, n.strokeStyle = o.strokeStyle, n.beginPath(), n.moveTo(t[0], t[1] + t[3]); | ||
for (let s = 0; s < e.length; s++) | ||
n.lineTo( | ||
t[0] + s * a, | ||
Math.max(t[1], d - e[s] * o) | ||
t[0] + s * r, | ||
Math.max(t[1], l - e[s] * i) | ||
); | ||
if (i.fillStyle) { | ||
if (n.fillStyle = i.fillStyle, n.lineTo(t[0] + t[2], t[1] + t[3]), i.clip) { | ||
if (o.fillStyle) { | ||
if (n.fillStyle = o.fillStyle, n.lineTo(t[0] + t[2], t[1] + t[3]), o.clip) { | ||
n.clip(); | ||
@@ -116,7 +116,7 @@ return; | ||
n.stroke(); | ||
}, _ = 1, Q = (n, t, e, i) => { | ||
const o = i || document.createElement("canvas"); | ||
if (o.setAttribute("width", String(t)), o.setAttribute("height", String(_)), n.getSize() === 0) | ||
return o; | ||
const a = n.getUint8Table( | ||
}, D = 1, tt = (n, t, e, o) => { | ||
const i = o || document.createElement("canvas"); | ||
if (i.setAttribute("width", String(t)), i.setAttribute("height", String(D)), n.getSize() === 0) | ||
return i; | ||
const r = n.getUint8Table( | ||
e[0], | ||
@@ -126,23 +126,23 @@ e[1], | ||
!0 | ||
), d = o.getContext("2d"); | ||
if (d) { | ||
const s = d.getImageData(0, 0, t, _); | ||
for (let h = 0; h < _; h++) | ||
s.data.set(a, h * 4 * t); | ||
const c = _ * t * 4; | ||
for (let h = 3; h < c; h += 4) | ||
s.data[h] = 255; | ||
d.putImageData(s, 0, 0); | ||
), l = i.getContext("2d"); | ||
if (l) { | ||
const s = l.getImageData(0, 0, t, D); | ||
for (let d = 0; d < D; d++) | ||
s.data.set(r, d * 4 * t); | ||
const c = D * t * 4; | ||
for (let d = 3; d < c; d += 4) | ||
s.data[d] = 255; | ||
l.putImageData(s, 0, 0); | ||
} | ||
return o; | ||
}, mt = (n) => { | ||
const t = O(n); | ||
return i; | ||
}, bt = (n) => { | ||
const t = X(n); | ||
return t[0][0] -= 1e-8, t[t.length - 1][0] += 1e-8, t; | ||
}, tt = (n) => { | ||
}, et = (n) => { | ||
if (!n) | ||
return []; | ||
const t = n.map((s) => s === 0 ? 0 : Math.log(s)), e = t.filter(Boolean), i = Math.min(...e), a = Math.max(...e) - i; | ||
return t.map((s) => s === 0 ? 0 : (s - i) / a); | ||
const t = n.map((s) => s === 0 ? 0 : Math.log(s)), e = t.filter(Boolean), o = Math.min(...e), r = Math.max(...e) - o; | ||
return t.map((s) => s === 0 ? 0 : (s - o) / r); | ||
}; | ||
function et(n, t) { | ||
function nt(n, t) { | ||
if (n.length !== t.length) | ||
@@ -155,6 +155,6 @@ return !1; | ||
} | ||
function B(n) { | ||
function F(n) { | ||
return `#${n.map((e) => Math.floor(e * 255)).map((e) => `0${e.toString(16)}`.slice(-2)).join("")}`; | ||
} | ||
const x = 10, nt = () => { | ||
const R = 10, ot = () => { | ||
const n = document.createElementNS("http://www.w3.org/2000/svg", "svg"); | ||
@@ -171,65 +171,118 @@ return n.setAttribute( | ||
), n.appendChild(t); | ||
const e = nt(); | ||
const e = ot(); | ||
t.appendChild(e); | ||
const i = new EventTarget(), o = (l) => { | ||
i.addEventListener("sizeupdated", l); | ||
const o = new EventTarget(), i = (h) => { | ||
o.addEventListener("sizeupdated", h); | ||
}; | ||
new ResizeObserver(() => { | ||
i.dispatchEvent(new Event("sizeupdated")); | ||
o.dispatchEvent(new Event("sizeupdated")); | ||
}).observe(t); | ||
const d = document.createElementNS( | ||
const l = document.createElementNS( | ||
"http://www.w3.org/2000/svg", | ||
"rect" | ||
); | ||
e.appendChild(d), d.setAttribute("fill", "none"), d.setAttribute("stroke", "black"); | ||
const s = (l) => { | ||
e.appendChild(l); | ||
}, c = (l) => { | ||
e.removeChild(l); | ||
e.appendChild(l), l.setAttribute("fill", "none"), l.setAttribute("stroke", "black"); | ||
const s = (h) => { | ||
e.appendChild(h); | ||
}, c = (h) => { | ||
e.removeChild(h); | ||
}; | ||
let h = [0, 1, 0, 1]; | ||
const y = () => h, p = (l, u, m = 0, g = 1) => { | ||
const w = h; | ||
h = [l, u, m, g], et(w, h) || i.dispatchEvent(new Event("sizeupdated")); | ||
}, S = () => { | ||
const { top: l, left: u, width: m, height: g } = t.getBoundingClientRect(); | ||
let d = [0, 1, 0, 1]; | ||
const E = () => d, p = (h, m, v = 0, g = 1) => { | ||
const b = d; | ||
d = [h, m, v, g], nt(b, d) || o.dispatchEvent(new Event("sizeupdated")); | ||
}, f = () => { | ||
const { top: h, left: m, width: v, height: g } = t.getBoundingClientRect(); | ||
return { | ||
width: m - 2 * x, | ||
height: g - 2 * x, | ||
top: l + x, | ||
left: u + x | ||
width: v - 2 * R, | ||
height: g - 2 * R, | ||
top: h + R, | ||
left: m + R | ||
}; | ||
}, R = (l, u) => { | ||
const { top: m, left: g, width: w, height: C } = S(), v = h[1] - h[0] || 1e-3, T = h[3] - h[2] || 1e-3; | ||
}, S = (h, m) => { | ||
const { top: v, left: g, width: b, height: x } = f(), w = d[1] - d[0] || 1e-3, A = d[3] - d[2] || 1e-3; | ||
return [ | ||
(l - g) / w * v + h[0], | ||
(1 - (u - m) / C) * T + h[2] | ||
(h - g) / b * w + d[0], | ||
(1 - (m - v) / x) * A + d[2] | ||
]; | ||
}, f = (l, u) => { | ||
const { width: m, height: g } = S(), w = h[1] - h[0] || 1e-3, C = (l - h[0]) / w * m + x, v = h[3] - h[2] || 1e-3, T = (1 - (u - h[2]) / v) * g + x; | ||
return [C, T]; | ||
}, E = () => { | ||
const [l, u] = f(0, 0), [m, g] = f(1, 1); | ||
return { left: l, bottom: u, right: m, top: g }; | ||
}, u = (h, m) => { | ||
const { width: v, height: g } = f(), b = d[1] - d[0] || 1e-3, x = (h - d[0]) / b * v + R, w = d[3] - d[2] || 1e-3, A = (1 - (m - d[2]) / w) * g + R; | ||
return [x, A]; | ||
}, C = () => { | ||
const [h, m] = u(0, 0), [v, g] = u(1, 1); | ||
return { left: h, bottom: m, right: v, top: g }; | ||
}; | ||
return o(() => { | ||
const { left: l, bottom: u, right: m, top: g } = E(); | ||
d.setAttribute("x", `${l}`), d.setAttribute("y", `${g}`), d.setAttribute("width", `${Math.max(0, m - l)}`), d.setAttribute("height", `${Math.max(0, u - g)}`); | ||
return i(() => { | ||
const { left: h, bottom: m, right: v, top: g } = C(); | ||
l.setAttribute("x", `${h}`), l.setAttribute("y", `${g}`), l.setAttribute("width", `${Math.max(0, v - h)}`), l.setAttribute("height", `${Math.max(0, m - g)}`); | ||
}), { | ||
appendChild: s, | ||
removeChild: c, | ||
addSizeObserver: o, | ||
getViewBox: y, | ||
addSizeObserver: i, | ||
getViewBox: E, | ||
setViewBox: p, | ||
domToNormalized: R, | ||
normalizedToSvg: f, | ||
borderSize: E, | ||
domToNormalized: S, | ||
normalizedToSvg: u, | ||
borderSize: C, | ||
remove: () => n.removeChild(t), | ||
root: t | ||
root: t, | ||
svg: e | ||
}; | ||
}, ot = "controlPoint", k = 2, st = 8, X = 14, b = X, rt = () => { | ||
}; | ||
let O = !1; | ||
const st = () => { | ||
if (O) | ||
return; | ||
O = !0; | ||
const n = document.createElement("style"); | ||
n.innerHTML = ` | ||
.tfeditor-svg-tooltip { | ||
color: black; | ||
background-color: rgba(255, 255, 255, 0.95); | ||
position: absolute; | ||
transform: translate(178px, 410.19px); | ||
border-style: solid; | ||
border-color: black; | ||
border-width: 1px; | ||
border-radius: 2px; | ||
font-size: 12px; | ||
padding: 8px; | ||
visibility: hidden; | ||
max-width: 150px; | ||
} | ||
`, document.head.appendChild(n); | ||
}; | ||
function rt(n) { | ||
st(); | ||
const t = [10, 10], e = document.createElementNS( | ||
"http://www.w3.org/2000/svg", | ||
"foreignObject" | ||
); | ||
e.setAttribute("width", "100%"), e.setAttribute("height", "100%"), e.setAttribute("pointer-events", "none"); | ||
const o = document.createElementNS( | ||
"http://www.w3.org/1999/xhtml", | ||
"div" | ||
); | ||
o.setAttribute("class", "tfeditor-svg-tooltip"), e.appendChild(o), n.append(e); | ||
function i(c, d, E) { | ||
let p = d + t[0], f = E + t[1]; | ||
o.innerHTML = c; | ||
const S = n.getBBox(), u = o.getBoundingClientRect(); | ||
p > S.width - u.width && (p = d - u.width - t[0]), f > S.height - u.height && (f = E - u.height - t[1]), o.style.transform = `translate(${p}px,${f}px)`; | ||
} | ||
function r() { | ||
o.style.visibility = "visible"; | ||
} | ||
function l() { | ||
o.style.visibility = "hidden"; | ||
} | ||
return { update: i, show: r, hide: l, remove: () => { | ||
n.removeChild(e); | ||
} }; | ||
} | ||
const at = "controlPoint", M = 2, dt = 8, W = 14, T = W, lt = () => { | ||
const n = document.createElementNS("http://www.w3.org/2000/svg", "svg"); | ||
n.setAttribute("width", String(b * 2)), n.setAttribute("height", String(b * 2)), n.setAttribute( | ||
n.setAttribute("width", String(T * 2)), n.setAttribute("height", String(T * 2)), n.setAttribute( | ||
"viewBox", | ||
`-${b} -${b} ${b * 2} ${b * 2}` | ||
`-${T} -${T} ${T * 2} ${T * 2}` | ||
); | ||
@@ -240,3 +293,3 @@ const t = document.createElementNS( | ||
); | ||
t.setAttribute("r", String(st)), t.setAttribute("fill", "white"), t.setAttribute("stroke", "black"), t.setAttribute("stroke-width", String(k)), t.setAttribute("class", ot), n.appendChild(t); | ||
t.setAttribute("r", String(dt)), t.setAttribute("fill", "white"), t.setAttribute("stroke", "black"), t.setAttribute("stroke-width", String(M)), t.setAttribute("class", at), n.appendChild(t); | ||
const e = document.createElementNS( | ||
@@ -246,68 +299,72 @@ "http://www.w3.org/2000/svg", | ||
); | ||
return e.setAttribute("r", String(X)), e.setAttribute("fill", "transparent"), e.setAttribute("stroke", "transparent"), e.setAttribute("style", "cursor: move;"), n.appendChild(e), { group: n, circle: t, clickTarget: e }; | ||
return e.setAttribute("r", String(W)), e.setAttribute("fill", "transparent"), e.setAttribute("stroke", "transparent"), e.setAttribute("style", "cursor: move;"), n.appendChild(e), { group: n, circle: t, clickTarget: e }; | ||
}; | ||
class H { | ||
constructor(t, e, i, o = !1) { | ||
r(this, "element"); | ||
r(this, "circle"); | ||
r(this, "container"); | ||
r(this, "isDragging", !1); | ||
r(this, "isHovered", !1); | ||
r(this, "point"); | ||
r(this, "deletable", !0); | ||
r(this, "DELETE_EVENT", "deleteme"); | ||
r(this, "eventTarget", new EventTarget()); | ||
r(this, "grabX", 0); | ||
r(this, "grabY", 0); | ||
const { group: a, circle: d } = rt(); | ||
this.element = a, this.circle = d, this.point = e, this.container = t, t.addSizeObserver(() => { | ||
class _ { | ||
constructor(t, e, o, i, r = !1) { | ||
a(this, "element"); | ||
a(this, "circle"); | ||
a(this, "tooltip"); | ||
a(this, "container"); | ||
a(this, "isDragging", !1); | ||
a(this, "isHovered", !1); | ||
a(this, "point"); | ||
a(this, "deletable", !0); | ||
a(this, "DELETE_EVENT", "deleteme"); | ||
a(this, "eventTarget", new EventTarget()); | ||
a(this, "grabX", 0); | ||
a(this, "grabY", 0); | ||
a(this, "toDataSpace"); | ||
const { group: l, circle: s } = lt(); | ||
this.element = l, this.circle = s, this.point = e, this.container = t, this.toDataSpace = o, this.tooltip = rt(this.container.svg), t.addSizeObserver(() => { | ||
this.positionElement(); | ||
}), i && this.eventTarget.addEventListener(this.DELETE_EVENT, (s) => { | ||
i(s); | ||
}), i && this.eventTarget.addEventListener(this.DELETE_EVENT, (c) => { | ||
i(c); | ||
}), t.appendChild(this.element), this.positionElement(), this.point.eventTarget.addEventListener( | ||
"updated", | ||
() => this.positionElement() | ||
), this.setupInteraction(), o && this.startInteraction(!0); | ||
), this.setupInteraction(), r && this.startInteraction(!0); | ||
} | ||
remove() { | ||
this.container.removeChild(this.element); | ||
this.tooltip.remove(), this.container.removeChild(this.element); | ||
} | ||
positionElement() { | ||
const { x: t, y: e } = this.point, [i, o] = this.container.normalizedToSvg(t, e); | ||
this.element.setAttribute("x", String(i - b)), this.element.setAttribute("y", String(o - b)); | ||
const { x: t, y: e } = this.point, [o, i] = this.container.normalizedToSvg(t, e); | ||
this.element.setAttribute("x", String(o - T)), this.element.setAttribute("y", String(i - T)); | ||
const r = this.toDataSpace(t); | ||
this.tooltip.update(String(r), o, i); | ||
} | ||
movePoint(t) { | ||
const [e, i] = this.container.domToNormalized(t.clientX, t.clientY); | ||
this.point.setPosition(e + this.grabX, i + this.grabY), this.positionElement(); | ||
const [e, o] = this.container.domToNormalized(t.clientX, t.clientY); | ||
this.point.setPosition(e + this.grabX, o + this.grabY), this.positionElement(); | ||
} | ||
updateStrokeWidth() { | ||
this.circle.setAttribute("stroke-width", String(k)), this.isHovered && this.circle.setAttribute("stroke-width", String(k + 1)), this.isDragging && this.circle.setAttribute("stroke-width", String(k * 2)); | ||
update() { | ||
this.circle.setAttribute("stroke-width", String(M)), this.isHovered ? (this.circle.setAttribute("stroke-width", String(M + 1)), this.tooltip.show()) : this.tooltip.hide(), this.isDragging && this.circle.setAttribute("stroke-width", String(M * 2)); | ||
} | ||
startInteraction(t = !1) { | ||
this.isDragging = t, !this.isDragging && this.deletable && this.circle.setAttribute("stroke", "red"); | ||
const e = (o) => { | ||
this.isDragging = !0, this.circle.setAttribute("stroke", "black"), this.movePoint(o); | ||
const e = (i) => { | ||
this.isDragging = !0, this.circle.setAttribute("stroke", "black"), this.movePoint(i); | ||
}; | ||
document.addEventListener("pointermove", e); | ||
const i = () => { | ||
if (document.removeEventListener("pointermove", e), document.removeEventListener("pointerup", i), !this.isDragging) { | ||
const o = new CustomEvent(this.DELETE_EVENT, { detail: this }); | ||
this.eventTarget.dispatchEvent(o); | ||
const o = () => { | ||
if (document.removeEventListener("pointermove", e), document.removeEventListener("pointerup", o), !this.isDragging) { | ||
const i = new CustomEvent(this.DELETE_EVENT, { detail: this }); | ||
this.eventTarget.dispatchEvent(i); | ||
} | ||
this.isDragging = !1, this.updateStrokeWidth(); | ||
this.isDragging = !1, this.update(); | ||
}; | ||
document.addEventListener("pointerup", i); | ||
document.addEventListener("pointerup", o); | ||
} | ||
setupInteraction() { | ||
this.element.addEventListener("pointerdown", (t) => { | ||
t.stopPropagation(), this.circle.setAttribute("stroke-width", String(k * 2)); | ||
const [e, i] = this.container.domToNormalized( | ||
t.stopPropagation(), this.circle.setAttribute("stroke-width", String(M * 2)); | ||
const [e, o] = this.container.domToNormalized( | ||
t.clientX, | ||
t.clientY | ||
); | ||
this.grabX = this.point.x - e, this.grabY = this.point.y - i, this.startInteraction(); | ||
this.grabX = this.point.x - e, this.grabY = this.point.y - o, this.startInteraction(); | ||
}), this.element.addEventListener("pointerenter", () => { | ||
this.isHovered = !0, this.updateStrokeWidth(); | ||
this.isHovered = !0, this.update(); | ||
}), this.element.addEventListener("pointerleave", () => { | ||
this.isHovered = !1, this.updateStrokeWidth(); | ||
this.isHovered = !1, this.update(); | ||
}); | ||
@@ -319,12 +376,14 @@ } | ||
} | ||
class at { | ||
constructor(t, e) { | ||
r(this, "container"); | ||
r(this, "points"); | ||
r(this, "onPointsUpdated"); | ||
r(this, "controlPoints", []); | ||
r(this, "isNewPointFromPointer", !1); | ||
this.container = t, this.points = e; | ||
a(_, "styleElement"); | ||
class ct { | ||
constructor(t, e, o) { | ||
a(this, "container"); | ||
a(this, "points"); | ||
a(this, "onPointsUpdated"); | ||
a(this, "controlPoints", []); | ||
a(this, "isNewPointFromPointer", !1); | ||
a(this, "toDataSpace"); | ||
this.container = t, this.points = e, this.toDataSpace = o; | ||
const { root: i } = t; | ||
i.addEventListener("pointerdown", (o) => this.onPointerDown(o)), this.onPointsUpdated = () => this.updatePoints(), this.points.eventTarget.addEventListener("updated", this.onPointsUpdated), this.updatePoints(); | ||
i.addEventListener("pointerdown", (r) => this.onPointerDown(r)), this.onPointsUpdated = () => this.updatePoints(), this.points.eventTarget.addEventListener("updated", this.onPointsUpdated), this.updatePoints(); | ||
} | ||
@@ -335,4 +394,4 @@ remove() { | ||
onPointerDown(t) { | ||
const [e, i] = this.container.domToNormalized(t.clientX, t.clientY); | ||
this.isNewPointFromPointer = !0, this.points.addPoint(e, i), this.isNewPointFromPointer = !1; | ||
const [e, o] = this.container.domToNormalized(t.clientX, t.clientY); | ||
this.isNewPointFromPointer = !0, this.points.addPoint(e, o), this.isNewPointFromPointer = !1; | ||
} | ||
@@ -344,19 +403,20 @@ onControlPointDelete(t) { | ||
const t = this.controlPoints.filter( | ||
(o) => !this.points.points.find((a) => a === o.point) | ||
(i) => !this.points.points.find((r) => r === i.point) | ||
); | ||
t.forEach((o) => o.remove()), this.controlPoints = this.controlPoints.filter( | ||
(o) => !t.includes(o) | ||
t.forEach((i) => i.remove()), this.controlPoints = this.controlPoints.filter( | ||
(i) => !t.includes(i) | ||
); | ||
const e = (o) => this.controlPoints.find((a) => a.point === o), i = (o) => this.controlPoints.push( | ||
new H( | ||
const e = (i) => this.controlPoints.find((r) => r.point === i), o = (i) => this.controlPoints.push( | ||
new _( | ||
this.container, | ||
o, | ||
(a) => this.onControlPointDelete(a), | ||
i, | ||
this.toDataSpace, | ||
(r) => this.onControlPointDelete(r), | ||
this.isNewPointFromPointer | ||
) | ||
); | ||
this.points.points.filter((o) => !e(o)).forEach(i); | ||
this.points.points.filter((i) => !e(i)).forEach(o); | ||
} | ||
} | ||
const dt = () => { | ||
const ht = () => { | ||
const n = document.createElementNS( | ||
@@ -368,9 +428,9 @@ "http://www.w3.org/2000/svg", | ||
}; | ||
class ht { | ||
class pt { | ||
constructor(t, e) { | ||
r(this, "points"); | ||
r(this, "container"); | ||
r(this, "onPointsUpdated"); | ||
r(this, "element"); | ||
this.container = t, this.points = e, this.element = dt(), this.container.appendChild(this.element), this.onPointsUpdated = () => this.update(), this.points.eventTarget.addEventListener("updated", this.onPointsUpdated), this.container.addSizeObserver(() => { | ||
a(this, "points"); | ||
a(this, "container"); | ||
a(this, "onPointsUpdated"); | ||
a(this, "element"); | ||
this.container = t, this.points = e, this.element = ht(), this.container.appendChild(this.element), this.onPointsUpdated = () => this.update(), this.points.eventTarget.addEventListener("updated", this.onPointsUpdated), this.container.addSizeObserver(() => { | ||
this.update(); | ||
@@ -387,45 +447,45 @@ }), this.update(); | ||
} | ||
const t = V(this.points.points).map(([e, i]) => this.container.normalizedToSvg(e, i)).map(([e, i]) => `${e},${i}`).join(" "); | ||
const t = $(this.points.points).map(([e, o]) => this.container.normalizedToSvg(e, o)).map(([e, o]) => `${e},${o}`).join(" "); | ||
this.element.setAttribute("points", t); | ||
} | ||
} | ||
const W = 1.1, lt = (n) => { | ||
const V = 1.1, gt = (n) => { | ||
n.root.addEventListener("wheel", (t) => { | ||
const e = t.deltaY > 0 ? W : 1 / W, [i] = n.domToNormalized(t.clientX, t.clientY), [o, a] = n.getViewBox(), d = Math.max( | ||
const e = t.deltaY > 0 ? V : 1 / V, [o] = n.domToNormalized(t.clientX, t.clientY), [i, r] = n.getViewBox(), l = Math.max( | ||
0, | ||
o - Math.max(0, i - o) * (e - 1) | ||
), s = Math.min(1, (a - o) * e + d); | ||
d === o && s === a || (t.preventDefault(), t.stopPropagation(), n.setViewBox(d, s)); | ||
i - Math.max(0, o - i) * (e - 1) | ||
), s = Math.min(1, (r - i) * e + l); | ||
l === i && s === r || (t.preventDefault(), t.stopPropagation(), n.setViewBox(l, s)); | ||
}); | ||
}, F = "rgba(50, 50, 50, 0.3)", ct = (n, t, e) => { | ||
const i = document.createElement("canvas"); | ||
n.root.appendChild(i), i.setAttribute("style", "width: 100%; height: 100%; "); | ||
const o = i.getContext("2d"); | ||
let a, d; | ||
}, H = "rgba(50, 50, 50, 0.3)", ut = (n, t, e) => { | ||
const o = document.createElement("canvas"); | ||
n.root.appendChild(o), o.setAttribute("style", "width: 100%; height: 100%; "); | ||
const i = o.getContext("2d"); | ||
let r, l; | ||
const s = document.createElement("canvas"), c = () => { | ||
if (o) { | ||
if (o.clearRect(0, 0, i.width, i.height), a) { | ||
const { width: p, height: S } = n.root.getBoundingClientRect(); | ||
i.setAttribute("width", String(p)), i.setAttribute("height", String(S)); | ||
const { left: R, right: f, bottom: E, top: P } = n.borderSize(); | ||
if (Math.ceil(f - R) < 0) | ||
if (i) { | ||
if (i.clearRect(0, 0, o.width, o.height), r) { | ||
const { width: p, height: f } = n.root.getBoundingClientRect(); | ||
o.setAttribute("width", String(p)), o.setAttribute("height", String(f)); | ||
const { left: S, right: u, bottom: C, top: P } = n.borderSize(); | ||
if (Math.ceil(u - S) < 0) | ||
return; | ||
const l = V(t.points), u = [[0, 0], ...l, [1, 0]].map( | ||
([A, L]) => n.normalizedToSvg(A, L) | ||
const h = $(t.points), m = [[0, 0], ...h, [1, 0]].map( | ||
([y, L]) => n.normalizedToSvg(y, L) | ||
); | ||
o.save(), o.beginPath(), u.forEach(([A, L]) => { | ||
o.lineTo(A, L); | ||
}), o.clip(); | ||
const [m, g] = e.getColorRange(), [w] = n.normalizedToSvg(m, 1), [C] = n.normalizedToSvg(g, 1), v = Math.min(p, Math.max(0, w)), T = Math.min(p, Math.max(0, C)), M = T - v < 2 ? v + 2 : T, N = Math.ceil(M - v); | ||
if (a) { | ||
const A = C - w, L = (v - w) / A, Y = (M - C) / A, z = a.getMappingRange(), U = z[1] - z[0], G = [ | ||
i.save(), i.beginPath(), m.forEach(([y, L]) => { | ||
i.lineTo(y, L); | ||
}), i.clip(); | ||
const [v, g] = e.getColorRange(), [b] = n.normalizedToSvg(v, 1), [x] = n.normalizedToSvg(g, 1), w = Math.min(p, Math.max(0, b)), A = Math.min(p, Math.max(0, x)), k = A - w < 2 ? w + 2 : A, I = Math.ceil(k - w); | ||
if (r) { | ||
const y = x - b, L = (w - b) / y, j = (k - x) / y, z = r.getMappingRange(), U = z[1] - z[0], G = [ | ||
z[0] + U * L, | ||
z[1] + U * Y | ||
z[1] + U * j | ||
]; | ||
Q( | ||
a, | ||
N, | ||
tt( | ||
r, | ||
I, | ||
G, | ||
s | ||
), o.drawImage( | ||
), i.drawImage( | ||
s, | ||
@@ -436,9 +496,9 @@ 0, | ||
s.height, | ||
Math.floor(v), | ||
Math.floor(w), | ||
Math.floor(P), | ||
N, | ||
Math.ceil(E - P) | ||
I, | ||
Math.ceil(C - P) | ||
); | ||
const j = o.imageSmoothingEnabled; | ||
o.imageSmoothingEnabled = !1, o.drawImage( | ||
const K = i.imageSmoothingEnabled; | ||
i.imageSmoothingEnabled = !1, i.drawImage( | ||
s, | ||
@@ -451,5 +511,5 @@ 0, | ||
Math.floor(P), | ||
Math.floor(v), | ||
Math.ceil(E - P) | ||
), o.drawImage( | ||
Math.floor(w), | ||
Math.ceil(C - P) | ||
), i.drawImage( | ||
s, | ||
@@ -460,16 +520,16 @@ s.width - 1, | ||
1, | ||
Math.floor(M), | ||
Math.floor(k), | ||
Math.floor(P), | ||
p - M, | ||
Math.ceil(E - P) | ||
), o.imageSmoothingEnabled = j; | ||
p - k, | ||
Math.ceil(C - P) | ||
), i.imageSmoothingEnabled = K; | ||
} | ||
o.restore(); | ||
i.restore(); | ||
} | ||
if (d) { | ||
const { left: p, right: S, bottom: R, top: f } = n.borderSize(), E = [p, f, S - p, R - f]; | ||
J(o, E, d, { | ||
if (l) { | ||
const { left: p, right: f, bottom: S, top: u } = n.borderSize(), C = [p, u, f - p, S - u]; | ||
Q(i, C, l, { | ||
lineWidth: 1, | ||
strokeStyle: F, | ||
fillStyle: F | ||
strokeStyle: H, | ||
fillStyle: H | ||
}); | ||
@@ -481,68 +541,82 @@ } | ||
container: n, | ||
canvas: i, | ||
canvas: o, | ||
setColorTransferFunction: (p) => { | ||
a = p, c(); | ||
r = p, c(); | ||
}, | ||
setHistogram: (p) => { | ||
d = p, c(); | ||
l = p, c(); | ||
}, | ||
render: c, | ||
remove: () => n.root.removeChild(i) | ||
remove: () => n.root.removeChild(o) | ||
}; | ||
}, pt = () => { | ||
const n = [new I(0, 0), new I(1, 0)], t = () => n.sort((s, c) => s.x - c.x), e = () => t().map((s) => s.x), i = new EventTarget(), o = () => i.dispatchEvent( | ||
}, mt = () => { | ||
const n = [new N(0, 0), new N(1, 0)], t = () => n.sort((s, c) => s.x - c.x), e = () => t().map((s) => s.x), o = new EventTarget(), i = () => o.dispatchEvent( | ||
new CustomEvent("updated", { detail: e() }) | ||
); | ||
let a = !1; | ||
const d = (s) => { | ||
let r = !1; | ||
const l = (s) => { | ||
s.eventTarget.addEventListener("updated", () => { | ||
s.y !== 0 && (s.y = 0), a || o(); | ||
s.y !== 0 && (s.y = 0), r || i(); | ||
}); | ||
}; | ||
return n.forEach(d), { | ||
return n.forEach(l), { | ||
getPoints: t, | ||
getColorRange: e, | ||
setColorRange: (s) => { | ||
a = !0, t().forEach((c, h) => { | ||
c.x = s[h]; | ||
}), a = !1, o(); | ||
r = !0, t().forEach((c, d) => { | ||
c.x = s[d]; | ||
}), r = !1, i(); | ||
}, | ||
eventTarget: i | ||
eventTarget: o | ||
}; | ||
}, gt = (n, t) => { | ||
const e = t.getPoints().map((d) => { | ||
const s = new H(n, d); | ||
return s.deletable = !1, s; | ||
}, vt = (n, t, e) => { | ||
const o = t.getPoints().map((s) => { | ||
const c = new _(n, s, e); | ||
return c.deletable = !1, c; | ||
}); | ||
let i; | ||
const o = () => { | ||
const r = () => { | ||
if (!i) | ||
return; | ||
const d = i.getMappingRange(), s = []; | ||
i.getColor(d[0], s); | ||
const c = []; | ||
i.getColor(d[1], c); | ||
const h = e.sort((y, p) => y.point.x - p.point.x); | ||
h[0].setColor(B(s)), h[1].setColor(B(c)); | ||
}, a = (d) => { | ||
i = d, o(); | ||
const s = i.getMappingRange(), c = []; | ||
i.getColor(s[0], c); | ||
const d = []; | ||
i.getColor(s[1], d); | ||
const E = o.sort((p, f) => p.point.x - f.point.x); | ||
E[0].setColor(F(c)), E[1].setColor(F(d)); | ||
}, l = (s) => { | ||
i = s, r(); | ||
}; | ||
return t.eventTarget.addEventListener("updated", () => { | ||
o(); | ||
r(); | ||
}), { | ||
points: e, | ||
setColorTransferFunction: a | ||
points: o, | ||
setColorTransferFunction: l | ||
}; | ||
}, ft = () => { | ||
let n; | ||
return { | ||
setColorTransferFunction: (o) => { | ||
n = o; | ||
}, | ||
toDataSpace: (o) => { | ||
if (!n) | ||
return o; | ||
const [i, r] = n.getMappingRange(), l = r - i; | ||
return o * l + i; | ||
} | ||
}; | ||
}; | ||
class vt { | ||
class Et { | ||
constructor(t) { | ||
r(this, "eventTarget", new EventTarget()); | ||
r(this, "points"); | ||
r(this, "colorRange"); | ||
r(this, "colorRangeController"); | ||
r(this, "line"); | ||
r(this, "pointController"); | ||
r(this, "container"); | ||
r(this, "background"); | ||
this.container = it(t), lt(this.container), this.points = new q(); | ||
a(this, "eventTarget", new EventTarget()); | ||
a(this, "points"); | ||
a(this, "colorRange"); | ||
a(this, "colorRangeController"); | ||
a(this, "line"); | ||
a(this, "pointController"); | ||
a(this, "container"); | ||
a(this, "background"); | ||
a(this, "dataSpaceConverter", ft()); | ||
this.container = it(t), gt(this.container), this.points = new J(); | ||
const e = [ | ||
@@ -552,12 +626,17 @@ [0, 0], | ||
]; | ||
this.points.setPoints(e), this.line = new ht(this.container, this.points), this.pointController = new at(this.container, this.points), this.colorRange = pt(), this.colorRangeController = gt( | ||
this.points.setPoints(e), this.line = new pt(this.container, this.points), this.pointController = new ct( | ||
this.container, | ||
this.colorRange | ||
), this.background = ct(this.container, this.points, this.colorRange), this.points.eventTarget.addEventListener("updated", (i) => { | ||
this.points, | ||
this.dataSpaceConverter.toDataSpace | ||
), this.colorRange = mt(), this.colorRangeController = vt( | ||
this.container, | ||
this.colorRange, | ||
this.dataSpaceConverter.toDataSpace | ||
), this.background = ut(this.container, this.points, this.colorRange), this.points.eventTarget.addEventListener("updated", (o) => { | ||
this.eventTarget.dispatchEvent( | ||
new CustomEvent("updated", { detail: i.detail }) | ||
new CustomEvent("updated", { detail: o.detail }) | ||
); | ||
}), this.colorRange.eventTarget.addEventListener("updated", (i) => { | ||
}), this.colorRange.eventTarget.addEventListener("updated", (o) => { | ||
this.eventTarget.dispatchEvent( | ||
new CustomEvent("colorRange", { detail: i.detail }) | ||
new CustomEvent("colorRange", { detail: o.detail }) | ||
); | ||
@@ -583,15 +662,15 @@ }); | ||
} | ||
setViewBox(t, e, i = 0, o = 1) { | ||
this.container.setViewBox(t, e, i, o); | ||
setViewBox(t, e, o = 0, i = 1) { | ||
this.container.setViewBox(t, e, o, i); | ||
} | ||
setColorTransferFunction(t) { | ||
this.background.setColorTransferFunction(t), this.colorRangeController.setColorTransferFunction(t); | ||
this.dataSpaceConverter.setColorTransferFunction(t), this.background.setColorTransferFunction(t), this.colorRangeController.setColorTransferFunction(t); | ||
} | ||
setHistogram(t) { | ||
this.background.setHistogram(tt(t)); | ||
this.background.setHistogram(et(t)); | ||
} | ||
} | ||
export { | ||
vt as TransferFunctionEditor, | ||
mt as windowPointsForSort | ||
Et as TransferFunctionEditor, | ||
bt as windowPointsForSort | ||
}; |
@@ -1,1 +0,16 @@ | ||
(function(m,g){typeof exports=="object"&&typeof module<"u"?g(exports):typeof define=="function"&&define.amd?define(["exports"],g):(m=typeof globalThis<"u"?globalThis:m||self,g(m.TransferFunctionEditor={}))})(this,function(m){"use strict";var mt=Object.defineProperty;var vt=(m,g,E)=>g in m?mt(m,g,{enumerable:!0,configurable:!0,writable:!0,value:E}):m[g]=E;var r=(m,g,E)=>(vt(m,typeof g!="symbol"?g+"":g,E),E);const g=n=>Math.max(0,Math.min(1,n));class E{constructor(t,e){r(this,"_x");r(this,"_y");r(this,"eventTarget",new EventTarget);this.x=t,this.y=e}get x(){return this._x}set x(t){this._x=g(t),this.dispatchUpdatedEvent()}get y(){return this._y}set y(t){this._y=g(t),this.dispatchUpdatedEvent()}setPosition(t,e){this.x=t,this.y=e,this.dispatchUpdatedEvent()}dispatchUpdatedEvent(){this.eventTarget.dispatchEvent(new CustomEvent("updated",{detail:[this.x,this.y]}))}}const D=(n,t=!1)=>{if(n.length===0)return[[0,1],[1,1]];if(n.length===1){const[,o]=n[0];return[[0,o],[1,o]]}const e=n[0],i=n[n.length-1];return t?[[e[0],0],...n,[i[0],0]]:[[0,e[1]],...n,[1,i[1]]]},B=n=>D(n.map(({x:t,y:e})=>[t,e]));class Y{constructor(){r(this,"_points",[]);r(this,"eventTarget",new EventTarget)}get points(){return[...this._points]}addPoint(t,e){const i=this.createPoint(t,e);return this.dispatchUpdatedEvent(),i}addPoints(t){return t.map(([i,o])=>this.createPoint(i,o))}setPoints(t){return[...this._points].forEach(e=>this.deletePoint(e)),this.addPoints(t)}removePoint(t){this.deletePoint(t),this.dispatchUpdatedEvent()}dispatchUpdatedEvent(){this.eventTarget.dispatchEvent(new CustomEvent("updated",{detail:this._points}))}createPoint(t,e){const i=new E(t,e);return i.eventTarget.addEventListener("updated",()=>{this._points.sort((o,a)=>o.x-a.x),this.dispatchUpdatedEvent()}),this._points.push(i),this._points.sort((o,a)=>o.x-a.x),i}deletePoint(t){this._points=this._points.filter(e=>e!==t)}}const j=(n,t,e,i={lineWidth:1,strokeStyle:"#000",fillStyle:void 0,clip:!1})=>{const o=t[3],a=t[2]/(e.length-1),d=o+t[1];n.lineWidth=i.lineWidth,n.strokeStyle=i.strokeStyle,n.beginPath(),n.moveTo(t[0],t[1]+t[3]);for(let s=0;s<e.length;s++)n.lineTo(t[0]+s*a,Math.max(t[1],d-e[s]*o));if(i.fillStyle){if(n.fillStyle=i.fillStyle,n.lineTo(t[0]+t[2],t[1]+t[3]),i.clip){n.clip();return}n.fill()}n.stroke()},_=1,G=(n,t,e,i)=>{const o=i||document.createElement("canvas");if(o.setAttribute("width",String(t)),o.setAttribute("height",String(_)),n.getSize()===0)return o;const a=n.getUint8Table(e[0],e[1],t,!0),d=o.getContext("2d");if(d){const s=d.getImageData(0,0,t,_);for(let h=0;h<_;h++)s.data.set(a,h*4*t);const c=_*t*4;for(let h=3;h<c;h+=4)s.data[h]=255;d.putImageData(s,0,0)}return o},K=n=>{const t=D(n);return t[0][0]-=1e-8,t[t.length-1][0]+=1e-8,t},Z=n=>{if(!n)return[];const t=n.map(s=>s===0?0:Math.log(s)),e=t.filter(Boolean),i=Math.min(...e),a=Math.max(...e)-i;return t.map(s=>s===0?0:(s-i)/a)};function q(n,t){if(n.length!==t.length)return!1;for(let e=0;e<n.length;e++)if(n[e]!==t[e])return!1;return!0}function F(n){return`#${n.map(e=>Math.floor(e*255)).map(e=>`0${e.toString(16)}`.slice(-2)).join("")}`}const x=10,J=()=>{const n=document.createElementNS("http://www.w3.org/2000/svg","svg");return n.setAttribute("style","position: absolute; top: 0; left: 0; z-index: 2; box-sizing: border-box; width: 100%; height: 100%;"),n},Q=n=>{const t=document.createElement("div");t.setAttribute("style","position: relative; width: 100%; height: 100%; user-select: none;"),n.appendChild(t);const e=J();t.appendChild(e);const i=new EventTarget,o=l=>{i.addEventListener("sizeupdated",l)};new ResizeObserver(()=>{i.dispatchEvent(new Event("sizeupdated"))}).observe(t);const d=document.createElementNS("http://www.w3.org/2000/svg","rect");e.appendChild(d),d.setAttribute("fill","none"),d.setAttribute("stroke","black");const s=l=>{e.appendChild(l)},c=l=>{e.removeChild(l)};let h=[0,1,0,1];const I=()=>h,p=(l,v,f=0,u=1)=>{const b=h;h=[l,v,f,u],q(b,h)||i.dispatchEvent(new Event("sizeupdated"))},R=()=>{const{top:l,left:v,width:f,height:u}=t.getBoundingClientRect();return{width:f-2*x,height:u-2*x,top:l+x,left:v+x}},M=(l,v)=>{const{top:f,left:u,width:b,height:A}=R(),w=h[1]-h[0]||.001,y=h[3]-h[2]||.001;return[(l-u)/b*w+h[0],(1-(v-f)/A)*y+h[2]]},C=(l,v)=>{const{width:f,height:u}=R(),b=h[1]-h[0]||.001,A=(l-h[0])/b*f+x,w=h[3]-h[2]||.001,y=(1-(v-h[2])/w)*u+x;return[A,y]},S=()=>{const[l,v]=C(0,0),[f,u]=C(1,1);return{left:l,bottom:v,right:f,top:u}};return o(()=>{const{left:l,bottom:v,right:f,top:u}=S();d.setAttribute("x",`${l}`),d.setAttribute("y",`${u}`),d.setAttribute("width",`${Math.max(0,f-l)}`),d.setAttribute("height",`${Math.max(0,v-u)}`)}),{appendChild:s,removeChild:c,addSizeObserver:o,getViewBox:I,setViewBox:p,domToNormalized:M,normalizedToSvg:C,borderSize:S,remove:()=>n.removeChild(t),root:t}},tt="controlPoint",k=2,et=8,O=14,P=O,nt=()=>{const n=document.createElementNS("http://www.w3.org/2000/svg","svg");n.setAttribute("width",String(P*2)),n.setAttribute("height",String(P*2)),n.setAttribute("viewBox",`-${P} -${P} ${P*2} ${P*2}`);const t=document.createElementNS("http://www.w3.org/2000/svg","circle");t.setAttribute("r",String(et)),t.setAttribute("fill","white"),t.setAttribute("stroke","black"),t.setAttribute("stroke-width",String(k)),t.setAttribute("class",tt),n.appendChild(t);const e=document.createElementNS("http://www.w3.org/2000/svg","circle");return e.setAttribute("r",String(O)),e.setAttribute("fill","transparent"),e.setAttribute("stroke","transparent"),e.setAttribute("style","cursor: move;"),n.appendChild(e),{group:n,circle:t,clickTarget:e}};class W{constructor(t,e,i,o=!1){r(this,"element");r(this,"circle");r(this,"container");r(this,"isDragging",!1);r(this,"isHovered",!1);r(this,"point");r(this,"deletable",!0);r(this,"DELETE_EVENT","deleteme");r(this,"eventTarget",new EventTarget);r(this,"grabX",0);r(this,"grabY",0);const{group:a,circle:d}=nt();this.element=a,this.circle=d,this.point=e,this.container=t,t.addSizeObserver(()=>{this.positionElement()}),i&&this.eventTarget.addEventListener(this.DELETE_EVENT,s=>{i(s)}),t.appendChild(this.element),this.positionElement(),this.point.eventTarget.addEventListener("updated",()=>this.positionElement()),this.setupInteraction(),o&&this.startInteraction(!0)}remove(){this.container.removeChild(this.element)}positionElement(){const{x:t,y:e}=this.point,[i,o]=this.container.normalizedToSvg(t,e);this.element.setAttribute("x",String(i-P)),this.element.setAttribute("y",String(o-P))}movePoint(t){const[e,i]=this.container.domToNormalized(t.clientX,t.clientY);this.point.setPosition(e+this.grabX,i+this.grabY),this.positionElement()}updateStrokeWidth(){this.circle.setAttribute("stroke-width",String(k)),this.isHovered&&this.circle.setAttribute("stroke-width",String(k+1)),this.isDragging&&this.circle.setAttribute("stroke-width",String(k*2))}startInteraction(t=!1){this.isDragging=t,!this.isDragging&&this.deletable&&this.circle.setAttribute("stroke","red");const e=o=>{this.isDragging=!0,this.circle.setAttribute("stroke","black"),this.movePoint(o)};document.addEventListener("pointermove",e);const i=()=>{if(document.removeEventListener("pointermove",e),document.removeEventListener("pointerup",i),!this.isDragging){const o=new CustomEvent(this.DELETE_EVENT,{detail:this});this.eventTarget.dispatchEvent(o)}this.isDragging=!1,this.updateStrokeWidth()};document.addEventListener("pointerup",i)}setupInteraction(){this.element.addEventListener("pointerdown",t=>{t.stopPropagation(),this.circle.setAttribute("stroke-width",String(k*2));const[e,i]=this.container.domToNormalized(t.clientX,t.clientY);this.grabX=this.point.x-e,this.grabY=this.point.y-i,this.startInteraction()}),this.element.addEventListener("pointerenter",()=>{this.isHovered=!0,this.updateStrokeWidth()}),this.element.addEventListener("pointerleave",()=>{this.isHovered=!1,this.updateStrokeWidth()})}setColor(t){this.circle.setAttribute("fill",t)}}class it{constructor(t,e){r(this,"container");r(this,"points");r(this,"onPointsUpdated");r(this,"controlPoints",[]);r(this,"isNewPointFromPointer",!1);this.container=t,this.points=e;const{root:i}=t;i.addEventListener("pointerdown",o=>this.onPointerDown(o)),this.onPointsUpdated=()=>this.updatePoints(),this.points.eventTarget.addEventListener("updated",this.onPointsUpdated),this.updatePoints()}remove(){this.points.eventTarget.removeEventListener("updated",this.onPointsUpdated)}onPointerDown(t){const[e,i]=this.container.domToNormalized(t.clientX,t.clientY);this.isNewPointFromPointer=!0,this.points.addPoint(e,i),this.isNewPointFromPointer=!1}onControlPointDelete(t){this.points.removePoint(t.detail.point)}updatePoints(){const t=this.controlPoints.filter(o=>!this.points.points.find(a=>a===o.point));t.forEach(o=>o.remove()),this.controlPoints=this.controlPoints.filter(o=>!t.includes(o));const e=o=>this.controlPoints.find(a=>a.point===o),i=o=>this.controlPoints.push(new W(this.container,o,a=>this.onControlPointDelete(a),this.isNewPointFromPointer));this.points.points.filter(o=>!e(o)).forEach(i)}}const ot=()=>{const n=document.createElementNS("http://www.w3.org/2000/svg","polyline");return n.setAttribute("fill","none"),n.setAttribute("stroke","black"),n.setAttribute("stroke-width","2"),n};class st{constructor(t,e){r(this,"points");r(this,"container");r(this,"onPointsUpdated");r(this,"element");this.container=t,this.points=e,this.element=ot(),this.container.appendChild(this.element),this.onPointsUpdated=()=>this.update(),this.points.eventTarget.addEventListener("updated",this.onPointsUpdated),this.container.addSizeObserver(()=>{this.update()}),this.update()}remove(){this.points.eventTarget.removeEventListener("updated",this.onPointsUpdated)}update(){if(this.points.points.length===0){this.element.setAttribute("points","");return}const t=B(this.points.points).map(([e,i])=>this.container.normalizedToSvg(e,i)).map(([e,i])=>`${e},${i}`).join(" ");this.element.setAttribute("points",t)}}const V=1.1,rt=n=>{n.root.addEventListener("wheel",t=>{const e=t.deltaY>0?V:1/V,[i]=n.domToNormalized(t.clientX,t.clientY),[o,a]=n.getViewBox(),d=Math.max(0,o-Math.max(0,i-o)*(e-1)),s=Math.min(1,(a-o)*e+d);d===o&&s===a||(t.preventDefault(),t.stopPropagation(),n.setViewBox(d,s))})},X="rgba(50, 50, 50, 0.3)",at=(n,t,e)=>{const i=document.createElement("canvas");n.root.appendChild(i),i.setAttribute("style","width: 100%; height: 100%; ");const o=i.getContext("2d");let a,d;const s=document.createElement("canvas"),c=()=>{if(o){if(o.clearRect(0,0,i.width,i.height),a){const{width:p,height:R}=n.root.getBoundingClientRect();i.setAttribute("width",String(p)),i.setAttribute("height",String(R));const{left:M,right:C,bottom:S,top:T}=n.borderSize();if(Math.ceil(C-M)<0)return;const l=B(t.points),v=[[0,0],...l,[1,0]].map(([L,z])=>n.normalizedToSvg(L,z));o.save(),o.beginPath(),v.forEach(([L,z])=>{o.lineTo(L,z)}),o.clip();const[f,u]=e.getColorRange(),[b]=n.normalizedToSvg(f,1),[A]=n.normalizedToSvg(u,1),w=Math.min(p,Math.max(0,b)),y=Math.min(p,Math.max(0,A)),N=y-w<2?w+2:y,H=Math.ceil(N-w);if(a){const L=A-b,z=(w-b)/L,pt=(N-A)/L,U=a.getMappingRange(),$=U[1]-U[0],gt=[U[0]+$*z,U[1]+$*pt];G(a,H,gt,s),o.drawImage(s,0,0,s.width,s.height,Math.floor(w),Math.floor(T),H,Math.ceil(S-T));const ut=o.imageSmoothingEnabled;o.imageSmoothingEnabled=!1,o.drawImage(s,0,0,1,1,0,Math.floor(T),Math.floor(w),Math.ceil(S-T)),o.drawImage(s,s.width-1,0,1,1,Math.floor(N),Math.floor(T),p-N,Math.ceil(S-T)),o.imageSmoothingEnabled=ut}o.restore()}if(d){const{left:p,right:R,bottom:M,top:C}=n.borderSize(),S=[p,C,R-p,M-C];j(o,S,d,{lineWidth:1,strokeStyle:X,fillStyle:X})}}};return n.addSizeObserver(c),t.eventTarget.addEventListener("updated",c),e.eventTarget.addEventListener("updated",c),{container:n,canvas:i,setColorTransferFunction:p=>{a=p,c()},setHistogram:p=>{d=p,c()},render:c,remove:()=>n.root.removeChild(i)}},dt=()=>{const n=[new E(0,0),new E(1,0)],t=()=>n.sort((s,c)=>s.x-c.x),e=()=>t().map(s=>s.x),i=new EventTarget,o=()=>i.dispatchEvent(new CustomEvent("updated",{detail:e()}));let a=!1;const d=s=>{s.eventTarget.addEventListener("updated",()=>{s.y!==0&&(s.y=0),a||o()})};return n.forEach(d),{getPoints:t,getColorRange:e,setColorRange:s=>{a=!0,t().forEach((c,h)=>{c.x=s[h]}),a=!1,o()},eventTarget:i}},ht=(n,t)=>{const e=t.getPoints().map(d=>{const s=new W(n,d);return s.deletable=!1,s});let i;const o=()=>{if(!i)return;const d=i.getMappingRange(),s=[];i.getColor(d[0],s);const c=[];i.getColor(d[1],c);const h=e.sort((I,p)=>I.point.x-p.point.x);h[0].setColor(F(s)),h[1].setColor(F(c))},a=d=>{i=d,o()};return t.eventTarget.addEventListener("updated",()=>{o()}),{points:e,setColorTransferFunction:a}};class lt{constructor(t){r(this,"eventTarget",new EventTarget);r(this,"points");r(this,"colorRange");r(this,"colorRangeController");r(this,"line");r(this,"pointController");r(this,"container");r(this,"background");this.container=Q(t),rt(this.container),this.points=new Y;const e=[[0,0],[1,1]];this.points.setPoints(e),this.line=new st(this.container,this.points),this.pointController=new it(this.container,this.points),this.colorRange=dt(),this.colorRangeController=ht(this.container,this.colorRange),this.background=at(this.container,this.points,this.colorRange),this.points.eventTarget.addEventListener("updated",i=>{this.eventTarget.dispatchEvent(new CustomEvent("updated",{detail:i.detail}))}),this.colorRange.eventTarget.addEventListener("updated",i=>{this.eventTarget.dispatchEvent(new CustomEvent("colorRange",{detail:i.detail}))})}remove(){this.background.remove(),this.container.remove()}getPoints(){return this.points.points.map(({x:t,y:e})=>[t,e])}setPoints(t){this.points.setPoints(t),this.pointController.updatePoints(),this.line.update(),this.background.render()}getColorRange(){return this.colorRange.getColorRange()}setColorRange(t){return this.colorRange.setColorRange(t)}setViewBox(t,e,i=0,o=1){this.container.setViewBox(t,e,i,o)}setColorTransferFunction(t){this.background.setColorTransferFunction(t),this.colorRangeController.setColorTransferFunction(t)}setHistogram(t){this.background.setHistogram(Z(t))}}m.TransferFunctionEditor=lt,m.windowPointsForSort=K,Object.defineProperty(m,Symbol.toStringTag,{value:"Module"})}); | ||
(function(m,g){typeof exports=="object"&&typeof module<"u"?g(exports):typeof define=="function"&&define.amd?define(["exports"],g):(m=typeof globalThis<"u"?globalThis:m||self,g(m.TransferFunctionEditor={}))})(this,function(m){"use strict";var bt=Object.defineProperty;var Et=(m,g,S)=>g in m?bt(m,g,{enumerable:!0,configurable:!0,writable:!0,value:S}):m[g]=S;var a=(m,g,S)=>(Et(m,typeof g!="symbol"?g+"":g,S),S);const g=n=>Math.max(0,Math.min(1,n));class S{constructor(t,e){a(this,"_x");a(this,"_y");a(this,"eventTarget",new EventTarget);this.x=t,this.y=e}get x(){return this._x}set x(t){this._x=g(t),this.dispatchUpdatedEvent()}get y(){return this._y}set y(t){this._y=g(t),this.dispatchUpdatedEvent()}setPosition(t,e){this.x=t,this.y=e,this.dispatchUpdatedEvent()}dispatchUpdatedEvent(){this.eventTarget.dispatchEvent(new CustomEvent("updated",{detail:[this.x,this.y]}))}}const B=(n,t=!1)=>{if(n.length===0)return[[0,1],[1,1]];if(n.length===1){const[,i]=n[0];return[[0,i],[1,i]]}const e=n[0],o=n[n.length-1];return t?[[e[0],0],...n,[o[0],0]]:[[0,e[1]],...n,[1,o[1]]]},F=n=>B(n.map(({x:t,y:e})=>[t,e]));class j{constructor(){a(this,"_points",[]);a(this,"eventTarget",new EventTarget)}get points(){return[...this._points]}addPoint(t,e){const o=this.createPoint(t,e);return this.dispatchUpdatedEvent(),o}addPoints(t){return t.map(([o,i])=>this.createPoint(o,i))}setPoints(t){return[...this._points].forEach(e=>this.deletePoint(e)),this.addPoints(t)}removePoint(t){this.deletePoint(t),this.dispatchUpdatedEvent()}dispatchUpdatedEvent(){this.eventTarget.dispatchEvent(new CustomEvent("updated",{detail:this._points}))}createPoint(t,e){const o=new S(t,e);return o.eventTarget.addEventListener("updated",()=>{this._points.sort((i,r)=>i.x-r.x),this.dispatchUpdatedEvent()}),this._points.push(o),this._points.sort((i,r)=>i.x-r.x),o}deletePoint(t){this._points=this._points.filter(e=>e!==t)}}const G=(n,t,e,o={lineWidth:1,strokeStyle:"#000",fillStyle:void 0,clip:!1})=>{const i=t[3],r=t[2]/(e.length-1),c=i+t[1];n.lineWidth=o.lineWidth,n.strokeStyle=o.strokeStyle,n.beginPath(),n.moveTo(t[0],t[1]+t[3]);for(let s=0;s<e.length;s++)n.lineTo(t[0]+s*r,Math.max(t[1],c-e[s]*i));if(o.fillStyle){if(n.fillStyle=o.fillStyle,n.lineTo(t[0]+t[2],t[1]+t[3]),o.clip){n.clip();return}n.fill()}n.stroke()},N=1,K=(n,t,e,o)=>{const i=o||document.createElement("canvas");if(i.setAttribute("width",String(t)),i.setAttribute("height",String(N)),n.getSize()===0)return i;const r=n.getUint8Table(e[0],e[1],t,!0),c=i.getContext("2d");if(c){const s=c.getImageData(0,0,t,N);for(let d=0;d<N;d++)s.data.set(r,d*4*t);const l=N*t*4;for(let d=3;d<l;d+=4)s.data[d]=255;c.putImageData(s,0,0)}return i},Z=n=>{const t=B(n);return t[0][0]-=1e-8,t[t.length-1][0]+=1e-8,t},q=n=>{if(!n)return[];const t=n.map(s=>s===0?0:Math.log(s)),e=t.filter(Boolean),o=Math.min(...e),r=Math.max(...e)-o;return t.map(s=>s===0?0:(s-o)/r)};function J(n,t){if(n.length!==t.length)return!1;for(let e=0;e<n.length;e++)if(n[e]!==t[e])return!1;return!0}function O(n){return`#${n.map(e=>Math.floor(e*255)).map(e=>`0${e.toString(16)}`.slice(-2)).join("")}`}const L=10,Q=()=>{const n=document.createElementNS("http://www.w3.org/2000/svg","svg");return n.setAttribute("style","position: absolute; top: 0; left: 0; z-index: 2; box-sizing: border-box; width: 100%; height: 100%;"),n},tt=n=>{const t=document.createElement("div");t.setAttribute("style","position: relative; width: 100%; height: 100%; user-select: none;"),n.appendChild(t);const e=Q();t.appendChild(e);const o=new EventTarget,i=h=>{o.addEventListener("sizeupdated",h)};new ResizeObserver(()=>{o.dispatchEvent(new Event("sizeupdated"))}).observe(t);const c=document.createElementNS("http://www.w3.org/2000/svg","rect");e.appendChild(c),c.setAttribute("fill","none"),c.setAttribute("stroke","black");const s=h=>{e.appendChild(h)},l=h=>{e.removeChild(h)};let d=[0,1,0,1];const P=()=>d,p=(h,f,w=0,u=1)=>{const C=d;d=[h,f,w,u],J(C,d)||o.dispatchEvent(new Event("sizeupdated"))},b=()=>{const{top:h,left:f,width:w,height:u}=t.getBoundingClientRect();return{width:w-2*L,height:u-2*L,top:h+L,left:f+L}},x=(h,f)=>{const{top:w,left:u,width:C,height:R}=b(),E=d[1]-d[0]||.001,M=d[3]-d[2]||.001;return[(h-u)/C*E+d[0],(1-(f-w)/R)*M+d[2]]},v=(h,f)=>{const{width:w,height:u}=b(),C=d[1]-d[0]||.001,R=(h-d[0])/C*w+L,E=d[3]-d[2]||.001,M=(1-(f-d[2])/E)*u+L;return[R,M]},A=()=>{const[h,f]=v(0,0),[w,u]=v(1,1);return{left:h,bottom:f,right:w,top:u}};return i(()=>{const{left:h,bottom:f,right:w,top:u}=A();c.setAttribute("x",`${h}`),c.setAttribute("y",`${u}`),c.setAttribute("width",`${Math.max(0,w-h)}`),c.setAttribute("height",`${Math.max(0,f-u)}`)}),{appendChild:s,removeChild:l,addSizeObserver:i,getViewBox:P,setViewBox:p,domToNormalized:x,normalizedToSvg:v,borderSize:A,remove:()=>n.removeChild(t),root:t,svg:e}};let V=!1;const et=()=>{if(V)return;V=!0;const n=document.createElement("style");n.innerHTML=` | ||
.tfeditor-svg-tooltip { | ||
color: black; | ||
background-color: rgba(255, 255, 255, 0.95); | ||
position: absolute; | ||
transform: translate(178px, 410.19px); | ||
border-style: solid; | ||
border-color: black; | ||
border-width: 1px; | ||
border-radius: 2px; | ||
font-size: 12px; | ||
padding: 8px; | ||
visibility: hidden; | ||
max-width: 150px; | ||
} | ||
`,document.head.appendChild(n)};function nt(n){et();const t=[10,10],e=document.createElementNS("http://www.w3.org/2000/svg","foreignObject");e.setAttribute("width","100%"),e.setAttribute("height","100%"),e.setAttribute("pointer-events","none");const o=document.createElementNS("http://www.w3.org/1999/xhtml","div");o.setAttribute("class","tfeditor-svg-tooltip"),e.appendChild(o),n.append(e);function i(l,d,P){let p=d+t[0],b=P+t[1];o.innerHTML=l;const x=n.getBBox(),v=o.getBoundingClientRect();p>x.width-v.width&&(p=d-v.width-t[0]),b>x.height-v.height&&(b=P-v.height-t[1]),o.style.transform=`translate(${p}px,${b}px)`}function r(){o.style.visibility="visible"}function c(){o.style.visibility="hidden"}return{update:i,show:r,hide:c,remove:()=>{n.removeChild(e)}}}const ot="controlPoint",z=2,it=8,H=14,T=H,st=()=>{const n=document.createElementNS("http://www.w3.org/2000/svg","svg");n.setAttribute("width",String(T*2)),n.setAttribute("height",String(T*2)),n.setAttribute("viewBox",`-${T} -${T} ${T*2} ${T*2}`);const t=document.createElementNS("http://www.w3.org/2000/svg","circle");t.setAttribute("r",String(it)),t.setAttribute("fill","white"),t.setAttribute("stroke","black"),t.setAttribute("stroke-width",String(z)),t.setAttribute("class",ot),n.appendChild(t);const e=document.createElementNS("http://www.w3.org/2000/svg","circle");return e.setAttribute("r",String(H)),e.setAttribute("fill","transparent"),e.setAttribute("stroke","transparent"),e.setAttribute("style","cursor: move;"),n.appendChild(e),{group:n,circle:t,clickTarget:e}};class U{constructor(t,e,o,i,r=!1){a(this,"element");a(this,"circle");a(this,"tooltip");a(this,"container");a(this,"isDragging",!1);a(this,"isHovered",!1);a(this,"point");a(this,"deletable",!0);a(this,"DELETE_EVENT","deleteme");a(this,"eventTarget",new EventTarget);a(this,"grabX",0);a(this,"grabY",0);a(this,"toDataSpace");const{group:c,circle:s}=st();this.element=c,this.circle=s,this.point=e,this.container=t,this.toDataSpace=o,this.tooltip=nt(this.container.svg),t.addSizeObserver(()=>{this.positionElement()}),i&&this.eventTarget.addEventListener(this.DELETE_EVENT,l=>{i(l)}),t.appendChild(this.element),this.positionElement(),this.point.eventTarget.addEventListener("updated",()=>this.positionElement()),this.setupInteraction(),r&&this.startInteraction(!0)}remove(){this.tooltip.remove(),this.container.removeChild(this.element)}positionElement(){const{x:t,y:e}=this.point,[o,i]=this.container.normalizedToSvg(t,e);this.element.setAttribute("x",String(o-T)),this.element.setAttribute("y",String(i-T));const r=this.toDataSpace(t);this.tooltip.update(String(r),o,i)}movePoint(t){const[e,o]=this.container.domToNormalized(t.clientX,t.clientY);this.point.setPosition(e+this.grabX,o+this.grabY),this.positionElement()}update(){this.circle.setAttribute("stroke-width",String(z)),this.isHovered?(this.circle.setAttribute("stroke-width",String(z+1)),this.tooltip.show()):this.tooltip.hide(),this.isDragging&&this.circle.setAttribute("stroke-width",String(z*2))}startInteraction(t=!1){this.isDragging=t,!this.isDragging&&this.deletable&&this.circle.setAttribute("stroke","red");const e=i=>{this.isDragging=!0,this.circle.setAttribute("stroke","black"),this.movePoint(i)};document.addEventListener("pointermove",e);const o=()=>{if(document.removeEventListener("pointermove",e),document.removeEventListener("pointerup",o),!this.isDragging){const i=new CustomEvent(this.DELETE_EVENT,{detail:this});this.eventTarget.dispatchEvent(i)}this.isDragging=!1,this.update()};document.addEventListener("pointerup",o)}setupInteraction(){this.element.addEventListener("pointerdown",t=>{t.stopPropagation(),this.circle.setAttribute("stroke-width",String(z*2));const[e,o]=this.container.domToNormalized(t.clientX,t.clientY);this.grabX=this.point.x-e,this.grabY=this.point.y-o,this.startInteraction()}),this.element.addEventListener("pointerenter",()=>{this.isHovered=!0,this.update()}),this.element.addEventListener("pointerleave",()=>{this.isHovered=!1,this.update()})}setColor(t){this.circle.setAttribute("fill",t)}}a(U,"styleElement");class rt{constructor(t,e,o){a(this,"container");a(this,"points");a(this,"onPointsUpdated");a(this,"controlPoints",[]);a(this,"isNewPointFromPointer",!1);a(this,"toDataSpace");this.container=t,this.points=e,this.toDataSpace=o;const{root:i}=t;i.addEventListener("pointerdown",r=>this.onPointerDown(r)),this.onPointsUpdated=()=>this.updatePoints(),this.points.eventTarget.addEventListener("updated",this.onPointsUpdated),this.updatePoints()}remove(){this.points.eventTarget.removeEventListener("updated",this.onPointsUpdated)}onPointerDown(t){const[e,o]=this.container.domToNormalized(t.clientX,t.clientY);this.isNewPointFromPointer=!0,this.points.addPoint(e,o),this.isNewPointFromPointer=!1}onControlPointDelete(t){this.points.removePoint(t.detail.point)}updatePoints(){const t=this.controlPoints.filter(i=>!this.points.points.find(r=>r===i.point));t.forEach(i=>i.remove()),this.controlPoints=this.controlPoints.filter(i=>!t.includes(i));const e=i=>this.controlPoints.find(r=>r.point===i),o=i=>this.controlPoints.push(new U(this.container,i,this.toDataSpace,r=>this.onControlPointDelete(r),this.isNewPointFromPointer));this.points.points.filter(i=>!e(i)).forEach(o)}}const at=()=>{const n=document.createElementNS("http://www.w3.org/2000/svg","polyline");return n.setAttribute("fill","none"),n.setAttribute("stroke","black"),n.setAttribute("stroke-width","2"),n};class dt{constructor(t,e){a(this,"points");a(this,"container");a(this,"onPointsUpdated");a(this,"element");this.container=t,this.points=e,this.element=at(),this.container.appendChild(this.element),this.onPointsUpdated=()=>this.update(),this.points.eventTarget.addEventListener("updated",this.onPointsUpdated),this.container.addSizeObserver(()=>{this.update()}),this.update()}remove(){this.points.eventTarget.removeEventListener("updated",this.onPointsUpdated)}update(){if(this.points.points.length===0){this.element.setAttribute("points","");return}const t=F(this.points.points).map(([e,o])=>this.container.normalizedToSvg(e,o)).map(([e,o])=>`${e},${o}`).join(" ");this.element.setAttribute("points",t)}}const X=1.1,ct=n=>{n.root.addEventListener("wheel",t=>{const e=t.deltaY>0?X:1/X,[o]=n.domToNormalized(t.clientX,t.clientY),[i,r]=n.getViewBox(),c=Math.max(0,i-Math.max(0,o-i)*(e-1)),s=Math.min(1,(r-i)*e+c);c===i&&s===r||(t.preventDefault(),t.stopPropagation(),n.setViewBox(c,s))})},$="rgba(50, 50, 50, 0.3)",lt=(n,t,e)=>{const o=document.createElement("canvas");n.root.appendChild(o),o.setAttribute("style","width: 100%; height: 100%; ");const i=o.getContext("2d");let r,c;const s=document.createElement("canvas"),l=()=>{if(i){if(i.clearRect(0,0,o.width,o.height),r){const{width:p,height:b}=n.root.getBoundingClientRect();o.setAttribute("width",String(p)),o.setAttribute("height",String(b));const{left:x,right:v,bottom:A,top:y}=n.borderSize();if(Math.ceil(v-x)<0)return;const h=F(t.points),f=[[0,0],...h,[1,0]].map(([k,D])=>n.normalizedToSvg(k,D));i.save(),i.beginPath(),f.forEach(([k,D])=>{i.lineTo(k,D)}),i.clip();const[w,u]=e.getColorRange(),[C]=n.normalizedToSvg(w,1),[R]=n.normalizedToSvg(u,1),E=Math.min(p,Math.max(0,C)),M=Math.min(p,Math.max(0,R)),_=M-E<2?E+2:M,W=Math.ceil(_-E);if(r){const k=R-C,D=(E-C)/k,vt=(_-R)/k,I=r.getMappingRange(),Y=I[1]-I[0],ft=[I[0]+Y*D,I[1]+Y*vt];K(r,W,ft,s),i.drawImage(s,0,0,s.width,s.height,Math.floor(E),Math.floor(y),W,Math.ceil(A-y));const wt=i.imageSmoothingEnabled;i.imageSmoothingEnabled=!1,i.drawImage(s,0,0,1,1,0,Math.floor(y),Math.floor(E),Math.ceil(A-y)),i.drawImage(s,s.width-1,0,1,1,Math.floor(_),Math.floor(y),p-_,Math.ceil(A-y)),i.imageSmoothingEnabled=wt}i.restore()}if(c){const{left:p,right:b,bottom:x,top:v}=n.borderSize(),A=[p,v,b-p,x-v];G(i,A,c,{lineWidth:1,strokeStyle:$,fillStyle:$})}}};return n.addSizeObserver(l),t.eventTarget.addEventListener("updated",l),e.eventTarget.addEventListener("updated",l),{container:n,canvas:o,setColorTransferFunction:p=>{r=p,l()},setHistogram:p=>{c=p,l()},render:l,remove:()=>n.root.removeChild(o)}},ht=()=>{const n=[new S(0,0),new S(1,0)],t=()=>n.sort((s,l)=>s.x-l.x),e=()=>t().map(s=>s.x),o=new EventTarget,i=()=>o.dispatchEvent(new CustomEvent("updated",{detail:e()}));let r=!1;const c=s=>{s.eventTarget.addEventListener("updated",()=>{s.y!==0&&(s.y=0),r||i()})};return n.forEach(c),{getPoints:t,getColorRange:e,setColorRange:s=>{r=!0,t().forEach((l,d)=>{l.x=s[d]}),r=!1,i()},eventTarget:o}},pt=(n,t,e)=>{const o=t.getPoints().map(s=>{const l=new U(n,s,e);return l.deletable=!1,l});let i;const r=()=>{if(!i)return;const s=i.getMappingRange(),l=[];i.getColor(s[0],l);const d=[];i.getColor(s[1],d);const P=o.sort((p,b)=>p.point.x-b.point.x);P[0].setColor(O(l)),P[1].setColor(O(d))},c=s=>{i=s,r()};return t.eventTarget.addEventListener("updated",()=>{r()}),{points:o,setColorTransferFunction:c}},gt=()=>{let n;return{setColorTransferFunction:o=>{n=o},toDataSpace:o=>{if(!n)return o;const[i,r]=n.getMappingRange(),c=r-i;return o*c+i}}};class ut{constructor(t){a(this,"eventTarget",new EventTarget);a(this,"points");a(this,"colorRange");a(this,"colorRangeController");a(this,"line");a(this,"pointController");a(this,"container");a(this,"background");a(this,"dataSpaceConverter",gt());this.container=tt(t),ct(this.container),this.points=new j;const e=[[0,0],[1,1]];this.points.setPoints(e),this.line=new dt(this.container,this.points),this.pointController=new rt(this.container,this.points,this.dataSpaceConverter.toDataSpace),this.colorRange=ht(),this.colorRangeController=pt(this.container,this.colorRange,this.dataSpaceConverter.toDataSpace),this.background=lt(this.container,this.points,this.colorRange),this.points.eventTarget.addEventListener("updated",o=>{this.eventTarget.dispatchEvent(new CustomEvent("updated",{detail:o.detail}))}),this.colorRange.eventTarget.addEventListener("updated",o=>{this.eventTarget.dispatchEvent(new CustomEvent("colorRange",{detail:o.detail}))})}remove(){this.background.remove(),this.container.remove()}getPoints(){return this.points.points.map(({x:t,y:e})=>[t,e])}setPoints(t){this.points.setPoints(t),this.pointController.updatePoints(),this.line.update(),this.background.render()}getColorRange(){return this.colorRange.getColorRange()}setColorRange(t){return this.colorRange.setColorRange(t)}setViewBox(t,e,o=0,i=1){this.container.setViewBox(t,e,o,i)}setColorTransferFunction(t){this.dataSpaceConverter.setColorTransferFunction(t),this.background.setColorTransferFunction(t),this.colorRangeController.setColorTransferFunction(t)}setHistogram(t){this.background.setHistogram(q(t))}}m.TransferFunctionEditor=ut,m.windowPointsForSort=Z,Object.defineProperty(m,Symbol.toStringTag,{value:"Module"})}); |
{ | ||
"name": "itk-viewer-transfer-function-editor", | ||
"version": "1.3.1", | ||
"version": "1.4.0", | ||
"description": "Interface to interactively edit opacity transfer functions, etc", | ||
@@ -5,0 +5,0 @@ "files": [ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
59582
24
948