aptechka 0.1.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/.prettierignore +16 -0
- package/.prettierrc +9 -0
- package/.vscode/extensions.json +4 -0
- package/.vscode/launch.json +11 -0
- package/.vscode/settings.json +18 -0
- package/README.md +0 -0
- package/index.html +32 -0
- package/package.json +272 -0
- package/public/vite.svg +1 -0
- package/src/packages/animation/Animated.ts +189 -0
- package/src/packages/animation/Damped.ts +39 -0
- package/src/packages/animation/Tweened.ts +51 -0
- package/src/packages/animation/index.ts +10 -0
- package/src/packages/attribute/index.ts +59 -0
- package/src/packages/canvas-2d/index.ts +137 -0
- package/src/packages/controls/Controls.ts +15 -0
- package/src/packages/controls/KeyboardControls.ts +63 -0
- package/src/packages/controls/LinearControls.ts +27 -0
- package/src/packages/controls/User.ts +20 -0
- package/src/packages/controls/WheelControls.ts +92 -0
- package/src/packages/controls/index.ts +5 -0
- package/src/packages/css-unit-parser/index.ts +32 -0
- package/src/packages/custom-element/index.ts +19 -0
- package/src/packages/device/Device.ts +113 -0
- package/src/packages/device/Viewport.ts +67 -0
- package/src/packages/device/index.ts +2 -0
- package/src/packages/element-constructor/ElementConstructor.ts +577 -0
- package/src/packages/element-constructor/htmlTags.ts +679 -0
- package/src/packages/element-constructor/index.ts +4 -0
- package/src/packages/element-constructor/specialObjects.ts +8 -0
- package/src/packages/element-constructor/svgTags.ts +588 -0
- package/src/packages/en3/attachments/En3SourceManager.ts +116 -0
- package/src/packages/en3/core/en3.ts +306 -0
- package/src/packages/en3/index.ts +52 -0
- package/src/packages/en3/instances/en3LazyLoader.ts +22 -0
- package/src/packages/en3/libs/MeshoptDecoder.js +138 -0
- package/src/packages/en3/loaders/en3GLTFLoader.ts +54 -0
- package/src/packages/en3/loaders/en3TextureLoader.ts +3 -0
- package/src/packages/en3/objects/En3Clip.ts +53 -0
- package/src/packages/en3/objects/En3ClipHelpers.ts +12 -0
- package/src/packages/en3/objects/En3GLTF.ts +35 -0
- package/src/packages/en3/objects/En3Image.ts +18 -0
- package/src/packages/en3/objects/En3ImageLike.ts +101 -0
- package/src/packages/en3/objects/En3SourceConsumer.ts +5 -0
- package/src/packages/en3/objects/En3Video.ts +88 -0
- package/src/packages/en3/test/En3HTML.ts +55 -0
- package/src/packages/en3/test/En3ModifiedMaterial.ts +221 -0
- package/src/packages/en3/test/En3Raycaster.ts +187 -0
- package/src/packages/en3/utils/coverTexture.ts +29 -0
- package/src/packages/en3/utils/dispose.ts +27 -0
- package/src/packages/en3/utils/traverseMaterials.ts +10 -0
- package/src/packages/en3/utils/traverseMeshes.ts +9 -0
- package/src/packages/image/index.ts +19 -0
- package/src/packages/intersector/index.ts +83 -0
- package/src/packages/ladder/index.ts +112 -0
- package/src/packages/layout-box/index.ts +417 -0
- package/src/packages/loading/index.ts +131 -0
- package/src/packages/measurer/CumulativeOffsetLeft.ts +8 -0
- package/src/packages/measurer/CumulativeOffsetTop.ts +8 -0
- package/src/packages/measurer/Meaurer.ts +38 -0
- package/src/packages/measurer/index.ts +3 -0
- package/src/packages/media/index.ts +38 -0
- package/src/packages/morph/Link.ts +32 -0
- package/src/packages/morph/Morph.ts +246 -0
- package/src/packages/morph/index.ts +10 -0
- package/src/packages/notifier/index.ts +41 -0
- package/src/packages/order/index.ts +14 -0
- package/src/packages/resizer/index.ts +55 -0
- package/src/packages/router/Link.ts +33 -0
- package/src/packages/router/Route.ts +152 -0
- package/src/packages/router/RouteElement.ts +34 -0
- package/src/packages/router/Router.ts +190 -0
- package/src/packages/router/index.ts +13 -0
- package/src/packages/scroll/ScrollElement.ts +618 -0
- package/src/packages/scroll/ScrollUserElement.ts +21 -0
- package/src/packages/scroll/ScrollbarElement.ts +170 -0
- package/src/packages/scroll/index.ts +2 -0
- package/src/packages/scroll-entries/index.ts +74 -0
- package/src/packages/source/SourceClass.ts +77 -0
- package/src/packages/source/SourceElement.ts +177 -0
- package/src/packages/source/SourceManager.ts +61 -0
- package/src/packages/source/SourceSet.ts +52 -0
- package/src/packages/source/index.ts +8 -0
- package/src/packages/store/Composed.ts +33 -0
- package/src/packages/store/Derived.ts +24 -0
- package/src/packages/store/DerivedArray.ts +36 -0
- package/src/packages/store/Resource.ts +38 -0
- package/src/packages/store/Store.ts +144 -0
- package/src/packages/store/StoreRegistry.ts +105 -0
- package/src/packages/store/index.ts +23 -0
- package/src/packages/ticker/index.ts +173 -0
- package/src/packages/utils/array.ts +3 -0
- package/src/packages/utils/attributes.ts +19 -0
- package/src/packages/utils/browser.ts +2 -0
- package/src/packages/utils/canvas.ts +46 -0
- package/src/packages/utils/collisions.ts +12 -0
- package/src/packages/utils/coordinates.ts +40 -0
- package/src/packages/utils/decoding.ts +11 -0
- package/src/packages/utils/dev.ts +5 -0
- package/src/packages/utils/dom.ts +48 -0
- package/src/packages/utils/easings.ts +69 -0
- package/src/packages/utils/file.ts +17 -0
- package/src/packages/utils/function.ts +29 -0
- package/src/packages/utils/index.ts +61 -0
- package/src/packages/utils/layout.ts +22 -0
- package/src/packages/utils/math.ts +74 -0
- package/src/packages/utils/number.ts +26 -0
- package/src/packages/utils/object.ts +108 -0
- package/src/packages/utils/string.ts +49 -0
- package/src/packages/utils/ts-shape.ts +25 -0
- package/src/packages/utils/ts-utility.ts +47 -0
- package/src/packages/video/index.ts +39 -0
- package/src/playground/index.ts +0 -0
- package/tsconfig.json +31 -0
- package/vite.config.ts +65 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Store, StoreOptions } from '$packages/store'
|
|
2
|
+
import { ElementOrSelector, isBrowser, getElement, parseAttributeValue } from '$packages/utils'
|
|
3
|
+
|
|
4
|
+
export class Attribute<T extends string | number | boolean> extends Store<T> {
|
|
5
|
+
#element: HTMLElement | null = null
|
|
6
|
+
#name: string
|
|
7
|
+
#mutationObserver: MutationObserver = null!
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
elementOrSelector: ElementOrSelector,
|
|
11
|
+
name: string,
|
|
12
|
+
defaultValue: T,
|
|
13
|
+
options?: StoreOptions<T>
|
|
14
|
+
) {
|
|
15
|
+
super(defaultValue, options)
|
|
16
|
+
|
|
17
|
+
this.#name = name
|
|
18
|
+
|
|
19
|
+
this.subscribe((e) => {
|
|
20
|
+
this.#element?.setAttribute(this.#name, e.current.toString())
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
if (isBrowser) {
|
|
24
|
+
this.#element = getElement(elementOrSelector)!
|
|
25
|
+
|
|
26
|
+
this.#mutationObserver = new MutationObserver((mutations) => {
|
|
27
|
+
mutations.forEach((mutation) => {
|
|
28
|
+
if (mutation.type === 'attributes' && mutation.attributeName === this.#name) {
|
|
29
|
+
this.#tryUpdate()
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public unobserve() {
|
|
37
|
+
if (isBrowser) {
|
|
38
|
+
this.#mutationObserver.disconnect()
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public observe() {
|
|
43
|
+
if (isBrowser && this.#element) {
|
|
44
|
+
this.#mutationObserver.observe(this.#element, {
|
|
45
|
+
attributes: true,
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
this.#tryUpdate()
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
#tryUpdate() {
|
|
53
|
+
const value = this.#element!.getAttribute(this.#name)
|
|
54
|
+
|
|
55
|
+
if (value != undefined) {
|
|
56
|
+
this.current = parseAttributeValue(value) as T
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { define, CustomElement } from '$packages/custom-element'
|
|
2
|
+
import { Notifier } from '$packages/notifier'
|
|
3
|
+
import { resizer } from '$packages/resizer'
|
|
4
|
+
import { ticker, TickerCallback } from '$packages/ticker'
|
|
5
|
+
import { clamp } from '$packages/utils'
|
|
6
|
+
|
|
7
|
+
export interface Canvas2DRenderDetail {
|
|
8
|
+
pixelRatio: number
|
|
9
|
+
width: number
|
|
10
|
+
height: number
|
|
11
|
+
element: HTMLElement
|
|
12
|
+
canvasElement: HTMLElement
|
|
13
|
+
context: CanvasRenderingContext2D
|
|
14
|
+
timestamp: number
|
|
15
|
+
elapsed: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type Canvas2DRenderCallback = (detail: Canvas2DRenderDetail) => void
|
|
19
|
+
|
|
20
|
+
@define('canvas-2d')
|
|
21
|
+
export class Canvas2DElement extends CustomElement {
|
|
22
|
+
#renderEvent = new Notifier<Canvas2DRenderCallback>()
|
|
23
|
+
|
|
24
|
+
#canvasElement: HTMLCanvasElement = null!
|
|
25
|
+
#context: CanvasRenderingContext2D = null!
|
|
26
|
+
|
|
27
|
+
#width = 0
|
|
28
|
+
#height = 0
|
|
29
|
+
#pixelRatio = 1
|
|
30
|
+
|
|
31
|
+
#timestamp = 0
|
|
32
|
+
#elapsed = 1
|
|
33
|
+
|
|
34
|
+
public get renderEvent() {
|
|
35
|
+
return this.#renderEvent
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public get canvasElement() {
|
|
39
|
+
return this.#canvasElement
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public get context() {
|
|
43
|
+
return this.#context
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public get pixelRatio() {
|
|
47
|
+
return this.#pixelRatio
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public get width() {
|
|
51
|
+
return this.#width
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public get height() {
|
|
55
|
+
return this.#height
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public get detail(): Canvas2DRenderDetail {
|
|
59
|
+
return {
|
|
60
|
+
width: this.#width,
|
|
61
|
+
height: this.#height,
|
|
62
|
+
element: this,
|
|
63
|
+
canvasElement: this.#canvasElement,
|
|
64
|
+
pixelRatio: this.#pixelRatio,
|
|
65
|
+
context: this.#context,
|
|
66
|
+
timestamp: this.#timestamp,
|
|
67
|
+
elapsed: this.#elapsed,
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
protected connectedCallback() {
|
|
72
|
+
this.style.display = 'block'
|
|
73
|
+
this.style.width = '100%'
|
|
74
|
+
this.style.height = '100%'
|
|
75
|
+
|
|
76
|
+
this.#canvasElement = document.createElement('canvas')
|
|
77
|
+
|
|
78
|
+
this.#canvasElement.style.cssText = `
|
|
79
|
+
display: block;
|
|
80
|
+
width: 100%;
|
|
81
|
+
height: 100%;
|
|
82
|
+
`
|
|
83
|
+
|
|
84
|
+
this.#context = this.#canvasElement.getContext('2d')!
|
|
85
|
+
|
|
86
|
+
this.appendChild(this.#canvasElement)
|
|
87
|
+
|
|
88
|
+
resizer.subscribe(this.#resizeListener)
|
|
89
|
+
|
|
90
|
+
if (!this.hasAttribute('static')) {
|
|
91
|
+
ticker.subscribe(this.#tickListener, {
|
|
92
|
+
culling: this,
|
|
93
|
+
maxFPS: this.hasAttribute('fps') ? parseInt(this.getAttribute('fps')!) : undefined,
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
protected disconnectedCallback() {
|
|
99
|
+
resizer.unsubscribe(this.#resizeListener)
|
|
100
|
+
ticker.unsubscribe(this.#tickListener)
|
|
101
|
+
|
|
102
|
+
this.#renderEvent.close()
|
|
103
|
+
this.#canvasElement.remove()
|
|
104
|
+
this.style.display = ''
|
|
105
|
+
this.style.width = ''
|
|
106
|
+
this.style.height = ''
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
#resizeListener = () => {
|
|
110
|
+
this.#pixelRatio = clamp(devicePixelRatio, 1, 2)
|
|
111
|
+
|
|
112
|
+
const rect = this.getBoundingClientRect()
|
|
113
|
+
|
|
114
|
+
this.#width = rect.width
|
|
115
|
+
this.#height = rect.height
|
|
116
|
+
|
|
117
|
+
this.#canvasElement.width = this.#width * this.pixelRatio
|
|
118
|
+
this.#canvasElement.height = this.#height * this.pixelRatio
|
|
119
|
+
|
|
120
|
+
this.context.scale(this.pixelRatio, this.pixelRatio)
|
|
121
|
+
|
|
122
|
+
this.renderEvent.notify(this.detail)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
#tickListener: TickerCallback = (e) => {
|
|
126
|
+
this.#timestamp = e.timestamp
|
|
127
|
+
this.#elapsed = e.elapsed
|
|
128
|
+
|
|
129
|
+
this.#renderEvent.notify(this.detail)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
declare global {
|
|
134
|
+
interface HTMLElementTagNameMap {
|
|
135
|
+
'canvas-2d': Canvas2DElement
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Notifier } from '$packages/notifier'
|
|
2
|
+
|
|
3
|
+
export type ControlsValue = number | 'max' | 'min'
|
|
4
|
+
export type ControlsCallback = (value: ControlsValue) => void
|
|
5
|
+
|
|
6
|
+
export abstract class Controls {
|
|
7
|
+
#changeEvent = new Notifier<ControlsCallback>()
|
|
8
|
+
|
|
9
|
+
public get changeEvent() {
|
|
10
|
+
return this.#changeEvent
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public abstract connect(): void
|
|
14
|
+
public abstract disconnect(): void
|
|
15
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { isBrowser, getElement } from '$packages/utils'
|
|
2
|
+
import { Controls } from './Controls'
|
|
3
|
+
import { user } from './User'
|
|
4
|
+
|
|
5
|
+
export interface KeyboardControlsOptions {
|
|
6
|
+
element?: HTMLElement
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class KeyboardControls extends Controls {
|
|
10
|
+
#element: HTMLElement | Window = null!
|
|
11
|
+
|
|
12
|
+
constructor(options?: KeyboardControlsOptions) {
|
|
13
|
+
super()
|
|
14
|
+
|
|
15
|
+
if (isBrowser) {
|
|
16
|
+
this.#element = options?.element ? getElement(options.element) || window : window
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public connect() {
|
|
21
|
+
if (isBrowser) {
|
|
22
|
+
this.#element.addEventListener('keydown', this.#keydownListener as EventListener)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public disconnect() {
|
|
27
|
+
if (isBrowser) {
|
|
28
|
+
this.#element.removeEventListener('keydown', this.#keydownListener as EventListener)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#keydownListener = (e: KeyboardEvent) => {
|
|
33
|
+
const dir = e.shiftKey ? -1 : 1
|
|
34
|
+
|
|
35
|
+
let interaction = true
|
|
36
|
+
|
|
37
|
+
if (e.code === 'Space') {
|
|
38
|
+
this.changeEvent.notify(dir * 500)
|
|
39
|
+
} else if (e.code === 'ArrowLeft') {
|
|
40
|
+
this.changeEvent.notify(-1 * 100)
|
|
41
|
+
} else if (e.code === 'ArrowRight') {
|
|
42
|
+
this.changeEvent.notify(1 * 100)
|
|
43
|
+
} else if (e.code === 'ArrowUp') {
|
|
44
|
+
this.changeEvent.notify(-1 * 100)
|
|
45
|
+
} else if (e.code === 'ArrowDown') {
|
|
46
|
+
this.changeEvent.notify(1 * 100)
|
|
47
|
+
} else if (e.code === 'PageUp') {
|
|
48
|
+
this.changeEvent.notify(-1 * 1000)
|
|
49
|
+
} else if (e.code === 'PageDown') {
|
|
50
|
+
this.changeEvent.notify(1 * 1000)
|
|
51
|
+
} else if (e.code === 'Home') {
|
|
52
|
+
this.changeEvent.notify('min')
|
|
53
|
+
} else if (e.code === 'End') {
|
|
54
|
+
this.changeEvent.notify('max')
|
|
55
|
+
} else {
|
|
56
|
+
interaction = false
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (interaction) {
|
|
60
|
+
user.registerInteraction()
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ticker, TickerCallback } from '$packages/ticker'
|
|
2
|
+
import { Controls } from './Controls'
|
|
3
|
+
|
|
4
|
+
export interface LinearControlsOptions {
|
|
5
|
+
speed?: number
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class LinearControls extends Controls {
|
|
9
|
+
speed: number
|
|
10
|
+
|
|
11
|
+
constructor(options?: LinearControlsOptions) {
|
|
12
|
+
super()
|
|
13
|
+
this.speed = options?.speed || 1
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public connect() {
|
|
17
|
+
ticker.subscribe(this.#animationFrameCallback)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public disconnect() {
|
|
21
|
+
ticker.unsubscribe(this.#animationFrameCallback)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
#animationFrameCallback: TickerCallback = (e) => {
|
|
25
|
+
this.changeEvent.notify(e.elapsed * this.speed)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
class User {
|
|
2
|
+
#idleTimeoutId: ReturnType<typeof setTimeout> | undefined
|
|
3
|
+
#isIdle = true
|
|
4
|
+
|
|
5
|
+
public get isIdle() {
|
|
6
|
+
return this.#isIdle
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
public registerInteraction() {
|
|
10
|
+
clearTimeout(this.#idleTimeoutId)
|
|
11
|
+
|
|
12
|
+
this.#isIdle = false
|
|
13
|
+
|
|
14
|
+
this.#idleTimeoutId = setTimeout(() => {
|
|
15
|
+
this.#isIdle = true
|
|
16
|
+
}, 2000)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const user = new User()
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Axes2D, isBrowser, getElement } from '$packages/utils'
|
|
2
|
+
import { Controls } from './Controls'
|
|
3
|
+
import { user } from './User'
|
|
4
|
+
|
|
5
|
+
export interface WheelControlsOptions {
|
|
6
|
+
axis?: Axes2D
|
|
7
|
+
speed?: number
|
|
8
|
+
debounce?: boolean
|
|
9
|
+
element?: HTMLElement
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class WheelControls extends Controls {
|
|
13
|
+
axis: Axes2D
|
|
14
|
+
speed: number
|
|
15
|
+
debounce: boolean
|
|
16
|
+
|
|
17
|
+
#element: HTMLElement | Window = null!
|
|
18
|
+
|
|
19
|
+
#timeout: ReturnType<typeof setTimeout> | undefined
|
|
20
|
+
#prevEventDate: number
|
|
21
|
+
|
|
22
|
+
constructor(options?: WheelControlsOptions) {
|
|
23
|
+
super()
|
|
24
|
+
|
|
25
|
+
this.axis = options?.axis || 'y'
|
|
26
|
+
this.speed = options?.speed || 1
|
|
27
|
+
this.debounce = options?.debounce || false
|
|
28
|
+
|
|
29
|
+
this.#prevEventDate = Date.now()
|
|
30
|
+
|
|
31
|
+
if (isBrowser) {
|
|
32
|
+
this.#element = options?.element ? getElement(options.element) || window : window
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public connect() {
|
|
37
|
+
if (isBrowser) {
|
|
38
|
+
this.#element.addEventListener('wheel', this.#wheelListener as EventListener, {
|
|
39
|
+
passive: false,
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public disconnect() {
|
|
45
|
+
if (isBrowser) {
|
|
46
|
+
this.#element.removeEventListener('wheel', this.#wheelListener as EventListener)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#wheelListener = (event: WheelEvent) => {
|
|
51
|
+
let delta = 0
|
|
52
|
+
|
|
53
|
+
if (
|
|
54
|
+
(this.axis === 'x' && Math.abs(event.deltaY) > Math.abs(event.deltaX)) ||
|
|
55
|
+
(this.axis === 'y' && Math.abs(event.deltaX) > Math.abs(event.deltaY))
|
|
56
|
+
) {
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
delta = (this.axis === 'x' ? event.deltaX : event.deltaY) * this.speed
|
|
61
|
+
|
|
62
|
+
user.registerInteraction()
|
|
63
|
+
event.stopPropagation()
|
|
64
|
+
event.preventDefault()
|
|
65
|
+
|
|
66
|
+
if (this.debounce) {
|
|
67
|
+
const now = Date.now()
|
|
68
|
+
|
|
69
|
+
if (now - this.#prevEventDate > 40) {
|
|
70
|
+
delta = 100 * Math.sign(delta)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
this.#prevEventDate = now
|
|
74
|
+
|
|
75
|
+
if (Math.abs(delta) < 100) {
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (this.#timeout) {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this.changeEvent.notify(delta)
|
|
84
|
+
|
|
85
|
+
this.#timeout = setTimeout(() => {
|
|
86
|
+
this.#timeout = undefined
|
|
87
|
+
}, 80)
|
|
88
|
+
} else {
|
|
89
|
+
this.changeEvent.notify(delta)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { Controls, type ControlsValue } from './Controls'
|
|
2
|
+
export { KeyboardControls } from './KeyboardControls'
|
|
3
|
+
export { LinearControls, type LinearControlsOptions } from './LinearControls'
|
|
4
|
+
export { WheelControls, type WheelControlsOptions } from './WheelControls'
|
|
5
|
+
export { user } from './User'
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
class CSSUnitParser {
|
|
2
|
+
#dummyElement: HTMLElement = null!
|
|
3
|
+
|
|
4
|
+
public parse(value: string) {
|
|
5
|
+
this.#createDummy()
|
|
6
|
+
|
|
7
|
+
this.#dummyElement.style.left = value
|
|
8
|
+
const computedWidth = getComputedStyle(this.#dummyElement).getPropertyValue('left')
|
|
9
|
+
|
|
10
|
+
return parseFloat(computedWidth)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
#createDummy() {
|
|
14
|
+
if (!this.#dummyElement) {
|
|
15
|
+
this.#dummyElement = document.createElement('div')
|
|
16
|
+
this.#dummyElement.style.cssText = `
|
|
17
|
+
position: fixed;
|
|
18
|
+
top: 0;
|
|
19
|
+
left: 0;
|
|
20
|
+
width: 0;
|
|
21
|
+
height: 0;
|
|
22
|
+
visibility: hidden;
|
|
23
|
+
`
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!document.body.contains(this.#dummyElement)) {
|
|
27
|
+
document.body.prepend(this.#dummyElement)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const cssUnitParser = new CSSUnitParser()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { isBrowser } from '$packages/utils'
|
|
2
|
+
|
|
3
|
+
export function define(name: string) {
|
|
4
|
+
return function (Constructor: CustomElementConstructor) {
|
|
5
|
+
if (isBrowser && !customElements.get(name)) {
|
|
6
|
+
customElements.define(name, Constructor)
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const HTMLElement = (
|
|
12
|
+
isBrowser
|
|
13
|
+
? window.HTMLElement
|
|
14
|
+
: class {
|
|
15
|
+
attachShadow(..._: any): any {}
|
|
16
|
+
}
|
|
17
|
+
) as typeof window.HTMLElement
|
|
18
|
+
|
|
19
|
+
export class CustomElement extends HTMLElement {}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { RESIZE_ORDER } from '$packages/order'
|
|
2
|
+
import { resizer } from '$packages/resizer'
|
|
3
|
+
import { isBrowser } from '$packages/utils'
|
|
4
|
+
import { TierResult, getGPUTier } from 'detect-gpu'
|
|
5
|
+
|
|
6
|
+
export type DeviceOS = 'macOS' | 'iOS' | 'Windows' | 'Android' | 'Linux' | 'unknown'
|
|
7
|
+
|
|
8
|
+
class Device {
|
|
9
|
+
#OS = 'unknown'
|
|
10
|
+
#gpu = 'unknown'
|
|
11
|
+
#gpuTier = 0
|
|
12
|
+
#gpuDetection: Promise<TierResult> = null!
|
|
13
|
+
#isMobile = false
|
|
14
|
+
#isTouch = false
|
|
15
|
+
#isWebgl = false
|
|
16
|
+
#isWebp = false
|
|
17
|
+
#isApple = false
|
|
18
|
+
|
|
19
|
+
constructor() {
|
|
20
|
+
if (isBrowser) {
|
|
21
|
+
this.#gpuDetection = getGPUTier()
|
|
22
|
+
|
|
23
|
+
this.#gpuDetection.then((v) => {
|
|
24
|
+
this.#gpu = v.gpu || 'unknown'
|
|
25
|
+
this.#gpuTier = v.tier
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
resizer.subscribe(() => {
|
|
29
|
+
this.#isMobile = /Mobi|Android/i.test(navigator.userAgent)
|
|
30
|
+
|
|
31
|
+
this.#isTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0
|
|
32
|
+
|
|
33
|
+
setTimeout(() => {
|
|
34
|
+
this.#isTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0
|
|
35
|
+
}, 0)
|
|
36
|
+
}, RESIZE_ORDER.DEVICE)
|
|
37
|
+
|
|
38
|
+
{
|
|
39
|
+
const canvas = document.createElement('canvas')
|
|
40
|
+
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl')
|
|
41
|
+
this.#isWebgl = (gl && gl instanceof WebGLRenderingContext) || false
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
{
|
|
45
|
+
const canvas = document.createElement('canvas')
|
|
46
|
+
if (canvas.getContext('2d')) {
|
|
47
|
+
this.#isWebp = canvas.toDataURL('image/webp').indexOf('data:image/webp') == 0
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const userAgent = window.navigator.userAgent
|
|
52
|
+
const platform =
|
|
53
|
+
(window.navigator as any)?.userAgentData?.platform || window.navigator.platform
|
|
54
|
+
const macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K', 'macOS']
|
|
55
|
+
const windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE']
|
|
56
|
+
const iosPlatforms = ['iPhone', 'iPad', 'iPod']
|
|
57
|
+
|
|
58
|
+
if (macosPlatforms.includes(platform)) {
|
|
59
|
+
this.#OS = 'macOS'
|
|
60
|
+
this.#isApple = true
|
|
61
|
+
} else if (iosPlatforms.includes(platform)) {
|
|
62
|
+
this.#OS = 'iOS'
|
|
63
|
+
this.#isApple = true
|
|
64
|
+
} else if (windowsPlatforms.includes(platform)) {
|
|
65
|
+
this.#OS = 'Windows'
|
|
66
|
+
} else if (/Android/.test(userAgent)) {
|
|
67
|
+
this.#OS = 'Android'
|
|
68
|
+
} else if (/Linux/.test(platform)) {
|
|
69
|
+
this.#OS = 'Linux'
|
|
70
|
+
} else {
|
|
71
|
+
this.#OS = 'unknown'
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public get OS() {
|
|
77
|
+
return this.#OS
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public get gpu() {
|
|
81
|
+
return this.#gpu
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public get gpuTier() {
|
|
85
|
+
return this.#gpuTier
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public get gpuDetection() {
|
|
89
|
+
return this.#gpuDetection
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public get isMobile() {
|
|
93
|
+
return this.#isMobile
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public get isTouch() {
|
|
97
|
+
return this.#isTouch
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public get isWebgl() {
|
|
101
|
+
return this.#isWebgl
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public get isWebp() {
|
|
105
|
+
return this.#isWebp
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public get isApple() {
|
|
109
|
+
return this.#isApple
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export const device = new Device()
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { RESIZE_ORDER } from '$packages/order'
|
|
2
|
+
import { resizer } from '$packages/resizer'
|
|
3
|
+
import { Store } from '$packages/store'
|
|
4
|
+
import { isBrowser } from '$packages/utils'
|
|
5
|
+
|
|
6
|
+
export enum ViewportBreakpoints {
|
|
7
|
+
'mobile' = '600px',
|
|
8
|
+
'tablet' = '1024px',
|
|
9
|
+
'notebook' = '1280px',
|
|
10
|
+
'desktop' = '1281px',
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export enum ViewportMediaRules {
|
|
14
|
+
'<=mobile' = '(max-width: 600px)',
|
|
15
|
+
'>=mobile' = '(min-width: 601px)',
|
|
16
|
+
'<=tablet' = '(max-width: 1024px)',
|
|
17
|
+
'>=tablet' = '(min-width: 1025px)',
|
|
18
|
+
'<=notebook' = '(max-width: 1280px)',
|
|
19
|
+
'>=notebook' = '(min-width: 1281px)',
|
|
20
|
+
'<=desktop' = '(max-width: 1280px)',
|
|
21
|
+
'>=desktop' = '(min-width: 1281px)',
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class Viewport {
|
|
25
|
+
#width = 0
|
|
26
|
+
#height = 0
|
|
27
|
+
#pixelRatio = 0
|
|
28
|
+
#store_type = new Store<keyof typeof ViewportBreakpoints | undefined>(undefined)
|
|
29
|
+
|
|
30
|
+
constructor() {
|
|
31
|
+
if (isBrowser) {
|
|
32
|
+
resizer.subscribe(() => {
|
|
33
|
+
this.#width = document.documentElement.clientWidth
|
|
34
|
+
this.#height = innerHeight
|
|
35
|
+
this.#pixelRatio = devicePixelRatio
|
|
36
|
+
|
|
37
|
+
if (matchMedia(ViewportMediaRules['<=mobile']).matches) {
|
|
38
|
+
this.#store_type.current = 'mobile'
|
|
39
|
+
} else if (matchMedia(ViewportMediaRules['<=tablet']).matches) {
|
|
40
|
+
this.#store_type.current = 'tablet'
|
|
41
|
+
} else if (matchMedia(ViewportMediaRules['<=notebook']).matches) {
|
|
42
|
+
this.#store_type.current = 'notebook'
|
|
43
|
+
} else if (matchMedia(ViewportMediaRules['>=desktop']).matches) {
|
|
44
|
+
this.#store_type.current = 'desktop'
|
|
45
|
+
}
|
|
46
|
+
}, RESIZE_ORDER.DEVICE)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public get width() {
|
|
51
|
+
return this.#width
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public get height() {
|
|
55
|
+
return this.#height
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public get store_type() {
|
|
59
|
+
return this.#store_type
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public get pixelRatio() {
|
|
63
|
+
return this.#pixelRatio
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const viewport = new Viewport()
|