@stemy/ngx-utils 19.7.0 → 19.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,7 @@ import * as i0 from '@angular/core';
4
4
  import { InjectionToken, PLATFORM_ID, Inject, Injectable, Optional, Injector, untracked, computed, signal, inject, DestroyRef, isDevMode, ErrorHandler, EventEmitter, createComponent, NgZone, Pipe, input, output, ChangeDetectorRef, ElementRef, effect, HostListener, Directive, Input, HostBinding, Output, TemplateRef, ChangeDetectionStrategy, ViewEncapsulation, Component, ViewChild, forwardRef, ContentChild, ContentChildren, model, contentChildren, provideAppInitializer, makeEnvironmentProviders, NgModule } from '@angular/core';
5
5
  import * as i2 from '@angular/router';
6
6
  import { ActivatedRouteSnapshot, Scroll, NavigationEnd, Router, DefaultUrlSerializer, UrlTree, UrlSegmentGroup, UrlSegment, UrlSerializer, ROUTES } from '@angular/router';
7
- import { BehaviorSubject, Observable, firstValueFrom, Subject, Subscription, from, delay, timer, TimeoutError, combineLatest, lastValueFrom } from 'rxjs';
7
+ import { BehaviorSubject, Observable, firstValueFrom, Subject, Subscription, from, delay, timer, TimeoutError, combineLatest, of, lastValueFrom } from 'rxjs';
8
8
  import { skipWhile, debounceTime, distinctUntilChanged, map, filter, mergeMap, timeout } from 'rxjs/operators';
9
9
  import * as i1$3 from '@angular/common';
10
10
  import { isPlatformBrowser, isPlatformServer, DOCUMENT, APP_BASE_HREF, CommonModule } from '@angular/common';
@@ -1146,6 +1146,9 @@ function drawOval(ctx, w, h) {
1146
1146
  ctx.ellipse(0, 0, w / 2, h / 2, 0, 0, Math.PI * 2);
1147
1147
  ctx.closePath();
1148
1148
  }
