@crispcode/shimmer 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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>