center-center 0.0.39 → 0.0.41

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/docs/index.html CHANGED
@@ -15,7 +15,7 @@
15
15
  import debug from 'debug'
16
16
 
17
17
  import {
18
- getRects,
18
+ createDOMRects,
19
19
  calculateLeft,
20
20
  calculateTop
21
21
  } from 'center-center'
@@ -73,7 +73,7 @@
73
73
  log('render')
74
74
 
75
75
  window.requestAnimationFrame(() => {
76
- const rects = getRects(container, target)
76
+ const rects = createDOMRects(container, target)
77
77
  const left = calculateLeft(rects)
78
78
  const top = calculateTop(rects)
79
79
 
package/index.mjs CHANGED
@@ -4,120 +4,69 @@
4
4
  * @typedef {import('.').CenterCenterRects} CenterCenterRects
5
5
  */
6
6
 
7
- const leftMap = new WeakMap()
8
- const topMap = new WeakMap()
9
-
10
7
  /**
11
- * Gets a parent element with `offsetLeft`
8
+ * Gets the document `scrollingElement` (or a valid alternative)
12
9
  *
13
- * @param {SVGElement} element
14
- * @returns {Element}
10
+ * @returns {ScrollingElement}
15
11
  */
16
- export function getParentElementForOffsetLeft (element) {
17
- let parentElement = element.parentElement
18
-
19
- while (!Reflect.has(parentElement, 'offsetLeft')) {
20
- parentElement = parentElement.parentElement
12
+ export function getScrollingElement () {
13
+ if (Reflect.has(document, 'scrollingElement')) {
14
+ const scrollingElement = Reflect.get(document, 'scrollingElement')
15
+ if (scrollingElement) return scrollingElement
21
16
  }
22
17
 
23
- return parentElement
18
+ return {
19
+ scrollLeft: 0,
20
+ scrollTop: 0
21
+ }
24
22
  }
25
23
 
26
24
  /**
27
- * Gets a parent element with `offsetTop`
25
+ * Destructures the `left` field from a `Rect`
28
26
  *
29
- * @param {SVGElement} element
30
- * @returns {Element}
27
+ * @param {CenterCenterRect}
28
+ * @returns {number}
31
29
  */
32
- export function getParentElementForOffsetTop (element) {
33
- let parentElement = element.parentElement
34
-
35
- while (!Reflect.has(parentElement, 'offsetTop')) {
36
- parentElement = parentElement.parentElement
37
- }
38
-
39
- return parentElement
30
+ export function getRectLeft ({ left }) {
31
+ return left
40
32
  }
41
33
 
42
34
  /**
43
- * Gets the `offsetLeft` from the element or calculates the equivalent with
44
- * DOMRect `left` and the nearest `offsetLeft` from a parent
35
+ * Destructures the `top` field from a `Rect`
45
36
  *
46
- * @param {Element | SVGElement} element
37
+ * @param {CenterCenterRect}
47
38
  * @returns {number}
48
39
  */
49
- export function getLeft (element) {
50
- if (Reflect.has(element, 'offsetLeft')) {
51
- return (
52
- Reflect.get(element, 'offsetLeft')
53
- )
54
- }
55
-
56
- if (!leftMap.has(element)) leftMap.set(element, getParentElementForOffsetLeft(element))
57
- const {
58
- offsetLeft = 0
59
- } = leftMap.get(element)
60
-
61
- const {
62
- left
63
- } = element.getBoundingClientRect()
64
-
65
- return (
66
- offsetLeft - left
67
- )
40
+ export function getRectTop ({ top }) {
41
+ return top
68
42
  }
69
43
 
70
44
  /**
71
- * Gets the `offsetTop` from the element or calculates the equivalent with
72
- * DOMRect `top` and the nearest `offsetTop` from a parent
45
+ * Destructures the `width` field from a `Rect`
73
46
  *
74
- * @param {Element | SVGElement} element
47
+ * @param {CenterCenterRect}
75
48
  * @returns {number}
76
49
  */
77
- export function getTop (element) {
78
- if (Reflect.has(element, 'offsetTop')) {
79
- return (
80
- Reflect.get(element, 'offsetTop')
81
- )
82
- }
83
-
84
- const {
85
- top
86
- } = element.getBoundingClientRect()
87
-
88
- if (!topMap.has(element)) topMap.set(element, getParentElementForOffsetTop(element))
89
- const {
90
- offsetTop = 0
91
- } = topMap.get(element)
92
-
93
- return (
94
- offsetTop - top
95
- )
50
+ export function getRectWidth ({ width }) {
51
+ return width
96
52
  }
97
53
 
98
54
  /**
99
- * Gets the document `scrollingElement` (or a valid alternative)
55
+ * Destructures the `height` field from a `Rect`
100
56
  *
101
- * @returns {ScrollingElement}
57
+ * @param {CenterCenterRect}
58
+ * @returns {number}
102
59
  */
103
- export function getScrollingElement () {
104
- if (Reflect.has(document, 'scrollingElement')) {
105
- const scrollingElement = Reflect.get(document, 'scrollingElement')
106
- if (scrollingElement) return scrollingElement
107
- }
108
-
109
- return {
110
- scrollLeft: 0,
111
- scrollTop: 0
112
- }
60
+ export function getRectHeight ({ height }) {
61
+ return height
113
62
  }
114
63
 
115
64
  /**
116
- * Gets a `Rect` for the viewport
65
+ * Creates a `Rect` for the viewport
117
66
  *
118
67
  * @returns {CenterCenterRect}
119
68
  */
120
- export function getViewportRect () {
69
+ export function createViewportRect () {
121
70
  const {
122
71
  innerWidth: width,
123
72
  innerHeight: height
@@ -139,12 +88,12 @@ export function getViewportRect () {
139
88
  }
140
89
 
141
90
  /**
142
- * Gets a `Rect` for an SVG element
91
+ * Creates a `Rect` for an SVG element
143
92
  *
144
- * @param {Element} element
93
+ * @param {SVGElement} element
145
94
  * @returns {CenterCenterRect}
146
95
  */
147
- export function getSVGElementRect (element) {
96
+ export function createSVGElementRect (element) {
148
97
  const {
149
98
  x: left,
150
99
  y: top,
@@ -163,12 +112,12 @@ export function getSVGElementRect (element) {
163
112
  }
164
113
 
165
114
  /**
166
- * Gets a `Rect` for a DOM element
115
+ * Creates a `Rect` for a DOM element
167
116
  *
168
117
  * @param {Element} element
169
118
  * @returns {CenterCenterRect}
170
119
  */
171
- export function getDOMElementRect (element) {
120
+ export function createDOMElementRect (element) {
172
121
  const {
173
122
  scrollLeft,
174
123
  scrollTop
@@ -195,118 +144,253 @@ export function getDOMElementRect (element) {
195
144
  }
196
145
 
197
146
  /**
198
- * Gets a `Rect` for a DOM element
199
- *
200
- * @param {Element} element
201
- * @returns {CenterCenterRect}
202
- */
203
- export function getElementRect (element) {
204
- return (
205
- getDOMElementRect(element)
206
- )
207
- }
208
-
209
- /**
210
- * Gets `Rects` for the viewport as well as the DOM container and DOM target elements
147
+ * Creates `Rects` for the viewport as well as the DOM container and SVG target elements
211
148
  *
212
149
  * @param {Element} container
213
- * @param {Element} target
150
+ * @param {SVGElement} target
214
151
  * @returns {CenterCenterRects}
215
152
  */
216
- export function getSVGRects (container, target) {
153
+ export function createSVGRects (container, target) {
217
154
  return {
218
- viewport: getViewportRect(),
219
- container: getDOMElementRect(container),
220
- target: getSVGElementRect(target)
155
+ viewport: createViewportRect(),
156
+ container: createDOMElementRect(container),
157
+ target: createSVGElementRect(target)
221
158
  }
222
159
  }
223
160
 
224
161
  /**
225
- * Gets `Rects` for the viewport as well as the DOM container and DOM target elements
162
+ * Creates `Rects` for the viewport as well as the DOM container and DOM target elements
226
163
  *
227
164
  * @param {Element} container
228
165
  * @param {Element} target
229
166
  * @returns {CenterCenterRects}
230
167
  */
231
- export function getDOMRects (container, target) {
168
+ export function createDOMRects (container, target) {
232
169
  return {
233
- viewport: getViewportRect(),
234
- container: getDOMElementRect(container),
235
- target: getDOMElementRect(target)
170
+ viewport: createViewportRect(),
171
+ container: createDOMElementRect(container),
172
+ target: createDOMElementRect(target)
236
173
  }
237
174
  }
238
175
 
239
176
  /**
240
- * Gets `Rects` for the viewport as well as the container and target elements
177
+ * Calculates the right-most boundary `x` coordinate of the target in the container
241
178
  *
242
- * @param {Element} container
243
- * @param {Element} target
244
- * @returns {CenterCenterRects}
179
+ * The range for target `x` is from left-most 0 to right-most boundary, inclusive
180
+ *
181
+ * @param {CenterCenterRects} rects
182
+ * @returns {number}
245
183
  */
246
- export function getRects (container, target) {
247
- return (
248
- getDOMRects(container, target)
249
- )
184
+ export function calculateBoundaryX (rects) {
185
+ const containerW = getRectWidth(getContainerRect(rects))
186
+ const targetW = getRectWidth(getTargetRect(rects))
187
+
188
+ return (containerW - targetW)
250
189
  }
251
190
 
252
191
  /**
253
- * Calculates the target `left` position
192
+ * Calculates the bottom-most boundary `y` coordinate of the target in the container
193
+ *
194
+ * The range for target `y` is from top-most 0 to bottom-most boundary, inclusive
195
+ *
196
+ * @param {CenterCenterRects} rects
197
+ * @returns {number}
198
+ */
199
+ export function calculateBoundaryY (rects) {
200
+ const containerH = getRectHeight(getContainerRect(rects))
201
+ const targetH = getRectHeight(getTargetRect(rects))
202
+
203
+ return (containerH - targetH)
204
+ }
205
+
206
+ /**
207
+ * Calculates the `x` coordinate of a `Rect`
254
208
  *
255
- * @param {CenterCenterRects}
209
+ * @param {CenterCenterRect}
256
210
  * @returns {number}
257
211
  */
258
- export function calculateLeft ({
212
+ export function calculateRectX ({ left: l, width: w }) {
213
+ return (l + (w / 2))
214
+ }
215
+
216
+ /**
217
+ * Calculates the `y` coordinate of a `Rect`
218
+ *
219
+ * @param {CenterCenterRect}
220
+ * @returns {number}
221
+ */
222
+ export function calculateRectY ({ top: t, height: h }) {
223
+ return (t + (h / 2))
224
+ }
225
+
226
+ /**
227
+ * Calculates the `x` coordinate of the container
228
+ *
229
+ * @param {CenterCenterRects} rects
230
+ * @returns {number}
231
+ */
232
+ export function calculateContainerX ({
259
233
  viewport: {
260
234
  left: viewportL,
261
235
  right: viewportR
262
236
  },
263
237
  container: {
264
238
  left: containerL,
265
- width: containerW,
266
239
  right: containerR
267
- },
268
- target: {
269
- width: targetW
270
240
  }
271
241
  }) {
272
242
  const l = Math.max(viewportL, containerL)
273
243
  const r = Math.min(viewportR, containerR)
274
244
  const w = (r - l)
275
245
  const x = (l - containerL)
276
- const boundary = (containerW - targetW)
277
246
 
278
- return (
279
- Math.max(0, Math.min(boundary, x + ((w / 2) - (targetW / 2))))
280
- )
247
+ return (x + (w / 2))
281
248
  }
282
249
 
283
250
  /**
284
- * Calculates the target `top` position
251
+ * Calculates the `y` coordinate of the container
285
252
  *
286
- * @param {CenterCenterRects}
253
+ * @param {CenterCenterRects} rects
287
254
  * @returns {number}
288
255
  */
289
- export function calculateTop ({
256
+ export function calculateContainerY ({
290
257
  viewport: {
291
258
  top: viewportT,
292
259
  bottom: viewportB
293
260
  },
294
261
  container: {
295
262
  top: containerT,
296
- height: containerH,
297
263
  bottom: containerB
298
- },
299
- target: {
300
- height: targetH
301
264
  }
302
265
  }) {
303
266
  const t = Math.max(viewportT, containerT)
304
267
  const b = Math.min(viewportB, containerB)
305
268
  const h = (b - t)
306
269
  const y = (t - containerT)
307
- const boundary = (containerH - targetH)
270
+
271
+ return (y + (h / 2))
272
+ }
273
+
274
+ /**
275
+ * Calculates the `x` coordinate of the target
276
+ *
277
+ * @param {CenterCenterRects} rects
278
+ * @returns {number}
279
+ */
280
+ export function calculateTargetX (rects) {
281
+ const x = calculateContainerX(rects)
282
+ const w = getRectWidth(getTargetRect(rects))
283
+
284
+ return (x - (w / 2))
285
+ }
286
+
287
+ /**
288
+ * Calculates the `y` coordinate of the target
289
+ *
290
+ * @param {CenterCenterRects} rects
291
+ * @returns {number}
292
+ */
293
+ export function calculateTargetY (rects) {
294
+ const y = calculateContainerY(rects)
295
+ const h = getRectHeight(getTargetRect(rects))
296
+
297
+ return (y - (h / 2))
298
+ }
299
+
300
+ /**
301
+ * Destructures the viewport `Rect`
302
+ *
303
+ * @param {CenterCenterRects} rects
304
+ * @returns {CenterCenterRect}
305
+ */
306
+ export function getViewportRect ({ viewport }) {
307
+ return viewport
308
+ }
309
+
310
+ /**
311
+ * Destructures the container `Rect`
312
+ *
313
+ * @param {CenterCenterRects} rects
314
+ * @returns {CenterCenterRect}
315
+ */
316
+ export function getContainerRect ({ container }) {
317
+ return container
318
+ }
319
+
320
+ /**
321
+ * Destructures the target `Rect`
322
+ *
323
+ * @param {CenterCenterRects} rects
324
+ * @returns {CenterCenterRect}
325
+ */
326
+ export function getTargetRect ({ target }) {
327
+ return target
328
+ }
329
+
330
+ /**
331
+ * Calculates the target `x` position
332
+ *
333
+ * @param {CenterCenterRects} rects
334
+ * @param {number | undefined} viewBoxW
335
+ * @param {number | undefined} scale
336
+ * @returns {number}
337
+ */
338
+ export function calculateX (rects, viewBoxW = 0, scale = 1) {
339
+ const targetX = calculateRectX(getTargetRect(rects))
340
+ const containerX = calculateContainerX(rects)
341
+ const w = getRectWidth(getContainerRect(rects))
342
+ const ratio = (viewBoxW / w)
343
+
344
+ return (
345
+ targetX - ((containerX * ratio) / scale)
346
+ )
347
+ }
348
+
349
+ /**
350
+ * Calculates the target `y` position
351
+ *
352
+ * @param {CenterCenterRects} rects
353
+ * @param {number | undefined} viewBoxH
354
+ * @param {number | undefined} scale
355
+ * @returns {number}
356
+ */
357
+ export function calculateY (rects, viewBoxH = 0, scale = 1) {
358
+ const targetY = calculateRectY(getTargetRect(rects))
359
+ const containerY = calculateContainerY(rects)
360
+ const h = getRectHeight(getContainerRect(rects))
361
+ const ratio = (viewBoxH / h)
362
+
363
+ return (
364
+ targetY - ((containerY * ratio) / scale)
365
+ )
366
+ }
367
+
368
+ /**
369
+ * Calculates the target `left` position
370
+ *
371
+ * @param {CenterCenterRects} rects
372
+ * @returns {number}
373
+ */
374
+ export function calculateLeft (rects) {
375
+ const boundary = calculateBoundaryX(rects)
376
+ const x = calculateTargetX(rects)
377
+
378
+ return (
379
+ Math.max(0, Math.min(boundary, x))
380
+ )
381
+ }
382
+
383
+ /**
384
+ * Calculates the target `top` position
385
+ *
386
+ * @param {CenterCenterRects} rects
387
+ * @returns {number}
388
+ */
389
+ export function calculateTop (rects) {
390
+ const boundary = calculateBoundaryY(rects)
391
+ const y = calculateTargetY(rects)
308
392
 
309
393
  return (
310
- Math.max(0, Math.min(boundary, y + ((h / 2) - (targetH / 2))))
394
+ Math.max(0, Math.min(boundary, y))
311
395
  )
312
396
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "center-center",
3
- "version": "0.0.39",
3
+ "version": "0.0.41",
4
4
  "description": "Position an element at the center center of a container",
5
5
  "main": "./index.mjs",
6
6
  "type": "module",
@@ -49,7 +49,7 @@
49
49
  "mocha": "^10.3.0",
50
50
  "nodemon": "^3.1.0",
51
51
  "npm-run-all": "^4.1.5",
52
- "typescript": "^5.3.3"
52
+ "typescript": "^5.4.2"
53
53
  },
54
54
  "imports": {
55
55
  "#center-center": "./index.mjs"
@@ -0,0 +1,137 @@
1
+ /**
2
+ * An `<svg />` is of type `Element`
3
+ *
4
+ * Its children are of `SVGElement`
5
+ */
6
+
7
+ import debug from 'debug'
8
+
9
+ const log = debug('center-center:view-box')
10
+
11
+ export const X = 0
12
+ export const Y = 1
13
+ export const W = 2
14
+ export const H = 3
15
+
16
+ /**
17
+ * Transforms a string to a round number
18
+ *
19
+ * @param {string} s
20
+ * @returns {number}
21
+ */
22
+ function toRound (s) {
23
+ return (
24
+ Math.round(Number(s))
25
+ )
26
+ }
27
+
28
+ /**
29
+ * Get the number at position `H` for the SVG element `viewBox` attribute
30
+ *
31
+ * @param {Element} svg
32
+ * @returns {number}
33
+ */
34
+ export function getViewBoxXFor (svg) {
35
+ return (
36
+ getViewBoxX(getViewBox(svg))
37
+ )
38
+ }
39
+
40
+ /**
41
+ * Get the number at position `H` for the SVG element `viewBox` attribute
42
+ *
43
+ * @param {Element} svg
44
+ * @returns {number}
45
+ */
46
+ export function getViewBoxYFor (svg) {
47
+ return (
48
+ getViewBoxY(getViewBox(svg))
49
+ )
50
+ }
51
+
52
+ /**
53
+ * Get the number at position `H` for the SVG element `viewBox` attribute
54
+ *
55
+ * @param {Element} svg
56
+ * @returns {number}
57
+ */
58
+ export function getViewBoxWFor (svg) {
59
+ return (
60
+ getViewBoxW(getViewBox(svg))
61
+ )
62
+ }
63
+
64
+ /**
65
+ * Get the number at position `H` for the SVG element `viewBox` attribute
66
+ *
67
+ * @param {Element} svg
68
+ * @returns {number}
69
+ */
70
+ export function getViewBoxHFor (svg) {
71
+ return (
72
+ getViewBoxH(getViewBox(svg))
73
+ )
74
+ }
75
+
76
+ /**
77
+ * Get the number at position `X`
78
+ *
79
+ * @param {number[]}
80
+ * @returns {number}
81
+ */
82
+ export function getViewBoxX ({
83
+ [X]: x = 0
84
+ }) {
85
+ return x
86
+ }
87
+
88
+ /**
89
+ * Get the number at position `Y`
90
+ *
91
+ * @param {number[]}
92
+ * @returns {number}
93
+ */
94
+ export function getViewBoxY ({ [Y]: y = 0 }) {
95
+ return y
96
+ }
97
+
98
+ /**
99
+ * Get the number at position `W`
100
+ *
101
+ * @param {number[]}
102
+ * @returns {number}
103
+ */
104
+ export function getViewBoxW ({ [W]: w = 0 }) {
105
+ return w
106
+ }
107
+
108
+ /**
109
+ * Get the number at position `H`
110
+ *
111
+ * @param {number[]}
112
+ * @returns {number}
113
+ */
114
+ export function getViewBoxH ({ [H]: h = 0 }) {
115
+ return h
116
+ }
117
+
118
+ /**
119
+ * Get an SVG element `viewBox` attribute as an array of numbers
120
+ *
121
+ * @param {Element} svg
122
+ * @returns {number[]}
123
+ */
124
+ export default function getViewBox (svg) {
125
+ log('getViewBox')
126
+
127
+ const viewBox = (
128
+ svg
129
+ .getAttribute('viewBox')
130
+ .split(String.fromCodePoint(32))
131
+ .map(toRound) // .map(Number).map(Math.round)
132
+ )
133
+
134
+ log(viewBox)
135
+
136
+ return viewBox
137
+ }