1149
+ function drawPoint(ctx) {
1150
+ drawOval(ctx, 4, 4);
1151
+ }
1149
1152
  class CanvasUtils {
1150
1153
  static manipulatePixels(canvas, ctx, colorTransformer) {
1151
1154
  const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
@@ -1732,28 +1735,54 @@ class FileSystemEntry {
1732
1735
  function dotProduct(a, b) {
1733
1736
  return a.x * b.x + a.y * b.y;
1734
1737
  }
1738
+ function tripleProduct(a, b, c) {
1739
+ const ac = a.x * c.x + a.y * c.y;
1740
+ const bc = b.x * c.x + b.y * c.y;
1741
+ return { x: b.x * ac - a.x * bc, y: b.y * ac - a.y * bc };
1742
+ }
1735
1743
  function isPoint(v) {
1736
- return typeof v === "object" && !isNaN(v.x) && !isNaN(v.y);
1744
+ return typeof v === "object" && Number.isFinite(v.x) && Number.isFinite(v.y);
1745
+ }
1746
+ function ensurePoint(p, fallback = { x: 0, y: 0 }) {
1747
+ return isPoint(p) ? { x: +p.x, y: +p.y } : fallback;
1737
1748
  }
1738
1749
  function perpendicular(p) {
1739
1750
  return { x: -p.y, y: +p.x };
1740
1751
  }
1741
- function ptAdd(a, b) {
1752
+ function negatePt(p) {
1753
+ return { x: -p.x, y: -p.y };
1754
+ }
1755
+ function normalizePt(p) {
1756
+ const length = lengthOfPt(p);
1757
+ return dividePts(p, length);
1758
+ }
1759
+ function addPts(a, b) {
1742
1760
  return { x: a.x + b.x, y: a.y + b.y };
1743
1761
  }
1744
- function ptDistance(a, b) {
1762
+ function distanceSq(a, b) {
1745
1763
  const x = b.x - a.x;
1746
1764
  const y = b.y - a.y;
1747
- return Math.sqrt(x * x + y * y);
1765
+ return x * x + y * y;
1766
+ }
1767
+ function distance(a, b) {
1768
+ return Math.sqrt(distanceSq(a, b));
1769
+ }
1770
+ function lerpPts(a, b, t) {
1771
+ const diff = subPts(b, a);
1772
+ return addPts(a, multiplyPts(diff, t));
1748
1773
  }
1749
- function ptLength(p) {
1774
+ function lengthOfPt(p) {
1750
1775
  return Math.hypot(p.x, p.y);
1751
1776
  }
1752
- function ptMultiply(a, b) {
1777
+ function multiplyPts(a, b) {
1753
1778
  const s = isPoint(b) ? b : { x: b, y: b };
1754
1779
  return { x: a.x * s.x, y: a.y * s.y };
1755
1780
  }
1756
- function ptSubtract(a, b) {
1781
+ function dividePts(a, b) {
1782
+ const s = isPoint(b) ? b : { x: b, y: b };
1783
+ return { x: a.x / s.x, y: a.y / s.y };
1784
+ }
1785
+ function subPts(a, b) {
1757
1786
  return { x: a.x - b.x, y: a.y - b.y };
1758
1787
  }
1759
1788
  function rotateDeg(p, ang) {
@@ -1770,125 +1799,261 @@ function toRadians(deg) {
1770
1799
  return deg * Math.PI / 180;
1771
1800
  }
1772
1801
 
1773
- function combineA(simplex, bary) {
1774
- let out = { x: 0, y: 0 };
1775
- for (let i = 0; i < simplex.length; i++)
1776
- out = ptAdd(out, ptMultiply(simplex[i].a, bary[i] || 0));
1777
- return out;
1802
+ const EPSILON = 1e-9;
1803
+ /**
1804
+ * Normalize a range
1805
+ * @param minOrRange
1806
+ * @param max
1807
+ */
1808
+ function normalizeRange(minOrRange, max) {
1809
+ const min = (Array.isArray(minOrRange) ? minOrRange[0] : minOrRange) ?? 0;
1810
+ max = (Array.isArray(minOrRange) ? minOrRange[1] : max) ?? 1;
1811
+ return (max < min) ? [max, min] : [min, max];
1778
1812
  }
1779
- function combineB(simplex, bary) {
1780
- let out = { x: 0, y: 0 };
1781
- for (let i = 0; i < simplex.length; i++)
1782
- out = ptAdd(out, ptMultiply(simplex[i].b, bary[i] || 0));
1783
- return out;
1813
+ /**
1814
+ * Clamps a value to a range
1815
+ * @param value
1816
+ * @param min
1817
+ * @param max
1818
+ */
1819
+ function clamp(value, min, max) {
1820
+ const range = normalizeRange(min, max);
1821
+ return Math.max(Math.min(value, range[1]), range[0]);
1784
1822
  }
1785
- function closestPointToOrigin(simplex) {
1786
- // returns { simplex: prunedSimplex, closest: vec, bary: weights[] }
1787
- if (simplex.length === 1) {
1788
- return { simplex, closest: simplex[0].p, bary: [1] };
1789
- }
1790
- if (simplex.length === 2) {
1791
- const A = simplex[0], B = simplex[1];
1792
- const ab = ptSubtract(B.p, A.p);
1793
- const ab2 = dotProduct(ab, ab);
1794
- if (ab2 <= 1e-18) {
1795
- return { simplex: [B], closest: B.p, bary: [1] };
1796
- }
1797
- const t = Math.max(0, Math.min(1, -dotProduct(A.p, ab) / ab2));
1798
- const closest = ptAdd(A.p, ptMultiply(ab, t));
1799
- if (t <= 1e-9) {
1800
- return { simplex: [A], closest: A.p, bary: [1] };
1801
- }
1802
- if (t >= 1 - 1e-9) {
1803
- return { simplex: [B], closest: B.p, bary: [1] };
1804
- }
1805
- return { simplex: [A, B], closest, bary: [1 - t, t] };
1806
- }
1807
- // Triangle case (A,B,C) – use Ericson's closest-point to triangle (p=origin)
1808
- const A = simplex[0], B = simplex[1], C = simplex[2];
1809
- const a = A.p, b = B.p, c = C.p;
1810
- const ab = ptSubtract(b, a), ac = ptSubtract(c, a), ap = { x: -a.x, y: -a.y };
1811
- const d1 = dotProduct(ab, ap), d2 = dotProduct(ac, ap);
1812
- if (d1 <= 0 && d2 <= 0)
1813
- return { simplex: [A], closest: a, bary: [1] };
1814
- const bp = { x: -b.x, y: -b.y };
1815
- const d3 = dotProduct(ab, bp), d4 = dotProduct(ac, bp);
1816
- if (d3 >= 0 && d4 <= d3)
1817
- return { simplex: [B], closest: b, bary: [1] };
1818
- const vc = d1 * d4 - d3 * d2;
1819
- if (vc <= 0 && d1 >= 0 && d3 <= 0) {
1820
- const v = d1 / (d1 - d3);
1821
- const closest = ptAdd(a, ptMultiply(ab, v));
1822
- return { simplex: [A, B], closest, bary: [1 - v, v] };
1823
- }
1824
- const cp = { x: -c.x, y: -c.y };
1825
- const bc = ptSubtract(c, b);
1826
- const d5 = dotProduct(bc, cp), d6 = dotProduct(ac, cp);
1827
- if (d6 >= 0 && d5 <= d6)
1828
- return { simplex: [C], closest: c, bary: [1] };
1829
- const vb = d5 * d2 - d1 * d6;
1830
- if (vb <= 0 && d2 >= 0 && d6 <= 0) {
1831
- const w = d2 / (d2 - d6);
1832
- const closest = ptAdd(a, ptMultiply(ac, w));
1833
- return { simplex: [A, C], closest, bary: [1 - w, 0, w] };
1834
- }
1835
- const va = d3 * d6 - d5 * d4;
1836
- if (va <= 0) {
1837
- const denom = (d4 - d3) + (d5 - d6);
1838
- const w = denom !== 0 ? (d4 - d3) / denom : 0.5;
1839
- const closest = ptAdd(b, ptMultiply(bc, w));
1840
- return { simplex: [B, C], closest, bary: [0, 1 - w, w] };
1841
- }
1842
- // Origin inside triangle – distance is zero
1843
- return { simplex: [A, B, C], closest: { x: 0, y: 0 }, bary: [0, 0, 0] };
1823
+ /**
1824
+ * Clamps a value to a range in a way, that when it is over in one end, then it appears from the other end
1825
+ * @param value
1826
+ * @param min
1827
+ * @param max
1828
+ */
1829
+ function overflow(value, min, max) {
1830
+ const range = normalizeRange(min, max);
1831
+ const length = range[1] - range[0];
1832
+ return ((((value - range[0]) % length) + length) % length) + range[0];
1844
1833
  }
1845
1834
  /**
1846
- * ====== GJK distance (2D) ======
1847
- * We keep, for each simplex vertex, the Minkowski point p = a - b and the witnesses a,b.
1848
- * @param A
1849
- * @param B
1835
+ * Checks if a number is equal to b number with epsilon tolerance
1836
+ * @param a
1837
+ * @param b
1838
+ * @param epsilon
1850
1839
  */
1840
+ function isEqual(a, b, epsilon = null) {
1841
+ epsilon = ObjectUtils.isNumber(epsilon) ? epsilon : EPSILON;
1842
+ return Math.abs(a - b) <= epsilon;
1843
+ }
1844
+ /**
1845
+ * Checks if a number is equal to zero with epsilon tolerance
1846
+ * @param a
1847
+ * @param epsilon
1848
+ */
1849
+ function isZero(a, epsilon = null) {
1850
+ return isEqual(a, 0, epsilon);
1851
+ }
1852
+ class MathUtils {
1853
+ static equal(a, b, epsilon = null) {
1854
+ return isEqual(a, b, epsilon);
1855
+ }
1856
+ static clamp(value, min, max) {
1857
+ return clamp(value, min, max);
1858
+ }
1859
+ static round(value, precision = 2, divider = 1) {
1860
+ precision = Math.pow(10, precision);
1861
+ return Math.round(value * precision / divider) / precision;
1862
+ }
1863
+ static approxIndex(x, values, epsilon = null) {
1864
+ if (!Array.isArray(values) || values.length == 0) {
1865
+ return -1;
1866
+ }
1867
+ let s = 0;
1868
+ let e = values.length - 1;
1869
+ while (s <= e) {
1870
+ const i = Math.floor((s + e) / 2);
1871
+ const v = values[i];
1872
+ if (MathUtils.equal(v, x, epsilon)) {
1873
+ return i;
1874
+ }
1875
+ if (v < x) {
1876
+ s = i + 1;
1877
+ }
1878
+ else {
1879
+ e = i - 1;
1880
+ }
1881
+ }
1882
+ const m = Math.max(e, 0);
1883
+ const a = values[s];
1884
+ const b = values[m];
1885
+ return Math.abs(a - x) < Math.abs(b - x) ? s : m;
1886
+ }
1887
+ static approximate(x, values, epsilon = null) {
1888
+ const index = MathUtils.approxIndex(x, values, epsilon);
1889
+ return values[index] ?? null;
1890
+ }
1891
+ }
1892
+
1893
+ const MAX_ITERS = 40;
1894
+ // =========================
1895
+ // GJK distance (robust)
1896
+ // =========================
1851
1897
  function gjkDistance(A, B) {
1852
- const MAX = 64, EPS = 1e-9;
1853
- const centerA = { x: A.x, y: A.y }, centerB = { x: B.x, y: B.y };
1854
- let d = ptSubtract(centerB, centerA);
1898
+ let intersection = gjkIntersection(A, B);
1899
+ if (intersection.hit)
1900
+ return { distance: 0 };
1901
+ const ca = A.center;
1902
+ const cb = B.center;
1903
+ let s = 0;
1904
+ let e = 1;
1905
+ let center = ca;
1906
+ let iters = 0;
1907
+ while (e - s > EPSILON) {
1908
+ iters++;
1909
+ const t = (e + s) / 2;
1910
+ const a = A.move(lerpPts(ca, cb, t));
1911
+ const test = gjkIntersection(a, B);
1912
+ center = a.center;
1913
+ if (test.hit) {
1914
+ intersection = test;
1915
+ e = t;
1916
+ if (iters >= MAX_ITERS)
1917
+ break;
1918
+ }
1919
+ else {
1920
+ s = t;
1921
+ }
1922
+ }
1923
+ const result = distance(ca, center);
1924
+ return {
1925
+ distance: result,
1926
+ pa: result > 0 ? addPts(intersection.pa, subPts(ca, center)) : null,
1927
+ pb: result > 0 ? intersection.pb : null
1928
+ };
1929
+ }
1930
+ // =========================
1931
+ // Boolean GJK (robust)
1932
+ // =========================
1933
+ function gjkIntersection(A, B) {
1934
+ const MAX = 64, EPS = 1e-12;
1935
+ const sup = (dir) => {
1936
+ const a = ensurePoint(A.support(dir), A.center);
1937
+ const b = ensurePoint(B.support(negatePt(dir)), B.center);
1938
+ return { p: subPts(a, b), a, b };
1939
+ };
1940
+ // initial direction: center-to-center; fall back to x-axis
1941
+ let d = subPts(B.center, A.center);
1855
1942
  if (Math.abs(d.x) < EPS && Math.abs(d.y) < EPS)
1856
1943
  d = { x: 1, y: 0 };
1857
- const sup = (dir) => {
1858
- const a = A.support(dir);
1859
- const b = B.support({ x: -dir.x, y: -dir.y });
1860
- return { p: ptSubtract(a, b), a, b };
1944
+ const simplex = [sup(d)];
1945
+ d = { x: -simplex[0].p.x, y: -simplex[0].p.y };
1946
+ for (let i = 0; i < MAX; i++) {
1947
+ // If direction collapses, steer toward origin from last point
1948
+ const dLen = Math.hypot(d.x, d.y);
1949
+ if (dLen <= EPS) {
1950
+ const last = simplex[simplex.length - 1];
1951
+ const AO = { x: -last.p.x, y: -last.p.y };
1952
+ const aoLen = Math.hypot(AO.x, AO.y);
1953
+ d = (aoLen > EPS) ? AO : { x: 1, y: 0 };
1954
+ }
1955
+ const a = sup(d);
1956
+ const s = a.p.x * d.x + a.p.y * d.y;
1957
+ if (s < -1e-12)
1958
+ return { hit: false }; // definite separation
1959
+ if (Math.abs(s) <= 1e-12) { // tangential contact: use normal ±d
1960
+ const L = Math.hypot(d.x, d.y) || 1;
1961
+ const n = { x: d.x / L, y: d.y / L };
1962
+ const pa = ensurePoint(A.support(n), A.center);
1963
+ const pb = ensurePoint(B.support(negatePt(n)), B.center);
1964
+ const point = { x: (pa.x + pb.x) / 2, y: (pa.y + pb.y) / 2 };
1965
+ return { hit: true, pa, pb, point };
1966
+ }
1967
+ simplex.push(a);
1968
+ {
1969
+ const info = doSimplexBoolean(simplex, d);
1970
+ if (info.hit)
1971
+ return info;
1972
+ }
1973
+ }
1974
+ // Max iterations without resolution → disjoint
1975
+ return { hit: false };
1976
+ }
1977
+ function doSimplexBoolean(simplex, d) {
1978
+ const last = simplex[simplex.length - 1];
1979
+ const AO = { x: -last.p.x, y: -last.p.y };
1980
+ if (simplex.length === 2) {
1981
+ const B = simplex[0];
1982
+ const AB = { x: B.p.x - last.p.x, y: B.p.y - last.p.y };
1983
+ // Perpendicular to AB toward origin
1984
+ const abPerp = tripleProduct(AB, AO, AB);
1985
+ const perpLen2 = abPerp.x * abPerp.x + abPerp.y * abPerp.y;
1986
+ if (perpLen2 < 1e-24) {
1987
+ // Colinear: project origin onto segment AB
1988
+ const ab2 = AB.x * AB.x + AB.y * AB.y;
1989
+ if (ab2 > 0) {
1990
+ const t = ((AO.x * AB.x + AO.y * AB.y) / ab2);
1991
+ if (t >= 0 && t <= 1) {
1992
+ // Contact at segment
1993
+ const pa = { x: last.a.x + t * (B.a.x - last.a.x), y: last.a.y + t * (B.a.y - last.a.y) };
1994
+ const pb = { x: last.b.x + t * (B.b.x - last.b.x), y: last.b.y + t * (B.b.y - last.b.y) };
1995
+ const point = { x: (pa.x + pb.x) / 2, y: (pa.y + pb.y) / 2 };
1996
+ return { hit: true, pa, pb, point };
1997
+ }
1998
+ }
1999
+ // Otherwise, move toward origin from A, keep only last point to progress
2000
+ d.x = -AO.x;
2001
+ d.y = -AO.y;
2002
+ simplex.splice(0, simplex.length - 1);
2003
+ return { hit: false };
2004
+ }
2005
+ d.x = abPerp.x;
2006
+ d.y = abPerp.y;
2007
+ return { hit: false };
2008
+ }
2009
+ // Triangle case: [C, B, A] with A = last
2010
+ const A = last, B = simplex[simplex.length - 2], C = simplex[simplex.length - 3];
2011
+ const AB = { x: B.p.x - A.p.x, y: B.p.y - A.p.y };
2012
+ const AC = { x: C.p.x - A.p.x, y: C.p.y - A.p.y };
2013
+ const ABperp = tripleProduct(AC, AB, AB);
2014
+ const ACperp = tripleProduct(AB, AC, AC);
2015
+ // If origin is outside AB region
2016
+ if (ABperp.x * AO.x + ABperp.y * AO.y > 0) {
2017
+ simplex.splice(simplex.length - 3, 1);
2018
+ d.x = ABperp.x;
2019
+ d.y = ABperp.y;
2020
+ return { hit: false };
2021
+ }
2022
+ // If origin is outside AC region
2023
+ if (ACperp.x * AO.x + ACperp.y * AO.y > 0) {
2024
+ simplex.splice(simplex.length - 2, 1);
2025
+ d.x = ACperp.x;
2026
+ d.y = ACperp.y;
2027
+ return { hit: false };
2028
+ }
2029
+ // Otherwise the origin is inside the triangle → overlap
2030
+ // Compute barycentric weights of origin w.r.t triangle (A,B,C)
2031
+ const v0 = AB; // B-A
2032
+ const v1 = AC; // C-A
2033
+ const b = { x: -A.p.x, y: -A.p.y };
2034
+ const det = v0.x * v1.y - v0.y * v1.x;
2035
+ let uA, uB, uC;
2036
+ if (Math.abs(det) > 1e-24) {
2037
+ const alpha = (b.x * v1.y - v1.x * b.y) / det; // weight for v0 (B)
2038
+ const beta = (v0.x * b.y - b.x * v0.y) / det; // weight for v1 (C)
2039
+ uB = alpha;
2040
+ uC = beta;
2041
+ uA = 1 - alpha - beta;
2042
+ }
2043
+ else {
2044
+ // Fallback: equal weights
2045
+ uA = uB = uC = 1 / 3;
2046
+ }
2047
+ const pa = {
2048
+ x: uA * A.a.x + uB * B.a.x + uC * C.a.x,
2049
+ y: uA * A.a.y + uB * B.a.y + uC * C.a.y
2050
+ };
2051
+ const pb = {
2052
+ x: uA * A.b.x + uB * B.b.x + uC * C.b.x,
2053
+ y: uA * A.b.y + uB * B.b.y + uC * C.b.y
1861
2054
  };
1862
- let simplex = [sup(d)];
1863
- let closest = simplex[0].p; // vector to origin
1864
- let dir = { x: -closest.x, y: -closest.y };
1865
- let best2 = dotProduct(closest, closest);
1866
- for (let iter = 0; iter < MAX; iter++) {
1867
- if (ptLength(dir) <= EPS) { // origin reached
1868
- const a = simplex[simplex.length - 1].a, b = simplex[simplex.length - 1].b;
1869
- return { distance: 0, pa: a, pb: b };
1870
- }
1871
- const vtx = sup(dir);
1872
- // termination: support didn't pass beyond previous closest along dir
1873
- if (dotProduct(vtx.p, dir) - Math.sqrt(best2) <= EPS) {
1874
- break;
1875
- }
1876
- simplex.push(vtx);
1877
- const reduced = closestPointToOrigin(simplex);
1878
- simplex = reduced.simplex;
1879
- closest = reduced.closest;
1880
- best2 = dotProduct(closest, closest);
1881
- dir = { x: -closest.x, y: -closest.y };
1882
- if (best2 <= EPS * EPS) {
1883
- const pa = combineA(simplex, reduced.bary);
1884
- const pb = combineB(simplex, reduced.bary);
1885
- return { distance: 0, pa, pb };
1886
- }
1887
- }
1888
- const res = closestPointToOrigin(simplex);
1889
- const pa = combineA(simplex, res.bary);
1890
- const pb = combineB(simplex, res.bary);
1891
- return { distance: Math.sqrt(dotProduct(res.closest, res.closest)), pa, pb };
2055
+ const point = { x: (pa.x + pb.x) / 2, y: (pa.y + pb.y) / 2 };
2056
+ return { hit: true, pa, pb, point };
1892
2057
  }
1893
2058
 
1894
2059
  class Shape {
@@ -1904,17 +2069,23 @@ class Shape {
1904
2069
  constructor(x, y) {
1905
2070
  this.pt = { x, y };
1906
2071
  }
1907
- distance(p) {
1908
- return ptDistance(this.center, p);
2072
+ intersection(shape) {
2073
+ return gjkIntersection(this, shape);
2074
+ }
2075
+ intersects(shape) {
2076
+ return this.intersection(shape).hit;
1909
2077
  }
1910
2078
  minDistance(shape) {
1911
- return gjkDistance(this, shape).distance;
2079
+ return gjkDistance(this, shape);
2080
+ }
2081
+ distance(shape) {
2082
+ return this.minDistance(shape).distance;
1912
2083
  }
1913
2084
  }
1914
2085
  class Point extends Shape {
1915
2086
  static { this.Zero = new Point(0, 0); }
1916
2087
  get length() {
1917
- return ptLength(this);
2088
+ return lengthOfPt(this);
1918
2089
  }
1919
2090
  get perpendicular() {
1920
2091
  return new Point(perpendicular(this));
@@ -1925,32 +2096,35 @@ class Point extends Shape {
1925
2096
  this.pt = isPoint(xOrP) ? xOrP : { x: isNaN(x) ? 0 : xOrP, y };
1926
2097
  }
1927
2098
  support() {
1928
- return this.pt;
2099
+ return this.center;
2100
+ }
2101
+ move(pos) {
2102
+ return new Point(pos);
1929
2103
  }
1930
2104
  add(p) {
1931
- return new Point(ptAdd(this, p));
2105
+ return new Point(addPts(this, p));
2106
+ }
2107
+ subtract(p) {
2108
+ return new Point(subPts(this, p));
1932
2109
  }
1933
- sub(p) {
1934
- return new Point(ptSubtract(this, p));
2110
+ multiply(p) {
2111
+ return new Point(multiplyPts(this, p));
1935
2112
  }
1936
- mul(p) {
1937
- return new Point(ptMultiply(this, p));
2113
+ divide(p) {
2114
+ return new Point(multiplyPts(this, p));
1938
2115
  }
1939
2116
  dot(p) {
1940
2117
  return new Point(dotProduct(this, p));
1941
2118
  }
1942
- distance(p) {
1943
- return ptDistance(this, p);
1944
- }
1945
2119
  lerp(p, ratio) {
1946
- const diff = p.sub(this);
1947
- return this.add(diff.mul(ratio));
2120
+ const diff = p.subtract(this);
2121
+ return this.add(diff.multiply(ratio));
1948
2122
  }
1949
2123
  perpendicularTo(p, length) {
1950
- const diff = p.perpendicular.sub(this.perpendicular);
2124
+ const diff = p.perpendicular.subtract(this.perpendicular);
1951
2125
  const ratio = length / diff.length;
1952
2126
  const center = this.lerp(p, .5);
1953
- return center.add(diff.mul(ratio));
2127
+ return center.add(diff.multiply(ratio));
1954
2128
  }
1955
2129
  circleWith(a, b) {
1956
2130
  const yDelta_a = b.y - a.y;
@@ -1965,8 +2139,8 @@ class Point extends Shape {
1965
2139
  return new Circle(center.x, center.y, center.distance(this));
1966
2140
  }
1967
2141
  tangents(c) {
1968
- const pd = ptSubtract(c.center, this);
1969
- const a = Math.asin(c.radius / ptLength(pd));
2142
+ const pd = subPts(c.center, this);
2143
+ const a = Math.asin(c.radius / lengthOfPt(pd));
1970
2144
  const b = Math.atan2(pd.y, pd.x);
1971
2145
  // Tangent points
1972
2146
  let t = b - a;
@@ -1976,7 +2150,7 @@ class Point extends Shape {
1976
2150
  return [t1, t2];
1977
2151
  }
1978
2152
  angle(p) {
1979
- const diff = p.sub(this);
2153
+ const diff = p.subtract(this);
1980
2154
  return Math.atan2(diff.y, diff.x) * 180 / Math.PI;
1981
2155
  }
1982
2156
  rotateAround(p, angle) {
@@ -1995,11 +2169,16 @@ class Rect extends Shape {
1995
2169
  }
1996
2170
  support(dir) {
1997
2171
  const ang = this.rotation ?? 0;
1998
- const dLocal = rotateDeg(dir, -ang);
2172
+ const dLocal = rotateDeg(ensurePoint(dir, { x: 1, y: 0 }), -ang);
1999
2173
  const hw = Math.max(0, this.width / 2), hh = Math.max(0, this.height / 2);
2174
+ if (hw === 0 && hh === 0)
2175
+ return ensurePoint(this.center);
2000
2176
  const lx = dLocal.x >= 0 ? hw : -hw;
2001
2177
  const ly = dLocal.y >= 0 ? hh : -hh;
2002
- return ptAdd(rotateDeg({ x: lx, y: ly }, ang), { x: this.x, y: this.y });
2178
+ return addPts(rotateDeg({ x: lx, y: ly }, ang), this.center);
2179
+ }
2180
+ move(pos) {
2181
+ return new Rect(pos.x, pos.y, this.width, this.height, this.rotation);
2003
2182
  }
2004
2183
  }
2005
2184
  class Oval extends Shape {
@@ -2011,15 +2190,16 @@ class Oval extends Shape {
2011
2190
  }
2012
2191
  support(dir) {
2013
2192
  const ang = this.rotation ?? 0;
2014
- const d = rotateDeg(dir, -ang);
2015
- const a = Math.max(0, this.width / 2);
2016
- const b = Math.max(0, this.height / 2);
2017
- if (Math.abs(d.x) < 1e-12 && Math.abs(d.y) < 1e-12)
2018
- return { x: this.x, y: this.y };
2019
- const q = Math.hypot(a * d.x, b * d.y) || 1; // sqrt((a*dx)^2 + (b*dy)^2)
2020
- const lx = (a * a * d.x) / q;
2021
- const ly = (b * b * d.y) / q;
2022
- return ptAdd(rotateDeg({ x: lx, y: ly }, ang), { x: this.x, y: this.y });
2193
+ const d = rotateDeg(ensurePoint(dir, { x: 1, y: 0 }), -ang);
2194
+ const a = Math.max(0, this.width / 2), b = Math.max(0, this.height / 2);
2195
+ if (a === 0 && b === 0)
2196
+ return ensurePoint(this.center);
2197
+ const q = Math.hypot(a * d.x, b * d.y) || 1;
2198
+ const lx = (a * a * d.x) / q, ly = (b * b * d.y) / q;
2199
+ return addPts(rotateDeg({ x: lx, y: ly }, ang), this.center);
2200
+ }
2201
+ move(pos) {
2202
+ return new Oval(pos.x, pos.y, this.width, this.height, this.rotation);
2023
2203
  }
2024
2204
  }
2025
2205
  class Circle extends Oval {
@@ -2027,6 +2207,9 @@ class Circle extends Oval {
2027
2207
  super(x, y, radius * 2, radius * 2, rotation);
2028
2208
  this.radius = radius;
2029
2209
  }
2210
+ move(pos) {
2211
+ return new Circle(pos.x, pos.y, this.radius, this.rotation);
2212
+ }
2030
2213
  }
2031
2214
 
2032
2215
  class Initializer {
@@ -2158,49 +2341,6 @@ class LoaderUtils {
2158
2341
  }
2159
2342
  }
2160
2343
 
2161
- class MathUtils {
2162
- static { this.EPSILON = 1e-9; }
2163
- static equal(a, b, epsilon = null) {
2164
- epsilon = ObjectUtils.isNumber(epsilon) ? epsilon : MathUtils.EPSILON;
2165
- return Math.abs(a - b) < epsilon;
2166
- }
2167
- static clamp(value, min, max) {
2168
- return Math.max(Math.min(value, max), min);
2169
- }
2170
- static round(value, precision = 2, divider = 1) {
2171
- precision = Math.pow(10, precision);
2172
- return Math.round(value * precision / divider) / precision;
2173
- }
2174
- static approxIndex(x, values, epsilon = null) {
2175
- if (!Array.isArray(values) || values.length == 0) {
2176
- return -1;
2177
- }
2178
- let s = 0;
2179
- let e = values.length - 1;
2180
- while (s <= e) {
2181
- const i = Math.floor((s + e) / 2);
2182
- const v = values[i];
2183
- if (MathUtils.equal(v, x, epsilon)) {
2184
- return i;
2185
- }
2186
- if (v < x) {
2187
- s = i + 1;
2188
- }
2189
- else {
2190
- e = i - 1;
2191
- }
2192
- }
2193
- const m = Math.max(e, 0);
2194
- const a = values[s];
2195
- const b = values[m];
2196
- return Math.abs(a - x) < Math.abs(b - x) ? s : m;
2197
- }
2198
- static approximate(x, values, epsilon = null) {
2199
- const index = MathUtils.approxIndex(x, values, epsilon);
2200
- return values[index] ?? null;
2201
- }
2202
- }
2203
-
2204
2344
  function isBrowser() {
2205
2345
  return typeof window !== "undefined";
2206
2346
  }
@@ -7281,6 +7421,9 @@ class DynamicTableComponent {
7281
7421
  this.testId = "table";
7282
7422
  this.titlePrefix = "label";
7283
7423
  this.realColumns = {};
7424
+ this.cols = [];
7425
+ this.sortable = false;
7426
+ this.localData = [];
7284
7427
  }
7285
7428
  setProperty(name, value) {
7286
7429
  const elem = this.element.nativeElement;
@@ -7305,6 +7448,9 @@ class DynamicTableComponent {
7305
7448
  ngAfterViewInit() {
7306
7449
  this.rowTemplate = this.rowTemplate || this.defaultRowTemplate;
7307
7450
  }
7451
+ ngOnDestroy() {
7452
+ this.subscription?.unsubscribe();
7453
+ }
7308
7454
  ngOnChanges(changes) {
7309
7455
  const orderBy = this.orderBy;
7310
7456
  if (changes.columns) {
@@ -7324,6 +7470,7 @@ class DynamicTableComponent {
7324
7470
  this.cols = Object.keys(this.realColumns);
7325
7471
  const sortable = this.cols.filter(c => this.realColumns[c].sort);
7326
7472
  const query = this.query || {};
7473
+ this.sortable = sortable.length > 0;
7327
7474
  this.orderBy = sortable.includes(this.orderBy) ? this.orderBy : sortable[0] || null;
7328
7475
  this.query = this.cols.reduce((res, col) => {
7329
7476
  const value = query[col];
@@ -7337,11 +7484,17 @@ class DynamicTableComponent {
7337
7484
  this.hasQuery = this.cols.some(col => this.realColumns[col].filter);
7338
7485
  if (changes.orderBy && this.realColumns && this.cols) {
7339
7486
  const sortable = this.cols.filter(c => this.realColumns[c].sort);
7487
+ this.sortable = sortable.length > 0;
7340
7488
  this.orderBy = sortable.includes(this.orderBy) ? this.orderBy : sortable[0] || null;
7341
7489
  }
7342
7490
  if (!changes.data && !changes.parallelData && !changes.dataLoader && !changes.itemsPerPage && !changes.orderDescending && orderBy === this.orderBy)
7343
7491
  return;
7344
- this.refresh();
7492
+ const source = this.data instanceof Observable ? this.data : of(this.data || []);
7493
+ this.subscription?.unsubscribe();
7494
+ this.subscription = source.subscribe(data => {
7495
+ this.localData = data;
7496
+ this.refresh();
7497
+ });
7345
7498
  }
7346
7499
  onDragStart(ev, elem, item) {
7347
7500
  if (!elem || !item || !ObjectUtils.isFunction(this.dragStartFn) || !this.dragStartFn({ ev, elem, item })) {
@@ -7443,21 +7596,21 @@ class DynamicTableComponent {
7443
7596
  this.itemsPerPage = count;
7444
7597
  this.refresh();
7445
7598
  }
7446
- loadLocalData(page, rowsPerPage, orderBy, orderDescending, filter) {
7447
- if (!this.data) {
7448
- return Promise.resolve({
7599
+ async loadLocalData(page, rowsPerPage, orderBy, orderDescending, filter) {
7600
+ if (!this.localData) {
7601
+ return {
7449
7602
  total: 0,
7450
7603
  items: []
7451
- });
7604
+ };
7452
7605
  }
7453
7606
  const compare = orderDescending
7454
7607
  ? (a, b) => DynamicTableComponent.compare(orderBy, b, a)
7455
7608
  : (a, b) => DynamicTableComponent.compare(orderBy, a, b);
7456
7609
  const from = (page - 1) * rowsPerPage;
7457
- const dataLength = this.data.length;
7610
+ const dataLength = this.localData.length;
7458
7611
  const length = Math.min(rowsPerPage, dataLength - from);
7459
7612
  const parallelData = this.parallelData || [];
7460
- let data = this.data.map((item, ix) => {
7613
+ let data = this.localData.map((item, ix) => {
7461
7614
  return new PaginationItemContext(item, parallelData[ix] || {}, dataLength, ix, ix);
7462
7615
  });
7463
7616
  if (ObjectUtils.isString(filter) && filter.length > 0) {
@@ -7466,19 +7619,20 @@ class DynamicTableComponent {
7466
7619
  }
7467
7620
  const items = orderBy ? data.sort(compare).splice(from, length) : data.splice(from, length);
7468
7621
  items.forEach((context, ix) => {
7469
- context.index = from + ix;
7622
+ context.index = ix;
7623
+ context.dataIndex = from + ix;
7470
7624
  });
7471
- return Promise.resolve({
7625
+ return {
7472
7626
  total: dataLength,
7473
7627
  items: items
7474
- });
7628
+ };
7475
7629
  }
7476
7630
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicTableComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
7477
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: DynamicTableComponent, isStandalone: false, selector: "dynamic-table", inputs: { dataLoader: "dataLoader", data: "data", selected: "selected", page: "page", urlParam: "urlParam", parallelData: "parallelData", columns: "columns", showFilter: "showFilter", filterLabel: "filterLabel", placeholder: "placeholder", showItems: "showItems", itemsPerPage: "itemsPerPage", updateTime: "updateTime", filterTime: "filterTime", maxPages: "maxPages", directionLinks: "directionLinks", boundaryLinks: "boundaryLinks", orderBy: "orderBy", orderDescending: "orderDescending", testId: "testId", titlePrefix: "titlePrefix", dragStartFn: "dragStartFn", dragEnterFn: "dragEnterFn", dropFn: "dropFn" }, queries: [{ propertyName: "rowTemplate", first: true, predicate: ["rowTemplate"], descendants: true, static: true }, { propertyName: "wrapperTemplate", first: true, predicate: ["wrapperTemplate"], descendants: true, static: true }, { propertyName: "templateDirectives", predicate: DynamicTableTemplateDirective }], viewQueries: [{ propertyName: "columnsTemplate", first: true, predicate: ["columnsTemplate"], descendants: true, static: true }, { propertyName: "defaultRowTemplate", first: true, predicate: ["defaultRowTemplate"], descendants: true, static: true }, { propertyName: "defaultWrapperTemplate", first: true, predicate: ["defaultWrapperTemplate"], descendants: true, static: true }, { propertyName: "pagination", first: true, predicate: ["pagination"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<ng-template #columnTemplate let-context let-column=\"column\" let-template=\"template\">\n <ng-template #defaultTemplate let-column=\"column\" let-item=\"item\">\n <span>{{ item[column] == undefined || item[column] == null ? '-' : item[column] }}</span>\n </ng-template>\n <ng-template #pureTemplate>\n <ng-container [ngxTemplateOutlet]=\"template.ref\" [context]=\"context\"></ng-container>\n </ng-template>\n <td [ngClass]=\"'column-' + column\"\n [attr.data-testid]=\"testId + '-' + column + '-' + context.rowIndex\"\n *ngIf=\"!template || !template.pure; else pureTemplate\">\n <ng-container [ngxTemplateOutlet]=\"!template ? defaultTemplate : template.ref\"\n [context]=\"context\"></ng-container>\n </td>\n</ng-template>\n\n<ng-template #columnsTemplate let-context>\n <ng-container *ngFor=\"let column of cols\"\n [ngxTemplateOutlet]=\"columnTemplate\"\n [context]=\"context\"\n [additionalContext]=\"{\n template: templates[column],\n column: column\n }\"></ng-container>\n</ng-template>\n\n<ng-template #defaultRowTemplate let-context>\n <tr #elem\n [draggable]=\"!!dragStartFn\"\n [ngClass]=\"{active: selected === context.item}\"\n (dragstart)=\"onDragStart($event, elem, context.item)\"\n (dragenter)=\"onDragEnter($event, elem, context.item)\"\n (dragleave)=\"onDragLeave($event, elem)\"\n (drop)=\"onDrop($event, elem, context.item)\">\n <ng-container [ngxTemplateOutlet]=\"columnsTemplate\" [context]=\"context\"></ng-container>\n </tr>\n</ng-template>\n\n<ng-template #headerTemplate let-column=\"column\" let-toggle=\"toggle\">\n <ng-template #defaultCol>\n <span>{{ realColumns[column].title | translate }}</span>\n </ng-template>\n <ng-template #emptyCol>\n <span>-</span>\n </ng-template>\n <ng-container *ngIf=\"realColumns[column]; else emptyCol\">\n <a *ngIf=\"realColumns[column].sort; else defaultCol\"\n [ngClass]=\"['sort', orderBy !== column ? '' : (orderDescending ? 'sort-desc' : 'sort-asc')]\"\n (click)=\"setSorting(column, toggle)\">\n <span>{{ realColumns[column].title | translate }}</span>\n </a>\n </ng-container>\n</ng-template>\n\n<div class=\"dynamic-table\">\n <div class=\"table-features-row\">\n <ng-content select=\"[table-features-before]\"></ng-content>\n <div class=\"table-input-wrap table-search-filter\" *ngIf=\"showFilter\">\n <label *ngIf=\"filterLabel\" [attr.for]=\"tableId\">\n {{ filterLabel | translate }}\n </label>\n <input type=\"text\"\n class=\"search-input\"\n [attr.id]=\"tableId\"\n [attr.data-testid]=\"testId + '-filter-input'\"\n [placeholder]=\"placeholder | translate\"\n [ngModel]=\"filter\"\n (ngModelChange)=\"setFilter($event)\"/>\n </div>\n <dropdown-box componentClass=\"sort-dropdown\" #sortDd>\n <ng-container toggle-content\n [ngTemplateOutlet]=\"headerTemplate\"\n [ngTemplateOutletContext]=\"{column: orderBy, toggle: sortDd}\"></ng-container>\n <ul>\n <ng-container *ngFor=\"let column of cols\">\n <li [ngClass]=\"'sort-column sort-' + column\" *ngIf=\"realColumns[column].sort\">\n <ng-container [ngTemplateOutlet]=\"headerTemplate\"\n [ngTemplateOutletContext]=\"{column: column}\"></ng-container>\n </li>\n </ng-container>\n </ul>\n </dropdown-box>\n <div class=\"table-input-wrap table-items-count\" *ngIf=\"showItems\">\n <label>\n {{ 'label.items.before' | translate }}\n </label>\n <dropdown-box>\n <ng-container toggle-content>\n {{ itemsPerPage }}\n </ng-container>\n <ul>\n <ng-container *ngFor=\"let count of showItems\">\n <li [ngClass]=\"'item-count count-' + count\" (click)=\"setItemsPerPage(count)\">\n {{ count }}\n </li>\n </ng-container>\n </ul>\n </dropdown-box>\n <label>\n {{ 'label.items.after' | translate }}\n </label>\n </div>\n <ng-content select=\"[table-features-after]\"></ng-content>\n </div>\n <div class=\"table-content-row\"\n #pagination=\"pagination\"\n [pagination]=\"loadData\"\n [page]=\"page\"\n [itemsPerPage]=\"itemsPerPage\"\n [updateTime]=\"updateTime\">\n <pagination-menu [urlParam]=\"urlParam\" [maxSize]=\"maxPages\" [directionLinks]=\"directionLinks\"\n [boundaryLinks]=\"boundaryLinks\"></pagination-menu>\n <div class=\"table-responsive\">\n <ng-template #defaultWrapperTemplate>\n <table class=\"table table-striped\">\n <thead>\n <tr>\n <th *ngFor=\"let column of cols\" [ngClass]=\"'header-column column-' + column\">\n <ng-container [ngTemplateOutlet]=\"headerTemplate\"\n [ngTemplateOutletContext]=\"{column: column}\"></ng-container>\n </th>\n </tr>\n <tr *ngIf=\"hasQuery\">\n <th *ngFor=\"let column of cols\" [ngClass]=\"['column-' + column, 'filter-column']\">\n <ng-container *ngIf=\"realColumns[column].filter\" [ngSwitch]=\"realColumns[column].filterType\">\n <ng-container *ngSwitchCase=\"'enum'\">\n <ng-template #optionItem let-option=\"option\">\n {{ (realColumns[column].enumPrefix ? realColumns[column].enumPrefix + '.' + option : option) | translate }}\n </ng-template>\n <dropdown-box componentClass=\"filter-box\"\n [ngClass]=\"'filter-box-' + column\" [closeInside]=\"false\">\n <ng-container toggle-content>\n <span class=\"toggle-placeholder\" *ngIf=\"!query[column]\">\n {{ realColumns[column].title | translate }}\n </span>\n <span [ngClass]=\"['option-' + option, column + '-option-' + option, option]\"\n *ngFor=\"let option of query[column] | values; let ix = index\">\n <ng-container *ngIf=\"ix > 0\">, </ng-container>\n <ng-container [ngTemplateOutlet]=\"optionItem\"\n [ngTemplateOutletContext]=\"{option: option}\"></ng-container>\n </span>\n </ng-container>\n <ul>\n <li [ngClass]=\"[column + '-option', 'option-' + option, option]\"\n (click)=\"setQueryValue(column, option)\"\n *ngFor=\"let option of realColumns[column].enum\">\n <a [ngClass]=\"'toggle-link-' + column\">\n <input type=\"checkbox\" [checked]=\"query[column] | includes: option\">\n <ng-container [ngTemplateOutlet]=\"optionItem\"\n [ngTemplateOutletContext]=\"{option: option}\"></ng-container>\n </a>\n </li>\n </ul>\n </dropdown-box>\n </ng-container>\n <ng-container *ngSwitchCase=\"'checkbox'\">\n <input type=\"checkbox\"\n [attr.data-testid]=\"testId + '-filter-' + column\"\n [placeholder]=\"realColumns[column].title | translate\"\n [ngModel]=\"query[column]\"\n (ngModelChange)=\"setQueryValue(column, $event)\"/>\n </ng-container>\n <ng-container *ngSwitchDefault>\n <input class=\"search-input\"\n type=\"text\"\n [attr.data-testid]=\"testId + '-filter-' + column\"\n [placeholder]=\"realColumns[column].title | translate\"\n [ngModel]=\"query[column]\"\n (ngModelChange)=\"setQueryValue(column, $event)\"/>\n </ng-container>\n </ng-container>\n </th>\n </tr>\n </thead>\n <tbody>\n <ng-container *paginationItem=\"let context\"\n [ngxTemplateOutlet]=\"rowTemplate\"\n [context]=\"context\"\n [additionalContext]=\"this\"></ng-container>\n </tbody>\n </table>\n </ng-template>\n\n <div class=\"table-wrapper\">\n <ng-content select=\"[table-top]\"></ng-content>\n <ng-container [ngxTemplateOutlet]=\"wrapperTemplate || defaultWrapperTemplate\"\n [context]=\"this\"></ng-container>\n <ng-content select=\"[table-bottom]\"></ng-content>\n </div>\n </div>\n <pagination-menu [urlParam]=\"urlParam\" [maxSize]=\"maxPages\" [directionLinks]=\"directionLinks\"\n [boundaryLinks]=\"boundaryLinks\"></pagination-menu>\n </div>\n</div>\n", styles: [".dynamic-table{--table-bg: transparent;--table-stripe-bg: rgba(210, 210, 210, .35);--border-size: 1px;--border-color: #ced4da;--bg-color: #ffffff;--text-color: #151515;--highlight-color: var(--primary-color, #888888);--highlight-text-color: #ffffff;--display-toggle: none;--arrow-size: 6px;--arrow-rotation: 90;--arrow-space: calc(var(--arrow-size) * .5 + 1px);--arrow-color: #c6c6c6}.dynamic-table *{box-sizing:border-box}.dynamic-table .search-input{background:var(--bg-color);color:var(--text-color);border:var(--border-size) solid var(--border-color);border-radius:5px;padding:6px 12px;-webkit-user-select:none;user-select:none;font-weight:400;font-size:var(--table-input-font-size, 15px);line-height:var(--table-input-line-height, 18px);outline:none}.dynamic-table .search-input .toggle-placeholder,.dynamic-table .search-input ::placeholder{color:#495057}.dynamic-table .table-responsive{border:1px solid var(--border-color);overflow:hidden;overflow-x:auto;margin-bottom:1rem}.dynamic-table .table-features-row:not(:empty){display:flex;gap:10px;flex-wrap:wrap;align-items:center;justify-content:space-between;margin-bottom:20px}.dynamic-table .table-content-row{position:relative}.dynamic-table .sort-dropdown{display:none}.dynamic-table .table-input-wrap{display:flex;align-items:center;justify-content:flex-end;gap:5px}.dynamic-table .table-input-wrap>label{margin:0;font-weight:700}.dynamic-table .table-input-wrap>input{max-width:400px}.dynamic-table .table-items-count{flex:1}.dynamic-table .table-wrapper{position:relative}.dynamic-table table.table{border-collapse:collapse;margin:0;width:100%;font-family:inherit;font-size:inherit}.dynamic-table table.table th{text-align:left}.dynamic-table table.table th,.dynamic-table table.table td{text-align:left;padding:6px 12px;border:1px solid var(--border-color);vertical-align:middle;white-space:nowrap;width:var(--cell-width, 25%);min-width:fit-content}.dynamic-table table.table-sm th,.dynamic-table table.table-sm td{font-size:var(--font-size-sm);padding:4px 6px}.dynamic-table table.table thead th{font-weight:500}.dynamic-table table.table thead th .dropdown-box{display:block;width:100%;text-align:left}.dynamic-table table.table thead th .search-input{width:100%}.dynamic-table table.table thead th span{display:inline-block;vertical-align:top}.dynamic-table table.table thead th a{cursor:pointer;text-align:left}.dynamic-table table.table thead th.filter-column{text-align:center}.dynamic-table table.table thead tr:first-child th{border-top-width:0}.dynamic-table table.table tbody tr:last-child td{border-bottom-width:0}.dynamic-table table.table thead tr th,.dynamic-table table.table tbody tr td{background-color:var(--table-bg)}.dynamic-table table.table thead tr th:first-child,.dynamic-table table.table tbody tr td:first-child{border-left-width:0}.dynamic-table table.table thead tr th:last-child,.dynamic-table table.table tbody tr td:last-child{border-right-width:0}.dynamic-table table.table tbody tr.active td{background-color:var(--highlight-color);color:var(--highlight-text-color)}.dynamic-table .table-striped>tbody>tr:nth-of-type(odd) td{background-color:var(--table-stripe-bg)}.dynamic-table .table-striped>tbody>tr:nth-of-type(odd).active td{background-color:var(--highlight-color);color:var(--highlight-text-color)}.sort-dropdown .dropdown-box-toggle a.dropdown-box-toggle-link{margin-right:0;padding-right:0}.sort-dropdown .dropdown-box-toggle a.dropdown-box-toggle-link:after{display:none}.sort-dropdown-content-wrapper a.sort,.dynamic-table a.sort{position:relative;display:block;margin-right:calc(var(--arrow-size) * 2);-webkit-user-select:none;user-select:none;padding-right:5px}.sort-dropdown-content-wrapper a.sort:before,.sort-dropdown-content-wrapper a.sort:after,.dynamic-table a.sort:before,.dynamic-table a.sort:after{content:\"\";position:absolute;transition:.2s ease;left:calc(100% + var(--arrow-size));top:calc(50% - var(--arrow-size));border-top:var(--arrow-size) solid transparent;border-bottom:var(--arrow-size) solid transparent;border-left:var(--arrow-size) solid var(--arrow-color);transform:rotate(calc(var(--arrow-rotation) * 1deg)) translate(var(--arrow-space))}.sort-dropdown-content-wrapper a.sort:before,.dynamic-table a.sort:before{--arrow-rotation: -90}.sort-dropdown-content-wrapper a.sort.sort-desc:before,.dynamic-table a.sort.sort-desc:before{--arrow-color: black}.sort-dropdown-content-wrapper a.sort.sort-asc:after,.dynamic-table a.sort.sort-asc:after{--arrow-color: black}\n"], dependencies: [{ kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$3.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$3.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$3.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgxTemplateOutletDirective, selector: "[ngxTemplateOutlet]", inputs: ["context", "additionalContext", "ngxTemplateOutlet"] }, { kind: "directive", type: PaginationDirective, selector: "[pagination]", inputs: ["pagination", "page", "itemsPerPage", "updateTime", "waitFor"], outputs: ["pageChange", "onRefresh"], exportAs: ["pagination"] }, { kind: "directive", type: PaginationItemDirective, selector: "[paginationItem]" }, { kind: "component", type: DropdownBoxComponent, selector: "dropdown-box", inputs: ["closeInside", "attachTo", "placement", "crossAxis", "alignment", "autoAlignment", "allowedPlacements", "componentClass"] }, { kind: "component", type: PaginationMenuComponent, selector: "pagination-menu", inputs: ["maxSize", "urlParam", "directionLinks", "boundaryLinks"] }, { kind: "pipe", type: IncludesPipe, name: "includes" }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: ValuesPipe, name: "values" }], encapsulation: i0.ViewEncapsulation.None }); }
7631
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: DynamicTableComponent, isStandalone: false, selector: "dynamic-table", inputs: { dataLoader: "dataLoader", data: "data", selected: "selected", page: "page", urlParam: "urlParam", parallelData: "parallelData", columns: "columns", showFilter: "showFilter", filterLabel: "filterLabel", placeholder: "placeholder", showItems: "showItems", itemsPerPage: "itemsPerPage", updateTime: "updateTime", filterTime: "filterTime", maxPages: "maxPages", directionLinks: "directionLinks", boundaryLinks: "boundaryLinks", orderBy: "orderBy", orderDescending: "orderDescending", testId: "testId", titlePrefix: "titlePrefix", dragStartFn: "dragStartFn", dragEnterFn: "dragEnterFn", dropFn: "dropFn" }, queries: [{ propertyName: "rowTemplate", first: true, predicate: ["rowTemplate"], descendants: true, static: true }, { propertyName: "wrapperTemplate", first: true, predicate: ["wrapperTemplate"], descendants: true, static: true }, { propertyName: "templateDirectives", predicate: DynamicTableTemplateDirective }], viewQueries: [{ propertyName: "columnsTemplate", first: true, predicate: ["columnsTemplate"], descendants: true, static: true }, { propertyName: "defaultRowTemplate", first: true, predicate: ["defaultRowTemplate"], descendants: true, static: true }, { propertyName: "defaultWrapperTemplate", first: true, predicate: ["defaultWrapperTemplate"], descendants: true, static: true }, { propertyName: "pagination", first: true, predicate: ["pagination"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<ng-template #columnTemplate let-context let-column=\"column\" let-template=\"template\">\n <ng-template #defaultTemplate let-column=\"column\" let-item=\"item\">\n <span>{{ item[column] == undefined || item[column] == null ? '-' : item[column] }}</span>\n </ng-template>\n <ng-template #pureTemplate>\n <ng-container [ngxTemplateOutlet]=\"template.ref\" [context]=\"context\"></ng-container>\n </ng-template>\n <td [ngClass]=\"'column-' + column\"\n [attr.data-testid]=\"testId + '-' + column + '-' + context.rowIndex\"\n *ngIf=\"!template || !template.pure; else pureTemplate\">\n <ng-container [ngxTemplateOutlet]=\"!template ? defaultTemplate : template.ref\"\n [context]=\"context\"></ng-container>\n </td>\n</ng-template>\n\n<ng-template #columnsTemplate let-context>\n <ng-container *ngFor=\"let column of cols\"\n [ngxTemplateOutlet]=\"columnTemplate\"\n [context]=\"context\"\n [additionalContext]=\"{\n template: templates[column],\n column: column\n }\"></ng-container>\n</ng-template>\n\n<ng-template #defaultRowTemplate let-context>\n <tr #elem\n [draggable]=\"!!dragStartFn\"\n [ngClass]=\"{active: selected === context.item}\"\n (dragstart)=\"onDragStart($event, elem, context.item)\"\n (dragenter)=\"onDragEnter($event, elem, context.item)\"\n (dragleave)=\"onDragLeave($event, elem)\"\n (drop)=\"onDrop($event, elem, context.item)\">\n <ng-container [ngxTemplateOutlet]=\"columnsTemplate\" [context]=\"context\"></ng-container>\n </tr>\n</ng-template>\n\n<ng-template #headerTemplate let-column=\"column\" let-toggle=\"toggle\">\n <ng-template #defaultCol>\n <span>{{ realColumns[column].title | translate }}</span>\n </ng-template>\n <ng-template #emptyCol>\n <span>-</span>\n </ng-template>\n <ng-container *ngIf=\"realColumns[column]; else emptyCol\">\n <a *ngIf=\"realColumns[column].sort; else defaultCol\"\n [ngClass]=\"['sort', orderBy !== column ? '' : (orderDescending ? 'sort-desc' : 'sort-asc')]\"\n (click)=\"setSorting(column, toggle)\">\n <span>{{ realColumns[column].title | translate }}</span>\n </a>\n </ng-container>\n</ng-template>\n\n<div class=\"dynamic-table\">\n <div class=\"table-features-row\">\n <ng-content select=\"[table-features-before]\"></ng-content>\n @if (showFilter) {\n <div class=\"table-input-wrap table-search-filter\">\n <label *ngIf=\"filterLabel\" [attr.for]=\"tableId\">\n {{ filterLabel | translate }}\n </label>\n <input type=\"text\"\n class=\"search-input\"\n [attr.id]=\"tableId\"\n [attr.data-testid]=\"testId + '-filter-input'\"\n [placeholder]=\"placeholder | translate\"\n [ngModel]=\"filter\"\n (ngModelChange)=\"setFilter($event)\"/>\n </div>\n }\n @if (sortable) {\n <dropdown-box componentClass=\"sort-dropdown\" #sortDd>\n <ng-container toggle-content\n [ngTemplateOutlet]=\"headerTemplate\"\n [ngTemplateOutletContext]=\"{column: orderBy, toggle: sortDd}\"></ng-container>\n <ul>\n <ng-container *ngFor=\"let column of cols\">\n <li [ngClass]=\"'sort-column sort-' + column\" *ngIf=\"realColumns[column].sort\">\n <ng-container [ngTemplateOutlet]=\"headerTemplate\"\n [ngTemplateOutletContext]=\"{column: column}\"></ng-container>\n </li>\n </ng-container>\n </ul>\n </dropdown-box>\n }\n @if (showItems) {\n <div class=\"table-input-wrap table-items-count\">\n <label>\n {{ 'label.items.before' | translate }}\n </label>\n <dropdown-box>\n <ng-container toggle-content>\n {{ itemsPerPage }}\n </ng-container>\n <ul>\n <ng-container *ngFor=\"let count of showItems\">\n <li [ngClass]=\"'item-count count-' + count\" (click)=\"setItemsPerPage(count)\">\n {{ count }}\n </li>\n </ng-container>\n </ul>\n </dropdown-box>\n <label>\n {{ 'label.items.after' | translate }}\n </label>\n </div>\n }\n <ng-content select=\"[table-features-after]\"></ng-content>\n </div>\n <div class=\"table-content-row\"\n #pagination=\"pagination\"\n [pagination]=\"loadData\"\n [page]=\"page\"\n [itemsPerPage]=\"itemsPerPage\"\n [updateTime]=\"updateTime\">\n <pagination-menu [urlParam]=\"urlParam\" [maxSize]=\"maxPages\" [directionLinks]=\"directionLinks\"\n [boundaryLinks]=\"boundaryLinks\"></pagination-menu>\n <div class=\"table-responsive\">\n <ng-template #defaultWrapperTemplate>\n <table class=\"table table-striped\">\n <thead>\n <tr>\n <th *ngFor=\"let column of cols\" [ngClass]=\"'header-column column-' + column\">\n <ng-container [ngTemplateOutlet]=\"headerTemplate\"\n [ngTemplateOutletContext]=\"{column: column}\"></ng-container>\n </th>\n </tr>\n <tr *ngIf=\"hasQuery\">\n <th *ngFor=\"let column of cols\" [ngClass]=\"['column-' + column, 'filter-column']\">\n <ng-container *ngIf=\"realColumns[column].filter\" [ngSwitch]=\"realColumns[column].filterType\">\n <ng-container *ngSwitchCase=\"'enum'\">\n <ng-template #optionItem let-option=\"option\">\n {{ (realColumns[column].enumPrefix ? realColumns[column].enumPrefix + '.' + option : option) | translate }}\n </ng-template>\n <dropdown-box componentClass=\"filter-box\"\n [ngClass]=\"'filter-box-' + column\" [closeInside]=\"false\">\n <ng-container toggle-content>\n <span class=\"toggle-placeholder\" *ngIf=\"!query[column]\">\n {{ realColumns[column].title | translate }}\n </span>\n <span [ngClass]=\"['option-' + option, column + '-option-' + option, option]\"\n *ngFor=\"let option of query[column] | values; let ix = index\">\n <ng-container *ngIf=\"ix > 0\">, </ng-container>\n <ng-container [ngTemplateOutlet]=\"optionItem\"\n [ngTemplateOutletContext]=\"{option: option}\"></ng-container>\n </span>\n </ng-container>\n <ul>\n <li [ngClass]=\"[column + '-option', 'option-' + option, option]\"\n (click)=\"setQueryValue(column, option)\"\n *ngFor=\"let option of realColumns[column].enum\">\n <a [ngClass]=\"'toggle-link-' + column\">\n <input type=\"checkbox\" [checked]=\"query[column] | includes: option\">\n <ng-container [ngTemplateOutlet]=\"optionItem\"\n [ngTemplateOutletContext]=\"{option: option}\"></ng-container>\n </a>\n </li>\n </ul>\n </dropdown-box>\n </ng-container>\n <ng-container *ngSwitchCase=\"'checkbox'\">\n <input type=\"checkbox\"\n [attr.data-testid]=\"testId + '-filter-' + column\"\n [placeholder]=\"realColumns[column].title | translate\"\n [ngModel]=\"query[column]\"\n (ngModelChange)=\"setQueryValue(column, $event)\"/>\n </ng-container>\n <ng-container *ngSwitchDefault>\n <input class=\"search-input\"\n type=\"text\"\n [attr.data-testid]=\"testId + '-filter-' + column\"\n [placeholder]=\"realColumns[column].title | translate\"\n [ngModel]=\"query[column]\"\n (ngModelChange)=\"setQueryValue(column, $event)\"/>\n </ng-container>\n </ng-container>\n </th>\n </tr>\n </thead>\n <tbody>\n <ng-container *paginationItem=\"let context\"\n [ngxTemplateOutlet]=\"rowTemplate\"\n [context]=\"context\"\n [additionalContext]=\"this\"></ng-container>\n </tbody>\n </table>\n </ng-template>\n\n <div class=\"table-wrapper\">\n <ng-content select=\"[table-top]\"></ng-content>\n <ng-container [ngxTemplateOutlet]=\"wrapperTemplate || defaultWrapperTemplate\"\n [context]=\"this\"></ng-container>\n <ng-content select=\"[table-bottom]\"></ng-content>\n </div>\n </div>\n <pagination-menu [urlParam]=\"urlParam\" [maxSize]=\"maxPages\" [directionLinks]=\"directionLinks\"\n [boundaryLinks]=\"boundaryLinks\"></pagination-menu>\n </div>\n</div>\n", styles: [".dynamic-table{--table-bg: transparent;--table-stripe-bg: rgba(210, 210, 210, .35);--border-size: 1px;--border-color: #ced4da;--bg-color: #ffffff;--text-color: #151515;--highlight-color: var(--primary-color, #888888);--highlight-text-color: #ffffff;--display-toggle: none;--arrow-size: 6px;--arrow-rotation: 90;--arrow-space: calc(var(--arrow-size) * .5 + 1px);--arrow-color: #c6c6c6}.dynamic-table *{box-sizing:border-box}.dynamic-table .search-input{background:var(--bg-color);color:var(--text-color);border:var(--border-size) solid var(--border-color);border-radius:5px;padding:6px 12px;-webkit-user-select:none;user-select:none;font-weight:400;font-size:var(--table-input-font-size, 15px);line-height:var(--table-input-line-height, 18px);outline:none}.dynamic-table .search-input .toggle-placeholder,.dynamic-table .search-input ::placeholder{color:#495057}.dynamic-table .table-responsive{border:1px solid var(--border-color);overflow:hidden;overflow-x:auto;margin-bottom:1rem}.dynamic-table .table-features-row:not(:empty){display:flex;gap:10px;flex-wrap:wrap;align-items:center;justify-content:space-between;margin-bottom:20px}.dynamic-table .table-content-row{position:relative}.dynamic-table .sort-dropdown{display:none}.dynamic-table .table-input-wrap{display:flex;align-items:center;justify-content:flex-end;gap:5px}.dynamic-table .table-input-wrap>label{margin:0;font-weight:700}.dynamic-table .table-input-wrap>input{max-width:400px}.dynamic-table .table-items-count{flex:1}.dynamic-table .table-wrapper{position:relative}.dynamic-table table.table{border-collapse:collapse;margin:0;width:100%;font-family:inherit;font-size:inherit}.dynamic-table table.table th{text-align:left}.dynamic-table table.table th,.dynamic-table table.table td{text-align:left;padding:6px 12px;border:1px solid var(--border-color);vertical-align:middle;white-space:nowrap;width:var(--cell-width, 25%);min-width:fit-content}.dynamic-table table.table-sm th,.dynamic-table table.table-sm td{font-size:var(--font-size-sm);padding:4px 6px}.dynamic-table table.table thead th{font-weight:500}.dynamic-table table.table thead th .dropdown-box{display:block;width:100%;text-align:left}.dynamic-table table.table thead th .search-input{width:100%}.dynamic-table table.table thead th span{display:inline-block;vertical-align:top}.dynamic-table table.table thead th a{cursor:pointer;text-align:left}.dynamic-table table.table thead th.filter-column{text-align:center}.dynamic-table table.table thead tr:first-child th{border-top-width:0}.dynamic-table table.table tbody tr:last-child td{border-bottom-width:0}.dynamic-table table.table thead tr th,.dynamic-table table.table tbody tr td{background-color:var(--table-bg)}.dynamic-table table.table thead tr th:first-child,.dynamic-table table.table tbody tr td:first-child{border-left-width:0}.dynamic-table table.table thead tr th:last-child,.dynamic-table table.table tbody tr td:last-child{border-right-width:0}.dynamic-table table.table tbody tr.active td{background-color:var(--highlight-color);color:var(--highlight-text-color)}.dynamic-table .table-striped>tbody>tr:nth-of-type(odd) td{background-color:var(--table-stripe-bg)}.dynamic-table .table-striped>tbody>tr:nth-of-type(odd).active td{background-color:var(--highlight-color);color:var(--highlight-text-color)}.sort-dropdown .dropdown-box-toggle a.dropdown-box-toggle-link{margin-right:0;padding-right:0}.sort-dropdown .dropdown-box-toggle a.dropdown-box-toggle-link:after{display:none}.sort-dropdown-content-wrapper a.sort,.dynamic-table a.sort{position:relative;display:block;margin-right:calc(var(--arrow-size) * 2);-webkit-user-select:none;user-select:none;padding-right:5px}.sort-dropdown-content-wrapper a.sort:before,.sort-dropdown-content-wrapper a.sort:after,.dynamic-table a.sort:before,.dynamic-table a.sort:after{content:\"\";position:absolute;transition:.2s ease;left:calc(100% + var(--arrow-size));top:calc(50% - var(--arrow-size));border-top:var(--arrow-size) solid transparent;border-bottom:var(--arrow-size) solid transparent;border-left:var(--arrow-size) solid var(--arrow-color);transform:rotate(calc(var(--arrow-rotation) * 1deg)) translate(var(--arrow-space))}.sort-dropdown-content-wrapper a.sort:before,.dynamic-table a.sort:before{--arrow-rotation: -90}.sort-dropdown-content-wrapper a.sort.sort-desc:before,.dynamic-table a.sort.sort-desc:before{--arrow-color: black}.sort-dropdown-content-wrapper a.sort.sort-asc:after,.dynamic-table a.sort.sort-asc:after{--arrow-color: black}\n"], dependencies: [{ kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$3.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$3.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$3.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgxTemplateOutletDirective, selector: "[ngxTemplateOutlet]", inputs: ["context", "additionalContext", "ngxTemplateOutlet"] }, { kind: "directive", type: PaginationDirective, selector: "[pagination]", inputs: ["pagination", "page", "itemsPerPage", "updateTime", "waitFor"], outputs: ["pageChange", "onRefresh"], exportAs: ["pagination"] }, { kind: "directive", type: PaginationItemDirective, selector: "[paginationItem]" }, { kind: "component", type: DropdownBoxComponent, selector: "dropdown-box", inputs: ["closeInside", "attachTo", "placement", "crossAxis", "alignment", "autoAlignment", "allowedPlacements", "componentClass"] }, { kind: "component", type: PaginationMenuComponent, selector: "pagination-menu", inputs: ["maxSize", "urlParam", "directionLinks", "boundaryLinks"] }, { kind: "pipe", type: IncludesPipe, name: "includes" }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: ValuesPipe, name: "values" }], encapsulation: i0.ViewEncapsulation.None }); }
7478
7632
  }
7479
7633
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicTableComponent, decorators: [{
7480
7634
  type: Component,
7481
- args: [{ standalone: false, encapsulation: ViewEncapsulation.None, selector: "dynamic-table", template: "<ng-template #columnTemplate let-context let-column=\"column\" let-template=\"template\">\n <ng-template #defaultTemplate let-column=\"column\" let-item=\"item\">\n <span>{{ item[column] == undefined || item[column] == null ? '-' : item[column] }}</span>\n </ng-template>\n <ng-template #pureTemplate>\n <ng-container [ngxTemplateOutlet]=\"template.ref\" [context]=\"context\"></ng-container>\n </ng-template>\n <td [ngClass]=\"'column-' + column\"\n [attr.data-testid]=\"testId + '-' + column + '-' + context.rowIndex\"\n *ngIf=\"!template || !template.pure; else pureTemplate\">\n <ng-container [ngxTemplateOutlet]=\"!template ? defaultTemplate : template.ref\"\n [context]=\"context\"></ng-container>\n </td>\n</ng-template>\n\n<ng-template #columnsTemplate let-context>\n <ng-container *ngFor=\"let column of cols\"\n [ngxTemplateOutlet]=\"columnTemplate\"\n [context]=\"context\"\n [additionalContext]=\"{\n template: templates[column],\n column: column\n }\"></ng-container>\n</ng-template>\n\n<ng-template #defaultRowTemplate let-context>\n <tr #elem\n [draggable]=\"!!dragStartFn\"\n [ngClass]=\"{active: selected === context.item}\"\n (dragstart)=\"onDragStart($event, elem, context.item)\"\n (dragenter)=\"onDragEnter($event, elem, context.item)\"\n (dragleave)=\"onDragLeave($event, elem)\"\n (drop)=\"onDrop($event, elem, context.item)\">\n <ng-container [ngxTemplateOutlet]=\"columnsTemplate\" [context]=\"context\"></ng-container>\n </tr>\n</ng-template>\n\n<ng-template #headerTemplate let-column=\"column\" let-toggle=\"toggle\">\n <ng-template #defaultCol>\n <span>{{ realColumns[column].title | translate }}</span>\n </ng-template>\n <ng-template #emptyCol>\n <span>-</span>\n </ng-template>\n <ng-container *ngIf=\"realColumns[column]; else emptyCol\">\n <a *ngIf=\"realColumns[column].sort; else defaultCol\"\n [ngClass]=\"['sort', orderBy !== column ? '' : (orderDescending ? 'sort-desc' : 'sort-asc')]\"\n (click)=\"setSorting(column, toggle)\">\n <span>{{ realColumns[column].title | translate }}</span>\n </a>\n </ng-container>\n</ng-template>\n\n<div class=\"dynamic-table\">\n <div class=\"table-features-row\">\n <ng-content select=\"[table-features-before]\"></ng-content>\n <div class=\"table-input-wrap table-search-filter\" *ngIf=\"showFilter\">\n <label *ngIf=\"filterLabel\" [attr.for]=\"tableId\">\n {{ filterLabel | translate }}\n </label>\n <input type=\"text\"\n class=\"search-input\"\n [attr.id]=\"tableId\"\n [attr.data-testid]=\"testId + '-filter-input'\"\n [placeholder]=\"placeholder | translate\"\n [ngModel]=\"filter\"\n (ngModelChange)=\"setFilter($event)\"/>\n </div>\n <dropdown-box componentClass=\"sort-dropdown\" #sortDd>\n <ng-container toggle-content\n [ngTemplateOutlet]=\"headerTemplate\"\n [ngTemplateOutletContext]=\"{column: orderBy, toggle: sortDd}\"></ng-container>\n <ul>\n <ng-container *ngFor=\"let column of cols\">\n <li [ngClass]=\"'sort-column sort-' + column\" *ngIf=\"realColumns[column].sort\">\n <ng-container [ngTemplateOutlet]=\"headerTemplate\"\n [ngTemplateOutletContext]=\"{column: column}\"></ng-container>\n </li>\n </ng-container>\n </ul>\n </dropdown-box>\n <div class=\"table-input-wrap table-items-count\" *ngIf=\"showItems\">\n <label>\n {{ 'label.items.before' | translate }}\n </label>\n <dropdown-box>\n <ng-container toggle-content>\n {{ itemsPerPage }}\n </ng-container>\n <ul>\n <ng-container *ngFor=\"let count of showItems\">\n <li [ngClass]=\"'item-count count-' + count\" (click)=\"setItemsPerPage(count)\">\n {{ count }}\n </li>\n </ng-container>\n </ul>\n </dropdown-box>\n <label>\n {{ 'label.items.after' | translate }}\n </label>\n </div>\n <ng-content select=\"[table-features-after]\"></ng-content>\n </div>\n <div class=\"table-content-row\"\n #pagination=\"pagination\"\n [pagination]=\"loadData\"\n [page]=\"page\"\n [itemsPerPage]=\"itemsPerPage\"\n [updateTime]=\"updateTime\">\n <pagination-menu [urlParam]=\"urlParam\" [maxSize]=\"maxPages\" [directionLinks]=\"directionLinks\"\n [boundaryLinks]=\"boundaryLinks\"></pagination-menu>\n <div class=\"table-responsive\">\n <ng-template #defaultWrapperTemplate>\n <table class=\"table table-striped\">\n <thead>\n <tr>\n <th *ngFor=\"let column of cols\" [ngClass]=\"'header-column column-' + column\">\n <ng-container [ngTemplateOutlet]=\"headerTemplate\"\n [ngTemplateOutletContext]=\"{column: column}\"></ng-container>\n </th>\n </tr>\n <tr *ngIf=\"hasQuery\">\n <th *ngFor=\"let column of cols\" [ngClass]=\"['column-' + column, 'filter-column']\">\n <ng-container *ngIf=\"realColumns[column].filter\" [ngSwitch]=\"realColumns[column].filterType\">\n <ng-container *ngSwitchCase=\"'enum'\">\n <ng-template #optionItem let-option=\"option\">\n {{ (realColumns[column].enumPrefix ? realColumns[column].enumPrefix + '.' + option : option) | translate }}\n </ng-template>\n <dropdown-box componentClass=\"filter-box\"\n [ngClass]=\"'filter-box-' + column\" [closeInside]=\"false\">\n <ng-container toggle-content>\n <span class=\"toggle-placeholder\" *ngIf=\"!query[column]\">\n {{ realColumns[column].title | translate }}\n </span>\n <span [ngClass]=\"['option-' + option, column + '-option-' + option, option]\"\n *ngFor=\"let option of query[column] | values; let ix = index\">\n <ng-container *ngIf=\"ix > 0\">, </ng-container>\n <ng-container [ngTemplateOutlet]=\"optionItem\"\n [ngTemplateOutletContext]=\"{option: option}\"></ng-container>\n </span>\n </ng-container>\n <ul>\n <li [ngClass]=\"[column + '-option', 'option-' + option, option]\"\n (click)=\"setQueryValue(column, option)\"\n *ngFor=\"let option of realColumns[column].enum\">\n <a [ngClass]=\"'toggle-link-' + column\">\n <input type=\"checkbox\" [checked]=\"query[column] | includes: option\">\n <ng-container [ngTemplateOutlet]=\"optionItem\"\n [ngTemplateOutletContext]=\"{option: option}\"></ng-container>\n </a>\n </li>\n </ul>\n </dropdown-box>\n </ng-container>\n <ng-container *ngSwitchCase=\"'checkbox'\">\n <input type=\"checkbox\"\n [attr.data-testid]=\"testId + '-filter-' + column\"\n [placeholder]=\"realColumns[column].title | translate\"\n [ngModel]=\"query[column]\"\n (ngModelChange)=\"setQueryValue(column, $event)\"/>\n </ng-container>\n <ng-container *ngSwitchDefault>\n <input class=\"search-input\"\n type=\"text\"\n [attr.data-testid]=\"testId + '-filter-' + column\"\n [placeholder]=\"realColumns[column].title | translate\"\n [ngModel]=\"query[column]\"\n (ngModelChange)=\"setQueryValue(column, $event)\"/>\n </ng-container>\n </ng-container>\n </th>\n </tr>\n </thead>\n <tbody>\n <ng-container *paginationItem=\"let context\"\n [ngxTemplateOutlet]=\"rowTemplate\"\n [context]=\"context\"\n [additionalContext]=\"this\"></ng-container>\n </tbody>\n </table>\n </ng-template>\n\n <div class=\"table-wrapper\">\n <ng-content select=\"[table-top]\"></ng-content>\n <ng-container [ngxTemplateOutlet]=\"wrapperTemplate || defaultWrapperTemplate\"\n [context]=\"this\"></ng-container>\n <ng-content select=\"[table-bottom]\"></ng-content>\n </div>\n </div>\n <pagination-menu [urlParam]=\"urlParam\" [maxSize]=\"maxPages\" [directionLinks]=\"directionLinks\"\n [boundaryLinks]=\"boundaryLinks\"></pagination-menu>\n </div>\n</div>\n", styles: [".dynamic-table{--table-bg: transparent;--table-stripe-bg: rgba(210, 210, 210, .35);--border-size: 1px;--border-color: #ced4da;--bg-color: #ffffff;--text-color: #151515;--highlight-color: var(--primary-color, #888888);--highlight-text-color: #ffffff;--display-toggle: none;--arrow-size: 6px;--arrow-rotation: 90;--arrow-space: calc(var(--arrow-size) * .5 + 1px);--arrow-color: #c6c6c6}.dynamic-table *{box-sizing:border-box}.dynamic-table .search-input{background:var(--bg-color);color:var(--text-color);border:var(--border-size) solid var(--border-color);border-radius:5px;padding:6px 12px;-webkit-user-select:none;user-select:none;font-weight:400;font-size:var(--table-input-font-size, 15px);line-height:var(--table-input-line-height, 18px);outline:none}.dynamic-table .search-input .toggle-placeholder,.dynamic-table .search-input ::placeholder{color:#495057}.dynamic-table .table-responsive{border:1px solid var(--border-color);overflow:hidden;overflow-x:auto;margin-bottom:1rem}.dynamic-table .table-features-row:not(:empty){display:flex;gap:10px;flex-wrap:wrap;align-items:center;justify-content:space-between;margin-bottom:20px}.dynamic-table .table-content-row{position:relative}.dynamic-table .sort-dropdown{display:none}.dynamic-table .table-input-wrap{display:flex;align-items:center;justify-content:flex-end;gap:5px}.dynamic-table .table-input-wrap>label{margin:0;font-weight:700}.dynamic-table .table-input-wrap>input{max-width:400px}.dynamic-table .table-items-count{flex:1}.dynamic-table .table-wrapper{position:relative}.dynamic-table table.table{border-collapse:collapse;margin:0;width:100%;font-family:inherit;font-size:inherit}.dynamic-table table.table th{text-align:left}.dynamic-table table.table th,.dynamic-table table.table td{text-align:left;padding:6px 12px;border:1px solid var(--border-color);vertical-align:middle;white-space:nowrap;width:var(--cell-width, 25%);min-width:fit-content}.dynamic-table table.table-sm th,.dynamic-table table.table-sm td{font-size:var(--font-size-sm);padding:4px 6px}.dynamic-table table.table thead th{font-weight:500}.dynamic-table table.table thead th .dropdown-box{display:block;width:100%;text-align:left}.dynamic-table table.table thead th .search-input{width:100%}.dynamic-table table.table thead th span{display:inline-block;vertical-align:top}.dynamic-table table.table thead th a{cursor:pointer;text-align:left}.dynamic-table table.table thead th.filter-column{text-align:center}.dynamic-table table.table thead tr:first-child th{border-top-width:0}.dynamic-table table.table tbody tr:last-child td{border-bottom-width:0}.dynamic-table table.table thead tr th,.dynamic-table table.table tbody tr td{background-color:var(--table-bg)}.dynamic-table table.table thead tr th:first-child,.dynamic-table table.table tbody tr td:first-child{border-left-width:0}.dynamic-table table.table thead tr th:last-child,.dynamic-table table.table tbody tr td:last-child{border-right-width:0}.dynamic-table table.table tbody tr.active td{background-color:var(--highlight-color);color:var(--highlight-text-color)}.dynamic-table .table-striped>tbody>tr:nth-of-type(odd) td{background-color:var(--table-stripe-bg)}.dynamic-table .table-striped>tbody>tr:nth-of-type(odd).active td{background-color:var(--highlight-color);color:var(--highlight-text-color)}.sort-dropdown .dropdown-box-toggle a.dropdown-box-toggle-link{margin-right:0;padding-right:0}.sort-dropdown .dropdown-box-toggle a.dropdown-box-toggle-link:after{display:none}.sort-dropdown-content-wrapper a.sort,.dynamic-table a.sort{position:relative;display:block;margin-right:calc(var(--arrow-size) * 2);-webkit-user-select:none;user-select:none;padding-right:5px}.sort-dropdown-content-wrapper a.sort:before,.sort-dropdown-content-wrapper a.sort:after,.dynamic-table a.sort:before,.dynamic-table a.sort:after{content:\"\";position:absolute;transition:.2s ease;left:calc(100% + var(--arrow-size));top:calc(50% - var(--arrow-size));border-top:var(--arrow-size) solid transparent;border-bottom:var(--arrow-size) solid transparent;border-left:var(--arrow-size) solid var(--arrow-color);transform:rotate(calc(var(--arrow-rotation) * 1deg)) translate(var(--arrow-space))}.sort-dropdown-content-wrapper a.sort:before,.dynamic-table a.sort:before{--arrow-rotation: -90}.sort-dropdown-content-wrapper a.sort.sort-desc:before,.dynamic-table a.sort.sort-desc:before{--arrow-color: black}.sort-dropdown-content-wrapper a.sort.sort-asc:after,.dynamic-table a.sort.sort-asc:after{--arrow-color: black}\n"] }]
7635
+ args: [{ standalone: false, encapsulation: ViewEncapsulation.None, selector: "dynamic-table", template: "<ng-template #columnTemplate let-context let-column=\"column\" let-template=\"template\">\n <ng-template #defaultTemplate let-column=\"column\" let-item=\"item\">\n <span>{{ item[column] == undefined || item[column] == null ? '-' : item[column] }}</span>\n </ng-template>\n <ng-template #pureTemplate>\n <ng-container [ngxTemplateOutlet]=\"template.ref\" [context]=\"context\"></ng-container>\n </ng-template>\n <td [ngClass]=\"'column-' + column\"\n [attr.data-testid]=\"testId + '-' + column + '-' + context.rowIndex\"\n *ngIf=\"!template || !template.pure; else pureTemplate\">\n <ng-container [ngxTemplateOutlet]=\"!template ? defaultTemplate : template.ref\"\n [context]=\"context\"></ng-container>\n </td>\n</ng-template>\n\n<ng-template #columnsTemplate let-context>\n <ng-container *ngFor=\"let column of cols\"\n [ngxTemplateOutlet]=\"columnTemplate\"\n [context]=\"context\"\n [additionalContext]=\"{\n template: templates[column],\n column: column\n }\"></ng-container>\n</ng-template>\n\n<ng-template #defaultRowTemplate let-context>\n <tr #elem\n [draggable]=\"!!dragStartFn\"\n [ngClass]=\"{active: selected === context.item}\"\n (dragstart)=\"onDragStart($event, elem, context.item)\"\n (dragenter)=\"onDragEnter($event, elem, context.item)\"\n (dragleave)=\"onDragLeave($event, elem)\"\n (drop)=\"onDrop($event, elem, context.item)\">\n <ng-container [ngxTemplateOutlet]=\"columnsTemplate\" [context]=\"context\"></ng-container>\n </tr>\n</ng-template>\n\n<ng-template #headerTemplate let-column=\"column\" let-toggle=\"toggle\">\n <ng-template #defaultCol>\n <span>{{ realColumns[column].title | translate }}</span>\n </ng-template>\n <ng-template #emptyCol>\n <span>-</span>\n </ng-template>\n <ng-container *ngIf=\"realColumns[column]; else emptyCol\">\n <a *ngIf=\"realColumns[column].sort; else defaultCol\"\n [ngClass]=\"['sort', orderBy !== column ? '' : (orderDescending ? 'sort-desc' : 'sort-asc')]\"\n (click)=\"setSorting(column, toggle)\">\n <span>{{ realColumns[column].title | translate }}</span>\n </a>\n </ng-container>\n</ng-template>\n\n<div class=\"dynamic-table\">\n <div class=\"table-features-row\">\n <ng-content select=\"[table-features-before]\"></ng-content>\n @if (showFilter) {\n <div class=\"table-input-wrap table-search-filter\">\n <label *ngIf=\"filterLabel\" [attr.for]=\"tableId\">\n {{ filterLabel | translate }}\n </label>\n <input type=\"text\"\n class=\"search-input\"\n [attr.id]=\"tableId\"\n [attr.data-testid]=\"testId + '-filter-input'\"\n [placeholder]=\"placeholder | translate\"\n [ngModel]=\"filter\"\n (ngModelChange)=\"setFilter($event)\"/>\n </div>\n }\n @if (sortable) {\n <dropdown-box componentClass=\"sort-dropdown\" #sortDd>\n <ng-container toggle-content\n [ngTemplateOutlet]=\"headerTemplate\"\n [ngTemplateOutletContext]=\"{column: orderBy, toggle: sortDd}\"></ng-container>\n <ul>\n <ng-container *ngFor=\"let column of cols\">\n <li [ngClass]=\"'sort-column sort-' + column\" *ngIf=\"realColumns[column].sort\">\n <ng-container [ngTemplateOutlet]=\"headerTemplate\"\n [ngTemplateOutletContext]=\"{column: column}\"></ng-container>\n </li>\n </ng-container>\n </ul>\n </dropdown-box>\n }\n @if (showItems) {\n <div class=\"table-input-wrap table-items-count\">\n <label>\n {{ 'label.items.before' | translate }}\n </label>\n <dropdown-box>\n <ng-container toggle-content>\n {{ itemsPerPage }}\n </ng-container>\n <ul>\n <ng-container *ngFor=\"let count of showItems\">\n <li [ngClass]=\"'item-count count-' + count\" (click)=\"setItemsPerPage(count)\">\n {{ count }}\n </li>\n </ng-container>\n </ul>\n </dropdown-box>\n <label>\n {{ 'label.items.after' | translate }}\n </label>\n </div>\n }\n <ng-content select=\"[table-features-after]\"></ng-content>\n </div>\n <div class=\"table-content-row\"\n #pagination=\"pagination\"\n [pagination]=\"loadData\"\n [page]=\"page\"\n [itemsPerPage]=\"itemsPerPage\"\n [updateTime]=\"updateTime\">\n <pagination-menu [urlParam]=\"urlParam\" [maxSize]=\"maxPages\" [directionLinks]=\"directionLinks\"\n [boundaryLinks]=\"boundaryLinks\"></pagination-menu>\n <div class=\"table-responsive\">\n <ng-template #defaultWrapperTemplate>\n <table class=\"table table-striped\">\n <thead>\n <tr>\n <th *ngFor=\"let column of cols\" [ngClass]=\"'header-column column-' + column\">\n <ng-container [ngTemplateOutlet]=\"headerTemplate\"\n [ngTemplateOutletContext]=\"{column: column}\"></ng-container>\n </th>\n </tr>\n <tr *ngIf=\"hasQuery\">\n <th *ngFor=\"let column of cols\" [ngClass]=\"['column-' + column, 'filter-column']\">\n <ng-container *ngIf=\"realColumns[column].filter\" [ngSwitch]=\"realColumns[column].filterType\">\n <ng-container *ngSwitchCase=\"'enum'\">\n <ng-template #optionItem let-option=\"option\">\n {{ (realColumns[column].enumPrefix ? realColumns[column].enumPrefix + '.' + option : option) | translate }}\n </ng-template>\n <dropdown-box componentClass=\"filter-box\"\n [ngClass]=\"'filter-box-' + column\" [closeInside]=\"false\">\n <ng-container toggle-content>\n <span class=\"toggle-placeholder\" *ngIf=\"!query[column]\">\n {{ realColumns[column].title | translate }}\n </span>\n <span [ngClass]=\"['option-' + option, column + '-option-' + option, option]\"\n *ngFor=\"let option of query[column] | values; let ix = index\">\n <ng-container *ngIf=\"ix > 0\">, </ng-container>\n <ng-container [ngTemplateOutlet]=\"optionItem\"\n [ngTemplateOutletContext]=\"{option: option}\"></ng-container>\n </span>\n </ng-container>\n <ul>\n <li [ngClass]=\"[column + '-option', 'option-' + option, option]\"\n (click)=\"setQueryValue(column, option)\"\n *ngFor=\"let option of realColumns[column].enum\">\n <a [ngClass]=\"'toggle-link-' + column\">\n <input type=\"checkbox\" [checked]=\"query[column] | includes: option\">\n <ng-container [ngTemplateOutlet]=\"optionItem\"\n [ngTemplateOutletContext]=\"{option: option}\"></ng-container>\n </a>\n </li>\n </ul>\n </dropdown-box>\n </ng-container>\n <ng-container *ngSwitchCase=\"'checkbox'\">\n <input type=\"checkbox\"\n [attr.data-testid]=\"testId + '-filter-' + column\"\n [placeholder]=\"realColumns[column].title | translate\"\n [ngModel]=\"query[column]\"\n (ngModelChange)=\"setQueryValue(column, $event)\"/>\n </ng-container>\n <ng-container *ngSwitchDefault>\n <input class=\"search-input\"\n type=\"text\"\n [attr.data-testid]=\"testId + '-filter-' + column\"\n [placeholder]=\"realColumns[column].title | translate\"\n [ngModel]=\"query[column]\"\n (ngModelChange)=\"setQueryValue(column, $event)\"/>\n </ng-container>\n </ng-container>\n </th>\n </tr>\n </thead>\n <tbody>\n <ng-container *paginationItem=\"let context\"\n [ngxTemplateOutlet]=\"rowTemplate\"\n [context]=\"context\"\n [additionalContext]=\"this\"></ng-container>\n </tbody>\n </table>\n </ng-template>\n\n <div class=\"table-wrapper\">\n <ng-content select=\"[table-top]\"></ng-content>\n <ng-container [ngxTemplateOutlet]=\"wrapperTemplate || defaultWrapperTemplate\"\n [context]=\"this\"></ng-container>\n <ng-content select=\"[table-bottom]\"></ng-content>\n </div>\n </div>\n <pagination-menu [urlParam]=\"urlParam\" [maxSize]=\"maxPages\" [directionLinks]=\"directionLinks\"\n [boundaryLinks]=\"boundaryLinks\"></pagination-menu>\n </div>\n</div>\n", styles: [".dynamic-table{--table-bg: transparent;--table-stripe-bg: rgba(210, 210, 210, .35);--border-size: 1px;--border-color: #ced4da;--bg-color: #ffffff;--text-color: #151515;--highlight-color: var(--primary-color, #888888);--highlight-text-color: #ffffff;--display-toggle: none;--arrow-size: 6px;--arrow-rotation: 90;--arrow-space: calc(var(--arrow-size) * .5 + 1px);--arrow-color: #c6c6c6}.dynamic-table *{box-sizing:border-box}.dynamic-table .search-input{background:var(--bg-color);color:var(--text-color);border:var(--border-size) solid var(--border-color);border-radius:5px;padding:6px 12px;-webkit-user-select:none;user-select:none;font-weight:400;font-size:var(--table-input-font-size, 15px);line-height:var(--table-input-line-height, 18px);outline:none}.dynamic-table .search-input .toggle-placeholder,.dynamic-table .search-input ::placeholder{color:#495057}.dynamic-table .table-responsive{border:1px solid var(--border-color);overflow:hidden;overflow-x:auto;margin-bottom:1rem}.dynamic-table .table-features-row:not(:empty){display:flex;gap:10px;flex-wrap:wrap;align-items:center;justify-content:space-between;margin-bottom:20px}.dynamic-table .table-content-row{position:relative}.dynamic-table .sort-dropdown{display:none}.dynamic-table .table-input-wrap{display:flex;align-items:center;justify-content:flex-end;gap:5px}.dynamic-table .table-input-wrap>label{margin:0;font-weight:700}.dynamic-table .table-input-wrap>input{max-width:400px}.dynamic-table .table-items-count{flex:1}.dynamic-table .table-wrapper{position:relative}.dynamic-table table.table{border-collapse:collapse;margin:0;width:100%;font-family:inherit;font-size:inherit}.dynamic-table table.table th{text-align:left}.dynamic-table table.table th,.dynamic-table table.table td{text-align:left;padding:6px 12px;border:1px solid var(--border-color);vertical-align:middle;white-space:nowrap;width:var(--cell-width, 25%);min-width:fit-content}.dynamic-table table.table-sm th,.dynamic-table table.table-sm td{font-size:var(--font-size-sm);padding:4px 6px}.dynamic-table table.table thead th{font-weight:500}.dynamic-table table.table thead th .dropdown-box{display:block;width:100%;text-align:left}.dynamic-table table.table thead th .search-input{width:100%}.dynamic-table table.table thead th span{display:inline-block;vertical-align:top}.dynamic-table table.table thead th a{cursor:pointer;text-align:left}.dynamic-table table.table thead th.filter-column{text-align:center}.dynamic-table table.table thead tr:first-child th{border-top-width:0}.dynamic-table table.table tbody tr:last-child td{border-bottom-width:0}.dynamic-table table.table thead tr th,.dynamic-table table.table tbody tr td{background-color:var(--table-bg)}.dynamic-table table.table thead tr th:first-child,.dynamic-table table.table tbody tr td:first-child{border-left-width:0}.dynamic-table table.table thead tr th:last-child,.dynamic-table table.table tbody tr td:last-child{border-right-width:0}.dynamic-table table.table tbody tr.active td{background-color:var(--highlight-color);color:var(--highlight-text-color)}.dynamic-table .table-striped>tbody>tr:nth-of-type(odd) td{background-color:var(--table-stripe-bg)}.dynamic-table .table-striped>tbody>tr:nth-of-type(odd).active td{background-color:var(--highlight-color);color:var(--highlight-text-color)}.sort-dropdown .dropdown-box-toggle a.dropdown-box-toggle-link{margin-right:0;padding-right:0}.sort-dropdown .dropdown-box-toggle a.dropdown-box-toggle-link:after{display:none}.sort-dropdown-content-wrapper a.sort,.dynamic-table a.sort{position:relative;display:block;margin-right:calc(var(--arrow-size) * 2);-webkit-user-select:none;user-select:none;padding-right:5px}.sort-dropdown-content-wrapper a.sort:before,.sort-dropdown-content-wrapper a.sort:after,.dynamic-table a.sort:before,.dynamic-table a.sort:after{content:\"\";position:absolute;transition:.2s ease;left:calc(100% + var(--arrow-size));top:calc(50% - var(--arrow-size));border-top:var(--arrow-size) solid transparent;border-bottom:var(--arrow-size) solid transparent;border-left:var(--arrow-size) solid var(--arrow-color);transform:rotate(calc(var(--arrow-rotation) * 1deg)) translate(var(--arrow-space))}.sort-dropdown-content-wrapper a.sort:before,.dynamic-table a.sort:before{--arrow-rotation: -90}.sort-dropdown-content-wrapper a.sort.sort-desc:before,.dynamic-table a.sort.sort-desc:before{--arrow-color: black}.sort-dropdown-content-wrapper a.sort.sort-asc:after,.dynamic-table a.sort.sort-asc:after{--arrow-color: black}\n"] }]
7482
7636
  }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { dataLoader: [{
7483
7637
  type: Input
7484
7638
  }], data: [{
@@ -7582,6 +7736,14 @@ class InteractiveItemComponent {
7582
7736
  get shapes() {
7583
7737
  return this.mShapes;
7584
7738
  }
7739
+ get hovered() {
7740
+ return this.canvas?.hoveredItem === this;
7741
+ }
7742
+ set hovered(value) {
7743
+ if (!this.canvas)
7744
+ return;
7745
+ this.canvas.hoveredItem = value ? this : null;
7746
+ }
7585
7747
  get x() {
7586
7748
  return this.pos.x;
7587
7749
  }
@@ -7625,7 +7787,6 @@ class InteractiveItemComponent {
7625
7787
  this.active = false;
7626
7788
  this.index = -1;
7627
7789
  this.valid = true;
7628
- this.cycles = [0];
7629
7790
  this.pos = Point.Zero;
7630
7791
  this.direction = "none";
7631
7792
  this.mShapes = [];
@@ -7640,41 +7801,39 @@ class InteractiveItemComponent {
7640
7801
  return;
7641
7802
  this.calcShapes();
7642
7803
  }
7643
- calcShapes(cycles) {
7804
+ calcShapes() {
7644
7805
  const ratio = this.canvas.ratio ?? 1;
7645
7806
  const x = this.pos.x * ratio;
7646
- this.cycles = cycles ?? this.cycles;
7647
- this.mShapes = this.cycles.map(pan => {
7648
- const y = this.pos.y * ratio + pan;
7649
- return this.calcShape(x, y);
7650
- });
7807
+ const y = this.pos.y * ratio;
7808
+ this.mShapes = this.canvas.cycles.map(pan => this.calcShape(x, y + pan));
7651
7809
  }
7652
7810
  hit(point) {
7653
7811
  for (const shape of this.shapes) {
7654
- if (shape.minDistance(point) <= 0)
7812
+ if (shape.intersects(point))
7655
7813
  return true;
7656
7814
  }
7657
7815
  return false;
7658
7816
  }
7659
- move(dx, dy) {
7660
- if (this.direction === "none")
7817
+ moveTo(x, y) {
7818
+ if (!this.canvas || this.direction === "none")
7661
7819
  return;
7662
- switch (this.direction) {
7663
- case "horizontal":
7664
- this.pos = new Point(this.pos.x + dx, this.pos.y);
7665
- break;
7666
- case "vertical":
7667
- this.pos = new Point(this.pos.x, this.pos.y + dy);
7668
- break;
7669
- default:
7670
- this.pos = new Point(this.pos.x + dx, this.pos.y + dy);
7671
- break;
7672
- }
7673
- const params = this.canvas.params || {};
7820
+ const target = this.restrictPosition(this.direction === "vertical" ? this.pos.x : x, this.direction === "horizontal" ? this.pos.y : y);
7821
+ this.pos = new Point(target);
7674
7822
  this.calcShapes();
7675
- this.valid = this.isValidByParams() && this.canvas.items.every(other => this === other || this.isValidByDistance(other));
7823
+ this.valid = this.isValidByParams() &&
7824
+ this.canvas.items.every(other => this === other || this.isValidByDistance(other));
7676
7825
  this.validPos = this.valid ? this.pos : this.validPos;
7677
7826
  }
7827
+ moveBy(dx, dy) {
7828
+ const { x, y } = this.pos;
7829
+ this.moveTo(x + dx, y + dy);
7830
+ }
7831
+ moveX(x) {
7832
+ this.moveTo(x, this.pos.y);
7833
+ }
7834
+ moveY(y) {
7835
+ this.moveTo(this.pos.x, y);
7836
+ }
7678
7837
  moveEnd() {
7679
7838
  if (this.valid)
7680
7839
  return;
@@ -7682,18 +7841,32 @@ class InteractiveItemComponent {
7682
7841
  this.valid = true;
7683
7842
  this.calcShapes();
7684
7843
  }
7844
+ restrictPosition(x, y) {
7845
+ return {
7846
+ x: clamp(x, this.canvas.xRange),
7847
+ y: this.canvas.infinite
7848
+ ? overflow(y, this.canvas.yRange)
7849
+ : clamp(y, this.canvas.yRange)
7850
+ };
7851
+ }
7685
7852
  isValidByParams() {
7686
- return true;
7853
+ return !this.shapes.some(shape => {
7854
+ return this.canvas.exclusions.some(ex => {
7855
+ return shape.distance(ex) < 1;
7856
+ });
7857
+ });
7687
7858
  }
7688
7859
  isValidByDistance(other) {
7689
- const min = this.getMinDistance(other);
7690
- const minPixels = isNaN(min) || min <= 0 ? 1 : min * this.canvas.ratio;
7860
+ const minPixels = this.distToPixels(this.getMinDistance(other));
7691
7861
  return !this.shapes.some(shape => {
7692
7862
  return other.shapes.some(os => {
7693
- return os.minDistance(shape) <= minPixels;
7863
+ return shape.distance(os) <= minPixels;
7694
7864
  });
7695
7865
  });
7696
7866
  }
7867
+ distToPixels(value) {
7868
+ return !this.canvas ? 1 : Math.max(1, (isNaN(value) || value < 0 ? 0 : value) * (this.canvas.ratio ?? 1));
7869
+ }
7697
7870
  getMinDistance(other) {
7698
7871
  return !other ? 0 : null;
7699
7872
  }
@@ -7724,49 +7897,62 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
7724
7897
 
7725
7898
  class InteractiveCanvasComponent {
7726
7899
  get items() {
7727
- return this.itemComponents;
7900
+ return this.$items.value;
7728
7901
  }
7729
7902
  get canvas() {
7730
7903
  return this.canvasElem?.nativeElement;
7731
7904
  }
7732
7905
  get lockedItem() {
7733
- return this.itemComponents[this.lockedIndex];
7906
+ return this.items[this.lockedIndex];
7734
7907
  }
7735
7908
  get selectedItem() {
7736
- return this.itemComponents[this.selectedIndex];
7909
+ return this.items[this.selectedIndex];
7737
7910
  }
7738
7911
  get hoveredItem() {
7739
- return this.itemComponents[this.hoveredIndex];
7912
+ return this.items[this.hoveredIndex];
7740
7913
  }
7741
- constructor(renderer, universal, element, rootElement) {
7914
+ set hoveredItem(item) {
7915
+ this.hoveredIndex = !item ? -1 : this.items.indexOf(item);
7916
+ }
7917
+ constructor(renderer, universal) {
7742
7918
  this.renderer = renderer;
7743
7919
  this.universal = universal;
7744
- this.element = element;
7745
- this.rootElement = rootElement;
7920
+ this.infinite = false;
7921
+ this.resizeMode = "fit";
7922
+ this.params = {};
7746
7923
  this.debug = false;
7747
7924
  this.horizontal = false;
7748
7925
  this.selectedIndex = 0;
7749
- this.resizeMode = "fit";
7750
7926
  this.realWidth = 100;
7751
7927
  this.realHeight = 100;
7752
7928
  this.panOffset = 0;
7753
- this.params = {};
7929
+ this.renderCtx = {};
7930
+ this.beforeItems = [];
7931
+ this.afterItems = [];
7754
7932
  this.selectedIndexChange = new EventEmitter();
7755
- this.itemPan = new EventEmitter();
7756
- this.itemPanEnd = new EventEmitter();
7933
+ this.onRotate = new EventEmitter();
7934
+ this.onItemPan = new EventEmitter();
7935
+ this.onItemPanned = new EventEmitter();
7936
+ this.onPan = new EventEmitter();
7937
+ this.onPanned = new EventEmitter();
7938
+ this.$items = new BehaviorSubject([]);
7757
7939
  this.tempCanvas = this.universal.isServer ? null : document.createElement("canvas");
7758
7940
  this.shouldDraw = !this.universal.isServer;
7759
- this.rotation = 0;
7941
+ this.hoveredIndex = null;
7942
+ this.xRange = [0, 1];
7943
+ this.yRange = [0, 1];
7944
+ this.ratio = 1;
7945
+ this.styles = null;
7946
+ this.ctx = null;
7760
7947
  this.canvasWidth = 0;
7761
7948
  this.canvasHeight = 0;
7762
- this.hoveredIndex = null;
7763
- this.itemComponents = [];
7949
+ this.rotation = 0;
7950
+ this.basePan = 0;
7951
+ this.cycles = [0];
7952
+ this.exclusions = [];
7764
7953
  this.touched = false;
7765
- this.deltaX = 0;
7766
- this.deltaY = 0;
7767
- this.ctrInit();
7768
- }
7769
- ctrInit() {
7954
+ this.panStartRotation = 0;
7955
+ this.panStartPos = Point.Zero;
7770
7956
  }
7771
7957
  ngOnInit() {
7772
7958
  this.redraw();
@@ -7777,6 +7963,11 @@ class InteractiveCanvasComponent {
7777
7963
  }
7778
7964
  ngOnChanges() {
7779
7965
  this.params = this.params || {};
7966
+ this.renderCtx = this.renderCtx || {};
7967
+ this.beforeItems = this.beforeItems || [];
7968
+ this.afterItems = this.afterItems || [];
7969
+ this.xRange = normalizeRange(this.params.xRange || [0, this.realWidth]);
7970
+ this.yRange = normalizeRange(this.params.yRange || [0, this.realHeight]);
7780
7971
  this.resize();
7781
7972
  }
7782
7973
  ngAfterViewInit() {
@@ -7817,16 +8008,19 @@ class InteractiveCanvasComponent {
7817
8008
  this.canvasWidth = canvas[axisX];
7818
8009
  this.canvasHeight = canvas[axisY];
7819
8010
  this.fullHeight = this.realHeight * this.ratio;
8011
+ this.viewRatio = Math.round(this.canvasHeight / this.fullHeight * 100) / 100;
7820
8012
  this.fixRotation();
7821
8013
  }
7822
8014
  onTouchStart($event) {
7823
8015
  this.hoveredIndex = this.getIndexUnderPointer($event.touches.item(0));
8016
+ this.lockedIndex = this.hoveredIndex;
7824
8017
  this.touched = true;
7825
8018
  }
7826
8019
  onTouchEnd($event) {
7827
8020
  this.selectItem($event.touches.item(0));
7828
8021
  }
7829
- onMouseDown() {
8022
+ onMouseDown($event) {
8023
+ this.lockedIndex = this.getIndexUnderPointer($event);
7830
8024
  this.touched = true;
7831
8025
  }
7832
8026
  onMouseUp($event) {
@@ -7839,60 +8033,82 @@ class InteractiveCanvasComponent {
7839
8033
  this.updateCursor();
7840
8034
  }
7841
8035
  onMouseLeave() {
8036
+ if (this.touched)
8037
+ return;
7842
8038
  this.hoveredIndex = null;
7843
8039
  this.updateCursor();
7844
8040
  }
7845
- onPanStart($event) {
7846
- this.lockedIndex = this.getIndexUnderPointer($event?.pointers[0]);
7847
- this.deltaX = 0;
7848
- this.deltaY = 0;
8041
+ onPanStart() {
8042
+ this.panStartRotation = this.rotation;
8043
+ this.panStartPos = this.lockedItem?.position || Point.Zero;
7849
8044
  }
7850
- onPan($event) {
8045
+ onPanMove($event) {
7851
8046
  const item = this.lockedItem;
7852
- const deltaX = ($event.deltaX - this.deltaX) / this.ratio;
7853
- const deltaY = ($event.deltaY - this.deltaY) / this.ratio;
8047
+ const deltaX = $event.deltaX / this.ratio;
8048
+ const deltaY = $event.deltaY / this.ratio;
8049
+ const data = {
8050
+ canvas: this,
8051
+ item,
8052
+ deltaX,
8053
+ deltaY
8054
+ };
8055
+ if (this.horizontal) {
8056
+ data.deltaX = -deltaY;
8057
+ data.deltaY = +deltaX;
8058
+ }
7854
8059
  if (item) {
7855
- const data = this.horizontal
7856
- ? { pointers: $event.pointers, deltaX: -deltaY, deltaY: +deltaX }
7857
- : { pointers: $event.pointers, deltaX, deltaY };
7858
- data.item = item;
7859
- item.move(data.deltaX, data.deltaY);
7860
- this.itemPan.emit(data);
7861
- }
7862
- else if (this.resizeMode == "fill") {
7863
- this.rotation += (this.horizontal ? deltaX : deltaY) / this.realHeight * 360;
8060
+ item.moveTo(this.panStartPos.x + data.deltaX, this.panStartPos.y + data.deltaY);
8061
+ this.onItemPan.emit(data);
8062
+ }
8063
+ else if (this.infinite) {
8064
+ this.rotation = this.panStartRotation + (this.horizontal ? deltaX : deltaY) / this.realHeight * 360;
7864
8065
  this.fixRotation();
8066
+ this.onPan.emit(data);
7865
8067
  }
7866
- this.deltaX = $event.deltaX;
7867
- this.deltaY = $event.deltaY;
7868
8068
  }
7869
8069
  onPanEnd() {
7870
8070
  const item = this.lockedItem;
8071
+ const data = {
8072
+ canvas: this,
8073
+ deltaX: 0,
8074
+ deltaY: 0,
8075
+ item
8076
+ };
7871
8077
  if (item) {
7872
8078
  item.moveEnd();
7873
- this.itemPanEnd.emit({
7874
- pointers: [],
7875
- deltaX: 0,
7876
- deltaY: 0,
7877
- item
7878
- });
8079
+ this.onItemPanned.emit(data);
8080
+ }
8081
+ else {
8082
+ this.onPanned.emit(data);
7879
8083
  }
7880
8084
  this.lockedIndex = -1;
7881
8085
  }
7882
8086
  fixRotation() {
7883
8087
  if (this.fullHeight <= 0)
7884
8088
  return;
7885
- this.rotation = ((this.rotation + 180) % 360 + 360) % 360 - 180;
7886
- this.basePan = (this.rotation / 360 - 1) * this.fullHeight + this.canvasHeight * this.panOffset;
7887
- const cycles = this.resizeMode == "fit"
7888
- ? [0] : [this.basePan - this.fullHeight, this.basePan, this.basePan + this.fullHeight];
7889
- this.itemComponents.forEach(item => {
7890
- item.calcShapes(cycles);
8089
+ this.rotation = overflow(Math.round(this.rotation * 100) / 100, -180, 180);
8090
+ this.basePan = (this.rotation / 360 - 1) * this.fullHeight
8091
+ + this.canvasHeight * this.panOffset;
8092
+ this.cycles = this.infinite
8093
+ ? [this.basePan - this.fullHeight, this.basePan, this.basePan + this.fullHeight] : [0];
8094
+ this.exclusions = (this.params.exclusions || []).flatMap(coords => {
8095
+ const x = (coords[2] + coords[0]) * .5 * this.ratio;
8096
+ const y = (coords[3] + coords[1]) * .5 * this.ratio;
8097
+ const width = Math.abs(coords[2] - coords[0]) * this.ratio;
8098
+ const height = Math.abs(coords[3] - coords[1]) * this.ratio;
8099
+ return this.cycles.map(cycle => {
8100
+ return new Rect(x, y + cycle, width, height);
8101
+ });
7891
8102
  });
8103
+ this.items.forEach(item => {
8104
+ item.calcShapes();
8105
+ });
8106
+ this.onRotate.emit(this.rotation);
7892
8107
  }
7893
8108
  fixItems() {
7894
- this.itemComponents = this.itemList.toArray();
7895
- this.itemComponents.forEach((item, ix) => {
8109
+ const items = this.itemList.toArray();
8110
+ this.$items.next(items);
8111
+ items.forEach((item, ix) => {
7896
8112
  item.canvas = this;
7897
8113
  item.index = ix;
7898
8114
  });
@@ -7909,26 +8125,31 @@ class InteractiveCanvasComponent {
7909
8125
  return;
7910
8126
  item.active = !item.active;
7911
8127
  }
8128
+ this.hoveredIndex = selected;
7912
8129
  }
7913
- getIndexUnderPointer(pointer) {
7914
- if (!pointer || !this.canvasElem || !this.items)
8130
+ toCanvasPoint(pointer) {
8131
+ if (!pointer || !this.canvas)
7915
8132
  return null;
7916
- const canvasRect = this.canvasElem.nativeElement.getBoundingClientRect();
7917
- const point = this.horizontal
8133
+ const canvasRect = this.canvas?.getBoundingClientRect();
8134
+ return this.horizontal
7918
8135
  ? new Point(canvasRect.bottom - pointer.clientY, pointer.clientX - canvasRect.left)
7919
8136
  : new Point(pointer.clientX - canvasRect.left, pointer.clientY - canvasRect.top);
8137
+ }
8138
+ getIndexUnderPointer(pointer) {
8139
+ const point = this.toCanvasPoint(pointer);
8140
+ if (!point || !this.items)
8141
+ return -1;
7920
8142
  const length = this.items.length;
7921
8143
  for (let ix = 0; ix < length; ix++) {
7922
- const item = this.itemComponents[ix];
8144
+ const item = this.items[ix];
7923
8145
  if (item?.hit(point)) {
7924
- return item.disabled ? null : ix;
8146
+ return item.disabled ? -1 : ix;
7925
8147
  }
7926
8148
  }
7927
8149
  return -1;
7928
8150
  }
7929
8151
  updateCursor() {
7930
8152
  const cursor = this.getCursor();
7931
- this.renderer.setStyle(this.canvasElem.nativeElement, "cursor", cursor);
7932
8153
  this.renderer.setStyle(this.containerElem.nativeElement, "cursor", cursor);
7933
8154
  }
7934
8155
  getCursor() {
@@ -7958,17 +8179,15 @@ class InteractiveCanvasComponent {
7958
8179
  }
7959
8180
  async drawItems() {
7960
8181
  const ctx = this.ctx;
8182
+ const lockedItem = this.lockedItem;
7961
8183
  for (const item of this.items) {
7962
- for (const shape of item.shapes) {
7963
- ctx.save();
7964
- ctx.translate(shape.x, shape.y);
7965
- ctx.lineWidth = 1;
7966
- ctx.strokeStyle = "black";
7967
- ctx.fillStyle = "white";
7968
- await item.draw(ctx);
7969
- ctx.restore();
8184
+ if (item !== lockedItem) {
8185
+ await this.drawItem(ctx, item);
7970
8186
  }
7971
8187
  }
8188
+ if (lockedItem) {
8189
+ await this.drawItem(ctx, lockedItem);
8190
+ }
7972
8191
  if (!this.debug)
7973
8192
  return;
7974
8193
  ctx.lineWidth = 2;
@@ -7991,44 +8210,67 @@ class InteractiveCanvasComponent {
7991
8210
  }
7992
8211
  }
7993
8212
  }
8213
+ async drawItem(ctx, item) {
8214
+ for (const shape of item.shapes) {
8215
+ ctx.save();
8216
+ ctx.translate(shape.x, shape.y);
8217
+ ctx.lineWidth = 1;
8218
+ ctx.strokeStyle = "black";
8219
+ ctx.fillStyle = "white";
8220
+ await item.draw(ctx);
8221
+ ctx.restore();
8222
+ }
8223
+ }
7994
8224
  async draw() {
7995
8225
  const ctx = this.ctx;
7996
8226
  const canvas = ctx.canvas;
8227
+ if (canvas.width < 1 || canvas.height < 1)
8228
+ return;
7997
8229
  ctx.clearRect(0, 0, canvas.width, canvas.height);
7998
8230
  ctx.save();
7999
8231
  if (this.horizontal) {
8000
8232
  ctx.rotate(-Math.PI / 2);
8001
8233
  ctx.translate(-this.canvasWidth, 0);
8002
8234
  }
8003
- await this.beforeItems?.call(this, this);
8004
- await this.drawItems();
8005
- await this.afterItems?.call(this, this);
8235
+ try {
8236
+ for (const renderer of this.beforeItems) {
8237
+ await renderer(this, this.renderCtx);
8238
+ }
8239
+ await this.drawItems();
8240
+ for (const renderer of this.afterItems) {
8241
+ await renderer(this, this.renderCtx);
8242
+ }
8243
+ }
8244
+ catch (e) {
8245
+ console.warn(`There was an error rendering the canvas: ${e}`);
8246
+ }
8006
8247
  ctx.restore();
8007
8248
  }
8008
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: InteractiveCanvasComponent, deps: [{ token: i0.Renderer2 }, { token: UniversalService }, { token: i0.ElementRef }, { token: ROOT_ELEMENT }], target: i0.ɵɵFactoryTarget.Component }); }
8009
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: InteractiveCanvasComponent, isStandalone: false, selector: "interactive-canvas", inputs: { debug: "debug", horizontal: "horizontal", selectedIndex: "selectedIndex", resizeMode: "resizeMode", realWidth: "realWidth", realHeight: "realHeight", panOffset: "panOffset", params: "params", beforeItems: "beforeItems", afterItems: "afterItems" }, outputs: { selectedIndexChange: "selectedIndexChange", itemPan: "itemPan", itemPanEnd: "itemPanEnd" }, host: { listeners: { "window:touchend": "onTouchEnd($event)", "window:mouseup": "onMouseUp($event)" } }, queries: [{ propertyName: "itemList", predicate: InteractiveItemComponent }], viewQueries: [{ propertyName: "containerElem", first: true, predicate: ["containerElem"], descendants: true, static: true }, { propertyName: "canvasElem", first: true, predicate: ["canvasElem"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div #containerElem\n [ngClass]=\"['interactive-canvas-wrapper', horizontal ? 'horizontal' : 'vertical']\"\n (resize)=\"resize()\"\n (touchstart)=\"onTouchStart($event)\"\n (mousedown)=\"onMouseDown()\"\n (mousemove)=\"onMouseMove($event)\"\n (mouseleave)=\"onMouseLeave()\"\n (panend)=\"onPanEnd()\"\n (panmove)=\"onPan($event)\"\n (panstart)=\"onPanStart($event)\">\n <canvas #canvasElem class=\"interactive-canvas-element\"></canvas>\n</div>\n", styles: [".interactive-canvas-wrapper{width:100%;height:100%;position:relative;display:flex;align-items:center;justify-content:center}.interactive-canvas-wrapper .interactive-canvas-element{position:absolute;pointer-events:none}\n"], dependencies: [{ kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
8249
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: InteractiveCanvasComponent, deps: [{ token: i0.Renderer2 }, { token: UniversalService }], target: i0.ɵɵFactoryTarget.Component }); }
8250
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: InteractiveCanvasComponent, isStandalone: false, selector: "interactive-canvas", inputs: { infinite: "infinite", resizeMode: "resizeMode", params: "params", realWidth: "realWidth", realHeight: "realHeight", debug: "debug", horizontal: "horizontal", selectedIndex: "selectedIndex", panOffset: "panOffset", renderCtx: "renderCtx", beforeItems: "beforeItems", afterItems: "afterItems" }, outputs: { selectedIndexChange: "selectedIndexChange", onRotate: "onRotate", onItemPan: "onItemPan", onItemPanned: "onItemPanned", onPan: "onPan", onPanned: "onPanned" }, host: { listeners: { "window:touchend": "onTouchEnd($event)", "window:mouseup": "onMouseUp($event)" } }, queries: [{ propertyName: "itemList", predicate: InteractiveItemComponent }], viewQueries: [{ propertyName: "containerElem", first: true, predicate: ["containerElem"], descendants: true, static: true }, { propertyName: "canvasElem", first: true, predicate: ["canvasElem"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div #containerElem\n [ngClass]=\"['interactive-canvas-container', horizontal ? 'horizontal' : 'vertical']\"\n (resize)=\"resize()\"\n (touchstart)=\"onTouchStart($event)\"\n (mousedown)=\"onMouseDown($event)\"\n (mousemove)=\"onMouseMove($event)\"\n (mouseleave)=\"onMouseLeave()\"\n (panend)=\"onPanEnd()\"\n (panmove)=\"onPanMove($event)\"\n (panstart)=\"onPanStart()\">\n <canvas #canvasElem class=\"interactive-canvas-element\"></canvas>\n</div>\n", styles: [".interactive-canvas-container{width:100%;height:100%;position:relative;display:flex;align-items:center;justify-content:center}.interactive-canvas-container .interactive-canvas-element{position:absolute;pointer-events:none}\n"], dependencies: [{ kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
8010
8251
  }
8011
8252
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: InteractiveCanvasComponent, decorators: [{
8012
8253
  type: Component,
8013
- args: [{ standalone: false, selector: "interactive-canvas", template: "<div #containerElem\n [ngClass]=\"['interactive-canvas-wrapper', horizontal ? 'horizontal' : 'vertical']\"\n (resize)=\"resize()\"\n (touchstart)=\"onTouchStart($event)\"\n (mousedown)=\"onMouseDown()\"\n (mousemove)=\"onMouseMove($event)\"\n (mouseleave)=\"onMouseLeave()\"\n (panend)=\"onPanEnd()\"\n (panmove)=\"onPan($event)\"\n (panstart)=\"onPanStart($event)\">\n <canvas #canvasElem class=\"interactive-canvas-element\"></canvas>\n</div>\n", styles: [".interactive-canvas-wrapper{width:100%;height:100%;position:relative;display:flex;align-items:center;justify-content:center}.interactive-canvas-wrapper .interactive-canvas-element{position:absolute;pointer-events:none}\n"] }]
8014
- }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: UniversalService }, { type: i0.ElementRef }, { type: HTMLElement, decorators: [{
8015
- type: Inject,
8016
- args: [ROOT_ELEMENT]
8017
- }] }], propDecorators: { debug: [{
8018
- type: Input
8019
- }], horizontal: [{
8020
- type: Input
8021
- }], selectedIndex: [{
8254
+ args: [{ standalone: false, selector: "interactive-canvas", template: "<div #containerElem\n [ngClass]=\"['interactive-canvas-container', horizontal ? 'horizontal' : 'vertical']\"\n (resize)=\"resize()\"\n (touchstart)=\"onTouchStart($event)\"\n (mousedown)=\"onMouseDown($event)\"\n (mousemove)=\"onMouseMove($event)\"\n (mouseleave)=\"onMouseLeave()\"\n (panend)=\"onPanEnd()\"\n (panmove)=\"onPanMove($event)\"\n (panstart)=\"onPanStart()\">\n <canvas #canvasElem class=\"interactive-canvas-element\"></canvas>\n</div>\n", styles: [".interactive-canvas-container{width:100%;height:100%;position:relative;display:flex;align-items:center;justify-content:center}.interactive-canvas-container .interactive-canvas-element{position:absolute;pointer-events:none}\n"] }]
8255
+ }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: UniversalService }], propDecorators: { infinite: [{
8022
8256
  type: Input
8023
8257
  }], resizeMode: [{
8024
8258
  type: Input
8259
+ }], params: [{
8260
+ type: Input
8025
8261
  }], realWidth: [{
8026
8262
  type: Input
8027
8263
  }], realHeight: [{
8028
8264
  type: Input
8265
+ }], debug: [{
8266
+ type: Input
8267
+ }], horizontal: [{
8268
+ type: Input
8269
+ }], selectedIndex: [{
8270
+ type: Input
8029
8271
  }], panOffset: [{
8030
8272
  type: Input
8031
- }], params: [{
8273
+ }], renderCtx: [{
8032
8274
  type: Input
8033
8275
  }], beforeItems: [{
8034
8276
  type: Input
@@ -8036,9 +8278,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
8036
8278
  type: Input
8037
8279
  }], selectedIndexChange: [{
8038
8280
  type: Output
8039
- }], itemPan: [{
8281
+ }], onRotate: [{
8282
+ type: Output
8283
+ }], onItemPan: [{
8284
+ type: Output
8285
+ }], onItemPanned: [{
8286
+ type: Output
8287
+ }], onPan: [{
8040
8288
  type: Output
8041
- }], itemPanEnd: [{
8289
+ }], onPanned: [{
8042
8290
  type: Output
8043
8291
  }], containerElem: [{
8044
8292
  type: ViewChild,
@@ -8847,5 +9095,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
8847
9095
  * Generated bundle index. Do not edit.
8848
9096
  */
8849
9097
 
8850
- export { API_SERVICE, APP_BASE_URL, AUTH_SERVICE, AclService, AjaxRequestHandler, ApiService, ArrayUtils, AsyncMethodBase, AsyncMethodDirective, AsyncMethodTargetDirective, AuthGuard, BASE_CONFIG, BUTTON_TYPE, BackgroundDirective, BaseDialogService, BaseHttpClient, BaseHttpService, BaseToasterService, BtnComponent, BtnDefaultComponent, CONFIG_SERVICE, CacheService, CanvasColor, CanvasUtils, ChipsComponent, ChunkPipe, Circle, CloseBtnComponent, ComponentLoaderDirective, ComponentLoaderService, ConfigService, DIALOG_SERVICE, DateUtils, DragDropEventPlugin, DropListComponent, DropdownBoxComponent, DropdownContentDirective, DropdownDirective, DropdownToggleDirective, DynamicTableComponent, DynamicTableTemplateDirective, ERROR_HANDLER, EXPRESS_REQUEST, EntriesPipe, ErrorHandlerService, EventsService, ExtraItemPropertiesPipe, FactoryDependencies, FakeModuleComponent, FileSystemEntry, FileUtils, FilterPipe, FindPipe, ForbiddenZone, FormatNumberPipe, FormatterService, GenericValue, GetOffsetPipe, GetTypePipe, GetValuePipe, GlobalTemplateDirective, GlobalTemplatePipe, GlobalTemplateService, GroupByPipe, ICON_MAP, ICON_SERVICE, ICON_TYPE, IConfiguration, IconComponent, IconDefaultComponent, IconDirective, IconService, IncludesPipe, Initializer, InteractiveCanvasComponent, InteractiveCircleComponent, InteractiveItemComponent, InteractiveRectComponent, IsTypePipe, JSONfn, JoinPipe, KeysPipe, LANGUAGE_SERVICE, LanguageService, LoaderUtils, LocalHttpService, MapPipe, MathUtils, MaxPipe, MinPipe, NgxTemplateOutletDirective, NgxUtilsModule, OPTIONS_TOKEN, ObjectType, ObjectUtils, ObservableUtils, OpenApiService, Oval, PROMISE_SERVICE, PaginationDirective, PaginationItemContext, PaginationItemDirective, PaginationMenuComponent, Point, PopPipe, PromiseService, RESIZE_DELAY, RESIZE_STRATEGY, ROOT_ELEMENT, Rect, ReducePipe, ReflectUtils, RemapPipe, ReplacePipe, ResizeEventPlugin, ResourceIfContext, ResourceIfDirective, ReversePipe, RoundPipe, SCRIPT_PARAMS, STATIC_SCHEMAS, SafeHtmlPipe, ScrollEventPlugin, SetUtils, ShiftPipe, SocketClient, SocketService, SplitPipe, StateService, StaticAuthService, StaticLanguageService, StickyClassDirective, StickyDirective, StorageMode, StorageService, StringUtils, TOASTER_SERVICE, TabsComponent, TabsItemDirective, TabsTemplateDirective, TimerUtils, TranslatePipe, TranslatedUrlSerializer, UniqueUtils, UniversalService, UnorderedListComponent, UnorderedListItemDirective, UnorderedListTemplateDirective, UploadComponent, ValuedPromise, ValuesPipe, cachedFactory, cancelablePromise, checkTransitions, computedPrevious, createTypedProvider, cssStyles, cssVariables, dotProduct, drawOval, drawRect, getComponentDef, getCssVariables, getRoot, hashCode, impatientPromise, isBrowser, isPoint, parseSelector, perpendicular, provideEntryComponents, provideWithOptions, ptAdd, ptDistance, ptLength, ptMultiply, ptSubtract, rotateDeg, rotateRad, selectorMatchesList, switchClass, toDegrees, toRadians };
9098
+ export { API_SERVICE, APP_BASE_URL, AUTH_SERVICE, AclService, AjaxRequestHandler, ApiService, ArrayUtils, AsyncMethodBase, AsyncMethodDirective, AsyncMethodTargetDirective, AuthGuard, BASE_CONFIG, BUTTON_TYPE, BackgroundDirective, BaseDialogService, BaseHttpClient, BaseHttpService, BaseToasterService, BtnComponent, BtnDefaultComponent, CONFIG_SERVICE, CacheService, CanvasColor, CanvasUtils, ChipsComponent, ChunkPipe, Circle, CloseBtnComponent, ComponentLoaderDirective, ComponentLoaderService, ConfigService, DIALOG_SERVICE, DateUtils, DragDropEventPlugin, DropListComponent, DropdownBoxComponent, DropdownContentDirective, DropdownDirective, DropdownToggleDirective, DynamicTableComponent, DynamicTableTemplateDirective, EPSILON, ERROR_HANDLER, EXPRESS_REQUEST, EntriesPipe, ErrorHandlerService, EventsService, ExtraItemPropertiesPipe, FactoryDependencies, FakeModuleComponent, FileSystemEntry, FileUtils, FilterPipe, FindPipe, ForbiddenZone, FormatNumberPipe, FormatterService, GenericValue, GetOffsetPipe, GetTypePipe, GetValuePipe, GlobalTemplateDirective, GlobalTemplatePipe, GlobalTemplateService, GroupByPipe, ICON_MAP, ICON_SERVICE, ICON_TYPE, IConfiguration, IconComponent, IconDefaultComponent, IconDirective, IconService, IncludesPipe, Initializer, InteractiveCanvasComponent, InteractiveCircleComponent, InteractiveItemComponent, InteractiveRectComponent, IsTypePipe, JSONfn, JoinPipe, KeysPipe, LANGUAGE_SERVICE, LanguageService, LoaderUtils, LocalHttpService, MapPipe, MathUtils, MaxPipe, MinPipe, NgxTemplateOutletDirective, NgxUtilsModule, OPTIONS_TOKEN, ObjectType, ObjectUtils, ObservableUtils, OpenApiService, Oval, PROMISE_SERVICE, PaginationDirective, PaginationItemContext, PaginationItemDirective, PaginationMenuComponent, Point, PopPipe, PromiseService, RESIZE_DELAY, RESIZE_STRATEGY, ROOT_ELEMENT, Rect, ReducePipe, ReflectUtils, RemapPipe, ReplacePipe, ResizeEventPlugin, ResourceIfContext, ResourceIfDirective, ReversePipe, RoundPipe, SCRIPT_PARAMS, STATIC_SCHEMAS, SafeHtmlPipe, ScrollEventPlugin, SetUtils, ShiftPipe, SocketClient, SocketService, SplitPipe, StateService, StaticAuthService, StaticLanguageService, StickyClassDirective, StickyDirective, StorageMode, StorageService, StringUtils, TOASTER_SERVICE, TabsComponent, TabsItemDirective, TabsTemplateDirective, TimerUtils, TranslatePipe, TranslatedUrlSerializer, UniqueUtils, UniversalService, UnorderedListComponent, UnorderedListItemDirective, UnorderedListTemplateDirective, UploadComponent, ValuedPromise, ValuesPipe, addPts, cachedFactory, cancelablePromise, checkTransitions, clamp, computedPrevious, createTypedProvider, cssStyles, cssVariables, distance, distanceSq, dividePts, dotProduct, drawOval, drawRect, ensurePoint, getComponentDef, getCssVariables, getRoot, gjkDistance, gjkIntersection, hashCode, impatientPromise, isBrowser, isPoint, lengthOfPt, lerpPts, multiplyPts, negatePt, normalizePt, normalizeRange, overflow, parseSelector, perpendicular, provideEntryComponents, provideWithOptions, rotateDeg, rotateRad, selectorMatchesList, subPts, switchClass, toDegrees, toRadians, tripleProduct };
8851
9099
  //# sourceMappingURL=stemy-ngx-utils.mjs.map