@crispcode/shimmer 5.0.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.
@@ -0,0 +1,95 @@
1
+ 'use strict'
2
+
3
+ export class Controls {
4
+ /**
5
+ * The pixi application renderer
6
+ * @param {Renderer} renderer
7
+ */
8
+ constructor ( renderer ) {
9
+ this.__renderer = renderer
10
+ this.__listeners = []
11
+ }
12
+
13
+ /**
14
+ * Returns the custom event names
15
+ * @param {String} name The base event name
16
+ * @returns {String}
17
+ */
18
+ __getEventName ( name ) {
19
+ return name // 'shimmer' + name.charAt( 0 ).toUpperCase() + name.slice( 1 )
20
+ }
21
+
22
+ /**
23
+ * Returns the pixi element at position { x,y }
24
+ * @param {Integer} x The x coordonate on the renderer
25
+ * @param {Integer} y The y coordonate on the renderer
26
+ * @returns {DisplayObject}
27
+ */
28
+ __getTarget ( x, y ) {
29
+ let target = this.__renderer.plugins.interaction.hitTest( { x: x, y: y } )
30
+ if ( target && target.interactive ) {
31
+ return target
32
+ }
33
+ return null
34
+ }
35
+
36
+ /**
37
+ * Enables mouse wheel event on elements
38
+ */
39
+ enableWheel () {
40
+ let onPush = ( e ) => {
41
+ let target = this.__getTarget( e.offsetX, e.offsetY )
42
+ if ( target && target.interactive ) {
43
+ target.emit( this.__getEventName( 'wheel' ), e )
44
+ }
45
+ }
46
+
47
+ this.__renderer.view.addEventListener( 'wheel', onPush, { passive: false } )
48
+ this.__listeners.push( () => {
49
+ this.__renderer.view.removeEventListener( 'wheel', onPush, { passive: false } )
50
+ } )
51
+ }
52
+
53
+ /**
54
+ * Enables long taps ( long clicks ) event on elements
55
+ */
56
+ enableLongtap () {
57
+ let onPush = ( e ) => {
58
+ let target = this.__getTarget( e.offsetX, e.offsetY )
59
+ let timeout = null
60
+ if ( target && target.interactive ) {
61
+ timeout = setTimeout( () => {
62
+ target.emit( this.__getEventName( 'longtap' ), e )
63
+ }, 700 )
64
+ }
65
+
66
+ let onRelease = () => {
67
+ clearTimeout( timeout )
68
+ }
69
+
70
+ this.__renderer.view.addEventListener( 'touchend', onRelease, { once: true } )
71
+ this.__renderer.view.addEventListener( 'mouseup', onRelease, { once: true } )
72
+ }
73
+
74
+ this.__renderer.view.addEventListener( 'touchstart', onPush, { passive: false } )
75
+ this.__listeners.push( () => {
76
+ this.__renderer.view.removeEventListener( 'touchstart', onPush )
77
+ } )
78
+
79
+ this.__renderer.view.addEventListener( 'mousedown', onPush, { passive: false } )
80
+ this.__listeners.push( () => {
81
+ this.__renderer.view.removeEventListener( 'mousedown', onPush )
82
+ } )
83
+ }
84
+
85
+ /**
86
+ * Destroys all listeners
87
+ */
88
+ destroy () {
89
+ this.__listeners.map( ( removeListener ) => {
90
+ removeListener()
91
+ return true
92
+ } )
93
+ this.__listeners = []
94
+ }
95
+ }
@@ -0,0 +1,154 @@
1
+ 'use strict'
2
+
3
+ import { loop, uid } from '@crispcode/modux'
4
+
5
+ import { Container } from '@pixi/display'
6
+
7
+ import { Tween } from './tween.js'
8
+
9
+ /**
10
+ * This class is used to create elements for shimmer
11
+ */
12
+ export class Element extends Container {
13
+ /**
14
+ * Creates an instance of Element
15
+ */
16
+ constructor () {
17
+ super()
18
+
19
+ /**
20
+ * Stores the current horizontal position of the Element
21
+ * @type {Number}
22
+ */
23
+ this.x = 0
24
+
25
+ /**
26
+ * Stores the current vertical position of the Element
27
+ * @type {Number}
28
+ */
29
+ this.y = 0
30
+
31
+ /**
32
+ * Stores the current alpha value for the Element
33
+ * @type {Number}
34
+ */
35
+ this.alpha = 1
36
+
37
+ /**
38
+ * Holds all the Tween instances for the Element
39
+ * @type {Object}
40
+ * @private
41
+ */
42
+ this.__tweens = {}
43
+
44
+ /**
45
+ * Holds all the sub elements of the Element
46
+ * @type {Object}
47
+ * @private
48
+ */
49
+ this.__children = {}
50
+ }
51
+
52
+ /**
53
+ * Creates a new tween for the Element
54
+ * @param {Number} from The start point for the Tween
55
+ * @param {Number} to The end point for the Tween
56
+ * @param {Number} step The step value for the Tween
57
+ * @param {Function} oneach A listener which gets called on each Tween step
58
+ * @param {String} id An specific identifier to use in this element. If not defined, a random unique one will be used.
59
+ * @return {Promise} The promise is resolved on tween end
60
+ */
61
+ createTween ( from, to, step, oneach, id ) {
62
+ return new Promise( ( resolve ) => {
63
+ id = id || uid()
64
+ let tween = new Tween( from, to, step )
65
+ tween.end( () => {
66
+ delete this.__tweens[ id ]
67
+ resolve()
68
+ } )
69
+ if ( typeof oneach === 'function' ) {
70
+ tween.each( oneach )
71
+ }
72
+ this.__tweens[ id ] = tween
73
+ } )
74
+ }
75
+
76
+ /**
77
+ * Removes a tween from the element
78
+ * @param {String} id An specific identifier to used remove tweens from the element
79
+ */
80
+ removeTween ( id ) {
81
+ if ( id ) {
82
+ delete this.__tweens[ id ]
83
+ } else {
84
+ this.__tweens = {}
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Adds a sub element. An element child
90
+ * @param {String} id An identifier for the added child
91
+ * @param {Element} element An instance of the Element class
92
+ * @return {Element} The current instance
93
+ */
94
+ addElementChild ( id, element ) {
95
+ super.addChild( element )
96
+ this.__children[ id ] = element
97
+ return this
98
+ }
99
+
100
+ /**
101
+ * Removes a sub element. An element child
102
+ * @param {String} id An identifier used to find the child
103
+ * @return {Element} The current instance
104
+ */
105
+ removeElementChild ( id ) {
106
+ let element = this.__children[ id ]
107
+ super.removeChild( element )
108
+ delete this.__children[ id ]
109
+ return this
110
+ }
111
+
112
+ /**
113
+ * Returns a child or all child Elements
114
+ * @param {String} [name=null] If provided, will return the child with this identifier
115
+ * @return {Object} An object containing all the child Elements
116
+ */
117
+ getElementChild ( name ) {
118
+ if ( name ) {
119
+ return this.__children[ name ]
120
+ }
121
+ return this.__children
122
+ }
123
+
124
+ /**
125
+ * Sets element visibility to true
126
+ * @return {Promise} A promise wich is resolved once the method is fully executed
127
+ */
128
+ show () {
129
+ this.alpha = 1
130
+ return Promise.resolve()
131
+ }
132
+
133
+ /**
134
+ * Sets element visibility to false
135
+ * @return {Promise} A promise wich is resolved once the method is fully executed
136
+ */
137
+ hide () {
138
+ this.alpha = 0
139
+ return Promise.resolve()
140
+ }
141
+
142
+ /**
143
+ * A method called by the renderer on each animation frame
144
+ * @param {Number} delta The delta time between cycles
145
+ */
146
+ tick ( delta ) {
147
+ loop( this.__tweens, ( tween ) => {
148
+ tween.next( delta )
149
+ } )
150
+ loop( this.getElementChild(), ( element ) => {
151
+ element.tick( delta )
152
+ } )
153
+ }
154
+ }
@@ -0,0 +1,28 @@
1
+ 'use strict'
2
+
3
+ import { Shimmer } from './shimmer.js'
4
+
5
+ import { Button } from './button.js'
6
+ import { Element } from './element.js'
7
+ import { Tween } from './tween.js'
8
+
9
+ import { Sprite } from '@pixi/sprite'
10
+ import { AnimatedSprite } from '@pixi/sprite-animated'
11
+ import { Text } from '@pixi/text'
12
+ import { Graphics } from '@pixi/graphics'
13
+ import { BaseTexture, Texture } from '@pixi/core'
14
+
15
+ export {
16
+ Shimmer,
17
+
18
+ Button,
19
+ Element,
20
+ Tween,
21
+
22
+ Sprite,
23
+ AnimatedSprite,
24
+ Text,
25
+ Texture,
26
+ BaseTexture,
27
+ Graphics
28
+ }
@@ -0,0 +1,195 @@
1
+ /* globals window */
2
+
3
+ 'use strict'
4
+
5
+ import { Component, extend, loop, logger } from '@crispcode/modux'
6
+
7
+ import { autoDetectRenderer, Renderer, BatchRenderer } from '@pixi/core'
8
+ import { Loader } from '@pixi/loaders'
9
+ import { Ticker } from '@pixi/ticker'
10
+ import { InteractionManager } from '@pixi/interaction'
11
+ import { skipHello, isWebGLSupported } from '@pixi/utils'
12
+
13
+ // Canvas support
14
+ import '@pixi/canvas-display'
15
+ import { CanvasExtract } from '@pixi/canvas-extract'
16
+ import { CanvasGraphicsRenderer } from '@pixi/canvas-graphics'
17
+ import { CanvasMeshRenderer } from '@pixi/canvas-mesh'
18
+ import '@pixi/canvas-particle-container'
19
+ import { CanvasPrepare } from '@pixi/canvas-prepare'
20
+ import { CanvasRenderer } from '@pixi/canvas-renderer'
21
+ import '@pixi/canvas-sprite-tiling'
22
+ import { CanvasSpriteRenderer } from '@pixi/canvas-sprite'
23
+ import '@pixi/canvas-text'
24
+
25
+ import { Element } from './element.js'
26
+ import { Controls } from './controls.js'
27
+
28
+ Renderer.registerPlugin( 'interaction', InteractionManager )
29
+ Renderer.registerPlugin( 'batch', BatchRenderer )
30
+
31
+ CanvasRenderer.registerPlugin( 'interaction', InteractionManager )
32
+ CanvasRenderer.registerPlugin( 'extract', CanvasExtract )
33
+ CanvasRenderer.registerPlugin( 'graphics', CanvasGraphicsRenderer )
34
+ CanvasRenderer.registerPlugin( 'mesh', CanvasMeshRenderer )
35
+ CanvasRenderer.registerPlugin( 'prepare', CanvasPrepare )
36
+ CanvasRenderer.registerPlugin( 'sprite', CanvasSpriteRenderer )
37
+
38
+ /**
39
+ * This class is used to create the shimmer component
40
+ */
41
+ export class Shimmer extends Component {
42
+ /**
43
+ * The html string that becomes the view for this component
44
+ * @type {String}
45
+ */
46
+ get template () {
47
+ return '<canvas style="display: block; width: 100%; height: 100%;"></canvas>'
48
+ }
49
+
50
+ /**
51
+ * The initialization options for shimmer
52
+ * @type {Object}
53
+ */
54
+ get settings () {
55
+ return {}
56
+ }
57
+
58
+ /**
59
+ * The method gets called whenever the container is resized
60
+ * @param {Number} width The width of the container
61
+ * @param {Number} height The height of the container
62
+ */
63
+ onResize ( width, height ) {
64
+
65
+ }
66
+
67
+ /**
68
+ * This method preloads a colection of assets
69
+ * @param {Object} assets A collection of assets
70
+ * @return {Promise} A promise which is resolved upon loading the assets. It resolves the loaded resources.
71
+ */
72
+ preload ( assets ) {
73
+ let loader = new Loader()
74
+ return new Promise( ( resolve ) => {
75
+ loop( assets, ( data, name ) => {
76
+ loader.add( name, data )
77
+ } )
78
+ loader.load( ( loader, resources ) => {
79
+ resolve( resources )
80
+ } )
81
+ } )
82
+ }
83
+
84
+ /**
85
+ * Creates an instance of Shimmer
86
+ * @param {HTMLElement} parent The parent wrapper
87
+ * @param {Module} module The parent module instance
88
+ * @param {Store} store An instance of @crispcode/pushstore, see https://www.npmjs.com/package/@crispcode/pushstore
89
+ */
90
+ constructor ( parent, module, store ) {
91
+ super( parent, module, store )
92
+
93
+ skipHello()
94
+
95
+ /**
96
+ * Stores the parent Element
97
+ * @type {Element}
98
+ */
99
+ this.stage = new Element()
100
+
101
+ /**
102
+ * Holds the previous width and height of the element
103
+ * @type {Object}
104
+ * @private
105
+ */
106
+ let previousElementSize = {}
107
+ /**
108
+ * Determines if the component watches for resize changes in parent dimensions
109
+ * @type {Boolean}
110
+ * @private
111
+ */
112
+ this.__resizeWatcher = true
113
+ /**
114
+ * This function checks for element size changes every 100ms as long as the component exists
115
+ * @type {Function}
116
+ * @private
117
+ */
118
+ const parentResizeCheck = () => {
119
+ setTimeout( () => {
120
+ if ( this.__resizeWatcher ) {
121
+ if ( previousElementSize.width !== this.element.clientWidth || previousElementSize.height !== this.element.clientHeight ) {
122
+ previousElementSize.width = this.element.clientWidth
123
+ previousElementSize.height = this.element.clientHeight
124
+ this.onResize( previousElementSize.width, previousElementSize.height )
125
+ }
126
+ parentResizeCheck()
127
+ }
128
+ }, 100 )
129
+ }
130
+ parentResizeCheck()
131
+
132
+ /**
133
+ * Stores the main ticker, which handles animation frames
134
+ * @type {Ticker}
135
+ */
136
+ this.ticker = new Ticker()
137
+ this.ticker.add( ( delta ) => {
138
+ this.stage.tick( delta )
139
+ this.renderer.render( this.stage )
140
+ } )
141
+
142
+ /**
143
+ * Renderer initialization settings
144
+ * @type {Object}
145
+ * @private
146
+ */
147
+ const rendererSettings = extend( {
148
+ view: this.element,
149
+ autoDensity: false,
150
+ backgroundAlpha: 0,
151
+ backgroundColor: 0x000000,
152
+ antialias: true,
153
+ resolution: window.devicePixelRatio || 1
154
+ }, {
155
+ autoDensity: this.settings.autoDensity,
156
+ backgroundAlpha: this.settings.backgroundAlpha,
157
+ backgroundColor: this.settings.backgroundColor,
158
+ antialias: this.settings.antialias,
159
+ resolution: this.settings.resolution
160
+ } )
161
+
162
+ /**
163
+ * Stores the renderer
164
+ * @type {Renderer}
165
+ */
166
+ this.renderer = ( isWebGLSupported() && !this.settings.forceCanvas ) ? autoDetectRenderer( rendererSettings ) : new CanvasRenderer( rendererSettings )
167
+
168
+ this.renderer.resize( this.element.clientWidth, this.element.clientHeight )
169
+
170
+ this.renderer.plugins.interaction.autoPreventDefault = false
171
+
172
+ if ( !isWebGLSupported() ) {
173
+ logger.warn( 'WebGL is not supported. Using Canvas fallback.' )
174
+ }
175
+
176
+ /**
177
+ * Stores the controls class, responsible with implementing special gestures
178
+ */
179
+ this.controls = new Controls( this.renderer )
180
+ this.controls.enableWheel()
181
+ this.controls.enableLongtap()
182
+ }
183
+
184
+ /**
185
+ * The method gets called when the component is destroyed
186
+ */
187
+ __destroy () {
188
+ super.__destroy()
189
+ this.controls.destroy()
190
+ this.__resizeWatcher = false
191
+ if ( this.ticker.started ) {
192
+ this.ticker.stop()
193
+ }
194
+ }
195
+ }
@@ -0,0 +1,147 @@
1
+ 'use strict'
2
+
3
+ import { approx, loop } from '@crispcode/modux'
4
+
5
+ /**
6
+ * This class is used to create a tween
7
+ */
8
+ export class Tween {
9
+ /**
10
+ * Creates an instance of Shimmer
11
+ * @param {Number} from The start number
12
+ * @param {Number} to The end number
13
+ * @param {Number} step The value to increment by on each render
14
+ */
15
+ constructor ( from, to, step ) {
16
+ /**
17
+ * Stores all event handlers attached
18
+ * @type {Object}
19
+ * @private
20
+ */
21
+ this.__eventHandlers = {}
22
+
23
+ /**
24
+ * Stores the starting point for the loop
25
+ * @type {Number}
26
+ */
27
+ this.from = from || 0
28
+
29
+ /**
30
+ * Stores the end point for the loop
31
+ * @type {Number}
32
+ */
33
+ this.to = to || 0
34
+
35
+ /**
36
+ * Stores the step value for the loop
37
+ * @type {Number}
38
+ */
39
+ this.step = step || 0
40
+
41
+ /**
42
+ * Stores the current frame in the tween
43
+ * @type {Number}
44
+ * @private
45
+ */
46
+ this.__current = this.from
47
+ }
48
+
49
+ /**
50
+ * Method to attach an event listener to tween
51
+ * @param {String} ev The event name
52
+ * @param {Function} handler The event handler to be attached to the tween
53
+ * @return {Tween} Returns the instance of the class
54
+ */
55
+ on ( ev, handler ) {
56
+ this.__eventHandlers[ ev ] = this.__eventHandlers[ ev ] || []
57
+ if ( typeof handler !== 'function' ) {
58
+ throw new Error( 'Tween expects an event handler ( function ) ' + ( typeof handler ) + ' given' )
59
+ }
60
+ this.__eventHandlers[ ev ].push( handler )
61
+ return this
62
+ }
63
+
64
+ // Shorthand event handlers
65
+
66
+ /**
67
+ * Short hand for the onEach event listener to attach
68
+ * @param {Function} handler The event handler to be attached to the tween
69
+ * @return {Tween} Returns the instance of the class
70
+ */
71
+ each ( handler ) {
72
+ return this.on( 'each', handler )
73
+ }
74
+ /**
75
+ * Short hand for the onEnd event listener to attach
76
+ * @param {Function} handler The event handler to be attached to the tween
77
+ * @return {Tween} Returns the instance of the class
78
+ */
79
+ end ( handler ) {
80
+ return this.on( 'end', handler )
81
+ }
82
+
83
+ /**
84
+ * Calls every event listener attached to the class
85
+ * @param {String} name The event name
86
+ * @param {Number} value The value to be sent to each handler
87
+ * @private
88
+ */
89
+ __triggerEvent ( name, value ) {
90
+ let events = this.__eventHandlers[ name ] || []
91
+ loop( events, ( event ) => {
92
+ event.call( this, value )
93
+ } )
94
+ }
95
+
96
+ /**
97
+ * Moves to a specific position in the tween
98
+ * @param {Number} frame The numeric position to move to in the tween
99
+ * @return {Tween} Returns the instance of the class
100
+ */
101
+ goto ( frame ) {
102
+ if ( frame ) {
103
+ this.__current = frame
104
+ } else {
105
+ this.__current = this.from
106
+ }
107
+ return this
108
+ }
109
+
110
+ /**
111
+ * Method moves forward in the tween based on the detal
112
+ * @param {Number} delta The time interval caused by FPS
113
+ */
114
+ next ( delta ) {
115
+ this.__current = approx( this.__current + approx( this.step * delta, 6 ), 6 )
116
+
117
+ if (
118
+ ( ( this.from <= this.to ) && ( this.__current >= this.to ) ) ||
119
+ ( ( this.from >= this.to ) && ( this.__current <= this.to ) )
120
+ ) {
121
+ // End
122
+ this.__triggerEvent( 'end' )
123
+ this.__current = this.to
124
+ }
125
+
126
+ this.__triggerEvent( 'each', this.__current )
127
+ }
128
+
129
+ /**
130
+ * Method moves backwards in the tween based on the detal
131
+ * @param {Number} delta The time interval caused by FPS
132
+ */
133
+ prev ( delta ) {
134
+ this.__current = approx( this.__current - approx( this.step * delta, 6 ), 6 )
135
+
136
+ if (
137
+ ( ( this.from <= this.to ) && ( this.__current <= this.from ) ) ||
138
+ ( ( this.from >= this.to ) && ( this.__current >= this.from ) )
139
+ ) {
140
+ // End
141
+ this.__triggerEvent( 'end' )
142
+ this.__current = this.from
143
+ }
144
+
145
+ this.__triggerEvent( 'each', this.__current )
146
+ }
147
+ }
package/test/app.html ADDED
@@ -0,0 +1,30 @@
1
+ <!DOCTYPE html>
2
+ <head>
3
+ <title> Shimmer </title>
4
+
5
+ <meta name="apple-mobile-web-app-capable" content="yes" />
6
+ <meta name="mobile-web-app-capable" content="yes" />
7
+ <meta name="format-detection" content="telephone=no">
8
+ <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, user-scalable=no">
9
+
10
+ <meta name="HandheldFriendly" content="true" />
11
+ <meta name="apple-mobile-web-app-capable" content="yes" />
12
+ <meta name="apple-mobile-web-app-status-bar-style" content="black" />
13
+ <meta name="apple-mobile-web-app-title" content="Open the Box">
14
+
15
+ <script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.min.js?flags=gated&features=default%2CMutationObserver%2CString.prototype.padStart%2Cconsole.info"></script>
16
+
17
+ <base href="/" />
18
+
19
+ <link rel="stylesheet" href="app.min.css" />
20
+
21
+ <script>
22
+ var config = {
23
+ debug: true
24
+ }
25
+ </script>
26
+ </head>
27
+ <body>
28
+ <script src="app.min.js"></script>
29
+ </body>
30
+ </html>
package/test/app.js ADDED
@@ -0,0 +1,4 @@
1
+ 'use strict'
2
+
3
+ require( './styles/index.scss' )
4
+ require( './scripts/index.js' )
@@ -0,0 +1,8 @@
1
+ 'use strict'
2
+
3
+ module.exports = ( config ) => {
4
+ // Enable logging in webpack
5
+ config.stats = 'normal'
6
+
7
+ return config
8
+ }
Binary file
Binary file
@@ -0,0 +1,9 @@
1
+ 'use strict'
2
+
3
+ import { Component } from '@crispcode/modux'
4
+
5
+ export class LayoutComponent extends Component {
6
+ get template () {
7
+ return require( './template.html' )
8
+ }
9
+ }
@@ -0,0 +1,3 @@
1
+ <section class="layout">
2
+ <section data-modux-component="shimmer"></section>
3
+ </section>