@thi.ng/imago 0.4.1 → 0.5.0

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.
package/units.js CHANGED
@@ -6,70 +6,119 @@ import {
6
6
  const round = Math.round;
7
7
  const ensureSize = (meta) => !(isNumber(meta.width) && isNumber(meta.height)) && illegalArgs("can't determine image size");
8
8
  const coerceColor = (col) => isString(col) ? col : isArrayLike(col) ? { r: col[0], g: col[1], b: col[2], alpha: col[3] ?? 1 } : col;
9
- const positionOrGravity = (pos, gravity, [w, h], [parentW, parentH], unit = "px") => {
9
+ const positionOrGravity = ([w, h], parentSize, {
10
+ pos,
11
+ gravity,
12
+ origin,
13
+ ref,
14
+ unit = "px"
15
+ }) => {
10
16
  if (!pos)
11
17
  return gravity ? { gravity: GRAVITY_MAP[gravity] } : void 0;
12
- const isPC = unit === "%";
18
+ const [parentW, parentH] = parentSize;
13
19
  let { l, r, t, b } = pos;
14
- if (l != null)
15
- l = round(isPC ? l * parentW / 100 : l);
16
- if (r != null)
17
- l = round(parentW - (isPC ? r * parentW / 100 : r) - w);
18
- if (t != null)
19
- t = round(isPC ? t * parentH / 100 : t);
20
- if (b != null)
21
- t = round(parentH - (isPC ? b * parentH / 100 : b) - h);
22
- return { left: l, top: t };
20
+ [l, r, t, b] = computeMargins(
21
+ [l || 0, r || 0, t || 0, b || 0],
22
+ parentSize,
23
+ ref,
24
+ unit
25
+ );
26
+ let left, top;
27
+ const [isE, isW, isN, isS] = origin ? gravityFlags(origin) : [];
28
+ const w2 = w >> 1;
29
+ const h2 = h >> 1;
30
+ if (pos.l != null)
31
+ left = round(l) + (origin ? isW ? 0 : isE ? -w : -w2 : 0);
32
+ if (pos.r != null)
33
+ left = round(parentW - r) + (origin ? isW ? 0 : isE ? -w : -w2 : -w);
34
+ if (pos.t != null)
35
+ top = round(t) + (origin ? isN ? 0 : isS ? -h : -h2 : 0);
36
+ if (pos.b != null)
37
+ top = round(parentH - b) + (origin ? isN ? 0 : isS ? -h : -h2 : -h);
38
+ return { left, top };
23
39
  };
40
+ const gravityFlags = (gravity) => ["e", "w", "n", "s"].map((x) => gravity.includes(x));
24
41
  const gravityPosition = (gravity, [w, h], [parentW, parentH]) => [
25
42
  gravity.includes("w") ? 0 : gravity.includes("e") ? parentW - w : parentW - w >> 1,
26
43
  gravity.includes("n") ? 0 : gravity.includes("s") ? parentH - h : parentH - h >> 1
27
44
  ];
28
45
  const refSize = ([w, h], ref) => {
46
+ let v;
29
47
  switch (ref) {
30
48
  case "w":
31
- return w;
49
+ return [w, w];
32
50
  case "h":
33
- return h;
51
+ return [h, h];
34
52
  case "max":
35
- return Math.max(w, h);
53
+ v = Math.max(w, h);
54
+ return [v, v];
36
55
  case "min":
56
+ v = Math.min(w, h);
57
+ return [v, v];
58
+ case "both":
37
59
  default:
38
- return Math.min(w, h);
60
+ return [w, h];
39
61
  }
40
62
  };
41
- const computeSize = (size, curr, unit = "px") => {
63
+ const computeSize = (size, curr, ref, unit = "px") => {
42
64
  const aspect = curr[0] / curr[1];
43
65
  let res;
44
66
  if (isNumber(size)) {
45
- res = aspect > 1 ? [size, size / aspect] : [size * aspect, size];
67
+ if (unit === "%") {
68
+ res = refSize(curr, ref);
69
+ res = [res[0] * size / 100, res[1] * size / 100];
70
+ } else {
71
+ res = [size, size];
72
+ }
46
73
  } else {
47
- const [w, h] = size;
48
- res = w >= 0 ? h >= 0 ? size : [w, w / aspect] : h > 0 ? [w * aspect, h] : illegalArgs(
74
+ let [w, h] = size;
75
+ if (unit === "%") {
76
+ const [rw, rh] = refSize(curr, ref);
77
+ w *= rw / 100;
78
+ h *= rh / 100;
79
+ size = [w, h];
80
+ }
81
+ res = w >= 0 ? h >= 0 ? size : [w, w / aspect] : h >= 0 ? [h * aspect, h] : illegalArgs(
49
82
  `require at least width or height, but got: ${JSON.stringify(
50
83
  size
51
84
  )}`
52
85
  );
53
86
  }
87
+ res[0] = round(res[0]);
88
+ res[1] = round(res[1]);
89
+ return res;
90
+ };
91
+ const computeSizeWithAspect = (size, [w, h], aspect, unit = "px", clamp = true) => {
92
+ const origAspect = w / h;
93
+ const min = Math.min(w, h);
94
+ const max = Math.max(w, h);
95
+ let res;
54
96
  if (unit === "%") {
55
- res[0] *= curr[0] / 100;
56
- res[1] *= curr[1] / 100;
97
+ size = size / 100 * max;
57
98
  }
99
+ if (clamp) {
100
+ size = Math.min(size, max);
101
+ if (size / aspect > min)
102
+ size = min * aspect;
103
+ }
104
+ res = origAspect > 1 ? [size, size / aspect] : [size / aspect, size];
58
105
  res[0] = round(res[0]);
59
106
  res[1] = round(res[1]);
60
107
  return res;
61
108
  };
62
- const computeMargins = (size, curr, ref = "min", unit = "px") => {
109
+ const computeMargins = (size, curr, ref, unit = "px") => {
63
110
  let res;
64
111
  const refSide = refSize(curr, ref);
65
112
  const isPC = unit === "%";
66
113
  if (isArray(size) && size.length === 4) {
67
- res = isPC ? size.map((x) => round(x * refSide / 100)) : size.map(round);
114
+ res = isPC ? size.map((x, i) => round(x * refSide[i >> 1] / 100)) : size.map(round);
68
115
  } else if (isNumber(size)) {
69
- const w = round(isPC ? refSide * size / 100 : size);
70
- res = [w, w, w, w];
116
+ const w = round(isPC ? refSide[0] * size / 100 : size);
117
+ const h = round(isPC ? refSide[1] * size / 100 : size);
118
+ res = [w, w, h, h];
71
119
  } else {
72
- const [w, h] = computeSize(size, curr, unit);
120
+ const w = round(isPC ? refSide[0] * size[0] / 100 : size[0]);
121
+ const h = round(isPC ? refSide[1] * size[1] / 100 : size[1]);
73
122
  res = [w, w, h, h];
74
123
  }
75
124
  return res;
@@ -78,7 +127,9 @@ export {
78
127
  coerceColor,
79
128
  computeMargins,
80
129
  computeSize,
130
+ computeSizeWithAspect,
81
131
  ensureSize,
132
+ gravityFlags,
82
133
  gravityPosition,
83
134
  positionOrGravity,
84
135
  refSize