2017-01-21 17:06:19 +00:00
( function e ( t , n , r ) { function s ( o , u ) { if ( ! n [ o ] ) { if ( ! t [ o ] ) { var a = typeof require == "function" && require ; if ( ! u && a ) return a ( o , ! 0 ) ; if ( i ) return i ( o , ! 0 ) ; var f = new Error ( "Cannot find module '" + o + "'" ) ; throw f . code = "MODULE_NOT_FOUND" , f } var l = n [ o ] = { exports : { } } ; t [ o ] [ 0 ] . call ( l . exports , function ( e ) { var n = t [ o ] [ 1 ] [ e ] ; return s ( n ? n : e ) } , l , l . exports , e , t , n , r ) } return n [ o ] . exports } var i = typeof require == "function" && require ; for ( var o = 0 ; o < r . length ; o ++ ) s ( r [ o ] ) ; return s } ) ( { 1 : [ function ( require , module , exports ) {
'use strict' ;
2017-02-04 21:26:48 +00:00
/ * *
* Constants for the different readyStates that a WebSocket can be in .
* @ type { Object }
* /
const WebSocketStates = {
/ * *
* Indicates that the WebSocket is connecting to the remote server .
* @ type { Number }
* /
connecting : 0 ,
/ * *
* Indicates that the WebSocket is connected to the remote server and ready to send / receive data .
* @ type { Number }
* /
ready : 1 ,
/ * *
* Indicates that the WebSocket is in the process of closing the connection to the remote server .
* @ type { Number }
* /
closing : 2 ,
/ * *
* Indicates that hte WebSocket is not connected to the remote server ( either because the connection was closed , or dropped by the remote server ) .
* @ type { Number }
* /
closed : 3
} ;
const EventEmitter$1 = require ( "event-emitter-es6" ) ;
class RippleLink extends EventEmitter$1
2017-01-21 18:38:52 +00:00
{
constructor ( inSocketUrl , inBoardWindow )
{
2017-02-04 21:26:48 +00:00
super ( ) ;
2017-01-21 18:38:52 +00:00
this . socketUrl = inSocketUrl ;
this . boardWindow = inBoardWindow ;
this . settings = this . boardWindow . settings ;
2017-02-04 21:26:48 +00:00
// Create the websocket and commect to the server
this . websocket = new WebSocket ( this . socketUrl , [ this . settings . WebsocketProtocol ] ) ;
this . websocket . addEventListener ( "open" , this . handleConnection . bind ( this ) ) ;
this . websocket . addEventListener ( "message" , this . handleMessage . bind ( this ) ) ;
this . websocket . addEventListener ( "close" , this . handleDisconnection . bind ( this ) ) ;
2017-02-05 14:46:40 +00:00
// Close the socket correctly
window . addEventListener ( "beforeunload" , ( function ( event ) {
this . websocket . close ( ) ;
} ) . bind ( this ) ) ;
2017-02-04 21:26:48 +00:00
}
handleConnection ( event ) {
console . info ( "[ripple link] Established connection successfully." ) ;
// Tell everyone about it
this . emit ( "connect" , event ) ;
}
handleDisconnection ( event ) {
console . error ( "[ripple link] Lost connection." ) ;
this . emit ( "disconnect" , event ) ;
}
handleMessage ( event ) {
// Decode the message form the server
var message = JSON . parse ( event . data ) ;
console . debug ( message ) ;
// Pass it on to the board manager by triggering the appropriate event
this . emit ( message . event , message ) ;
}
/ * *
* Sends a message object to the server .
* /
send ( message ) {
if ( this . websocket . readyState !== WebSocketStates . ready )
{
console . error ( ` Attempt to send data on the RippleLine when it is not ready (state ${ this . websocket . readyState } ) ` ) ;
return false ;
}
this . websocket . send ( JSON . stringify ( message ) ) ;
return true ;
2017-01-21 18:38:52 +00:00
}
}
2017-02-07 21:29:17 +00:00
class CursorSyncer
{
constructor ( inRippleLink , syncFrequency )
{
// The ripple link we should send the cursor updates down
this . rippleLink = inRippleLink ;
// The target frequency in fps at we should send sursor updates.
this . cursorUpdateFrequency = syncFrequency ;
// Register ourselves to start sending cursor updates once the ripple
// link connects
this . rippleLink . on ( "connect" , this . setup . bind ( this ) ) ;
}
setup ( )
{
// The last time we sent a cursor update to the server.
this . lastCursorUpdate = 0 ;
document . addEventListener ( "mousemove" , ( function ( event ) {
this . cursorPosition = {
X : event . clientX ,
Y : event . clientY
} ;
setTimeout ( ( function ( ) {
// Throttle the cursor updates we send to the server - a high
// update frequency here will just consume bandwidth and is only
// noticable if you have a good connection
if ( + new Date ( ) - this . lastCursorUpdate < 1 / this . cursorUpdateFrequency )
return false ;
// Update the server on the mouse's position
this . sendCursorUpdate ( ) ;
this . lastFrameStart = + new Date ( ) ;
} ) . bind ( this ) , 1 / this . cursorUpdateFrequency ) ;
} ) . bind ( this ) ) ;
this . sendCursorUpdate ( ) ;
}
sendCursorUpdate ( )
{
// Update the server on the mouse's position
this . rippleLink . send ( {
"event" : "CursorPosition" ,
"AbsCursorPosition" : this . cursorPosition
} ) ;
}
}
2017-01-21 17:06:19 +00:00
function get ( u ) { return new Promise ( function ( r , t , a ) { a = new XMLHttpRequest ( ) ; a . onload = function ( b , c ) { b = a . status ; c = a . response ; if ( b > 199 && b < 300 ) { r ( c ) ; } else { t ( c ) ; } } ; a . open ( "GET" , u , true ) ; a . send ( null ) ; } ) }
// npm modules
window . EventEmitter = require ( "event-emitter-es6" ) ;
window . FaviconNotification = require ( "favicon-notification" ) ;
2017-02-04 21:26:48 +00:00
window . panzoom = require ( "pan-zoom" ) ;
2017-01-21 17:06:19 +00:00
// Our files
class BoardWindow extends EventEmitter
{
constructor ( canvas )
{
super ( ) ; // Run the parent constructor
2017-02-04 21:26:48 +00:00
// The maximum target fps.
2017-01-22 13:05:59 +00:00
this . maxFps = 60 ;
2017-02-07 21:29:17 +00:00
// The target fps at which we should send sursor updates.
this . cursorUpdateFrequency = 5 ;
// Setup the fps indicator in the top right corner
2017-01-22 13:05:59 +00:00
this . renderTimeIndicator = document . createElement ( "span" ) ;
this . renderTimeIndicator . innerHTML = "0ms" ;
document . querySelector ( ".fps" ) . appendChild ( this . renderTimeIndicator ) ;
2017-02-04 21:26:48 +00:00
// Setup the canvas
2017-01-21 17:06:19 +00:00
this . canvas = canvas ;
this . context = canvas . getContext ( "2d" ) ;
2017-02-04 21:26:48 +00:00
// --~~~--
// Setup the favicon thingy
2017-01-21 17:06:19 +00:00
FaviconNotification . init ( {
color : '#ff6333'
} ) ;
FaviconNotification . add ( ) ;
2017-02-04 21:26:48 +00:00
// Setup the input controls
window . panzoom ( canvas , this . handleCanvasMovement . bind ( this ) ) ;
// Fetch the RippleLink connection information and other settings from
// the server
2017-01-21 17:06:19 +00:00
get ( "/Settings.json" ) . then ( JSON . parse ) . then ( ( function ( settings ) {
2017-01-21 18:38:52 +00:00
console . info ( "[setup]" , "Obtained settings from server:" , settings ) ;
2017-01-21 17:06:19 +00:00
this . settings = settings ;
this . setup ( ) ;
} ) . bind ( this ) , function ( errorMessage ) {
console . error ( ` Error: Failed to fetch settings from server! Response: ${ errorMessage } ` ) ;
} ) ;
2017-02-04 21:26:48 +00:00
// Make the canvas track the window size
2017-01-21 17:06:19 +00:00
this . trackWindowSize ( ) ;
}
2017-02-04 21:26:48 +00:00
/ * *
* Setup ready for user input .
* This mainly consists of establishing the RippleLink connection to the server .
* /
2017-01-21 18:38:52 +00:00
setup ( ) {
this . rippleLink = new RippleLink ( this . settings . WebsocketUri , this ) ;
2017-02-04 21:26:48 +00:00
this . rippleLink . on ( "connect" , ( function ( event ) {
// Send the handshake request
this . rippleLink . send ( {
2017-02-07 21:29:17 +00:00
event : "HandshakeRequest" ,
2017-02-04 21:26:48 +00:00
InitialViewport : { // TODO: Add support for persisting this between sessions
X : 0 ,
Y : 0 ,
Width : window . innerWidth ,
Height : window . innerHeight
} ,
InitialAbsCursorPosition : this . cursorPosition
} ) ;
} ) . bind ( this ) ) ;
2017-02-07 21:29:17 +00:00
// Track the mouse position
this . cursorSyncer = new CursorSyncer ( this . rippleLink , this . cursorUpdateFrequency ) ;
2017-02-04 21:26:48 +00:00
// RippleLink message bindings
2017-01-21 18:38:52 +00:00
}
2017-02-04 21:26:48 +00:00
/ * *
* Renders the next frame .
* /
2017-01-21 17:06:19 +00:00
nextFrame ( )
{
2017-01-22 13:05:59 +00:00
// The time at which the current frame started rendering.
let frameStart = + new Date ( ) ;
if ( frameStart - this . lastFrameStart >= ( 1 / this . maxFps ) * 1000 )
{
this . update ( ) ;
this . render ( this . canvas , this . context ) ;
}
// Update the time the last frame started rendering
this . lastFrameStart = frameStart ;
// Update the time we took rendering the last frame
this . lastFrameTime = + new Date ( ) - frameStart ;
this . renderTimeIndicator . innerHTML = ` ${ this . lastFrameTime } ms ` ;
// Limit the maximum fps
2017-01-21 17:06:19 +00:00
requestAnimationFrame ( this . nextFrame . bind ( this ) ) ;
}
2017-02-04 21:26:48 +00:00
/ * *
* Updates everything ready for the next frame to be rendered .
* /
2017-01-21 17:06:19 +00:00
update ( )
{
}
2017-02-04 21:26:48 +00:00
/ * *
* Renders the next frame .
* /
2017-01-21 17:06:19 +00:00
render ( canvas , context )
{
context . clearRect ( 0 , 0 , canvas . width , canvas . height ) ;
context . fillStyle = "red" ;
context . fillRect ( 10 , 10 , 100 , 100 ) ;
}
/ * *
* Updates the canvas size to match the current viewport size .
* /
matchWindowSize ( ) {
this . canvas . width = window . innerWidth ;
this . canvas . height = window . innerHeight ;
this . render ( this . canvas , this . context ) ;
}
/ * *
* Makes the canvas size track the window size .
* /
trackWindowSize ( ) {
this . matchWindowSize ( ) ;
window . addEventListener ( "resize" , this . matchWindowSize . bind ( this ) ) ;
}
2017-02-04 21:26:48 +00:00
/ * *
* Handles events generated by pan - zoom , the package that handles the
* dragging and zooming of the whiteboard .
* /
handleCanvasMovement ( event ) {
this . viewportState = event ; // Store the viewport information for later
}
2017-01-21 17:06:19 +00:00
}
2017-01-22 13:05:59 +00:00
window . FpsIndicator = require ( "fps-indicator" ) ;
2017-01-21 17:06:19 +00:00
window . addEventListener ( "load" , function ( event ) {
2017-01-22 13:05:59 +00:00
let fpsIndicator = FpsIndicator ( {
updatePeriod : 1000 ,
maxFps : 60
} ) ;
fpsIndicator . element . style . color = "rgb(114, 194, 179)" ;
let canvas = document . getElementById ( "canvas-main" ) ,
2017-01-21 17:06:19 +00:00
boardWindow = new BoardWindow ( canvas ) ;
boardWindow . nextFrame ( ) ;
window . boardWindow = boardWindow ;
} ) ;
2017-02-04 21:26:48 +00:00
} , { "event-emitter-es6" : 3 , "favicon-notification" : 4 , "fps-indicator" : 5 , "pan-zoom" : 10 } ] , 2 : [ function ( require , module , exports ) {
module . exports = defaultProperty
function defaultProperty ( get , set ) {
return {
configurable : true ,
enumerable : true ,
get : get ,
set : set
}
}
} , { } ] , 3 : [ function ( require , module , exports ) {
2017-01-21 17:06:19 +00:00
'use strict' ;
var _createClass = function ( ) { function defineProperties ( target , props ) { for ( var i = 0 ; i < props . length ; i ++ ) { var descriptor = props [ i ] ; descriptor . enumerable = descriptor . enumerable || false ; descriptor . configurable = true ; if ( "value" in descriptor ) descriptor . writable = true ; Object . defineProperty ( target , descriptor . key , descriptor ) ; } } return function ( Constructor , protoProps , staticProps ) { if ( protoProps ) defineProperties ( Constructor . prototype , protoProps ) ; if ( staticProps ) defineProperties ( Constructor , staticProps ) ; return Constructor ; } ; } ( ) ;
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
var DEFAULT _VALUES = {
emitDelay : 10 ,
strictMode : false
} ;
/ * *
* @ typedef { object } EventEmitterListenerFunc
* @ property { boolean } once
* @ property { function } fn
* /
/ * *
* @ class EventEmitter
*
* @ private
* @ property { Object . < string , EventEmitterListenerFunc [ ] > } _listeners
* @ property { string [ ] } events
* /
var EventEmitter = function ( ) {
/ * *
* @ constructor
* @ param { { } } [ opts ]
* @ param { number } [ opts . emitDelay = 10 ] - Number in ms . Specifies whether emit will be sync or async . By default - 10 ms . If 0 - fires sync
* @ param { boolean } [ opts . strictMode = false ] - is true , Emitter throws error on emit error with no listeners
* /
function EventEmitter ( ) {
var opts = arguments . length <= 0 || arguments [ 0 ] === undefined ? DEFAULT _VALUES : arguments [ 0 ] ;
_classCallCheck ( this , EventEmitter ) ;
var emitDelay = void 0 ,
strictMode = void 0 ;
if ( opts . hasOwnProperty ( 'emitDelay' ) ) {
emitDelay = opts . emitDelay ;
} else {
emitDelay = DEFAULT _VALUES . emitDelay ;
}
this . _emitDelay = emitDelay ;
if ( opts . hasOwnProperty ( 'strictMode' ) ) {
strictMode = opts . strictMode ;
} else {
strictMode = DEFAULT _VALUES . strictMode ;
}
this . _strictMode = strictMode ;
this . _listeners = { } ;
this . events = [ ] ;
}
/ * *
* @ protected
* @ param { string } type
* @ param { function } listener
* @ param { boolean } [ once = false ]
* /
_createClass ( EventEmitter , [ {
key : '_addListenner' ,
value : function _addListenner ( type , listener , once ) {
if ( typeof listener !== 'function' ) {
throw TypeError ( 'listener must be a function' ) ;
}
if ( this . events . indexOf ( type ) === - 1 ) {
this . _listeners [ type ] = [ {
once : once ,
fn : listener
} ] ;
this . events . push ( type ) ;
} else {
this . _listeners [ type ] . push ( {
once : once ,
fn : listener
} ) ;
}
}
/ * *
* Subscribes on event type specified function
* @ param { string } type
* @ param { function } listener
* /
} , {
key : 'on' ,
value : function on ( type , listener ) {
this . _addListenner ( type , listener , false ) ;
}
/ * *
* Subscribes on event type specified function to fire only once
* @ param { string } type
* @ param { function } listener
* /
} , {
key : 'once' ,
value : function once ( type , listener ) {
this . _addListenner ( type , listener , true ) ;
}
/ * *
* Removes event with specified type . If specified listenerFunc - deletes only one listener of specified type
* @ param { string } eventType
* @ param { function } [ listenerFunc ]
* /
} , {
key : 'off' ,
value : function off ( eventType , listenerFunc ) {
var _this = this ;
var typeIndex = this . events . indexOf ( eventType ) ;
var hasType = eventType && typeIndex !== - 1 ;
if ( hasType ) {
if ( ! listenerFunc ) {
delete this . _listeners [ eventType ] ;
this . events . splice ( typeIndex , 1 ) ;
} else {
( function ( ) {
var removedEvents = [ ] ;
var typeListeners = _this . _listeners [ eventType ] ;
typeListeners . forEach (
/ * *
* @ param { EventEmitterListenerFunc } fn
* @ param { number } idx
* /
function ( fn , idx ) {
if ( fn . fn === listenerFunc ) {
removedEvents . unshift ( idx ) ;
}
} ) ;
removedEvents . forEach ( function ( idx ) {
typeListeners . splice ( idx , 1 ) ;
} ) ;
if ( ! typeListeners . length ) {
_this . events . splice ( typeIndex , 1 ) ;
delete _this . _listeners [ eventType ] ;
}
} ) ( ) ;
}
}
}
/ * *
* Applies arguments to specified event type
* @ param { string } eventType
* @ param { * [ ] } eventArguments
* @ protected
* /
} , {
key : '_applyEvents' ,
value : function _applyEvents ( eventType , eventArguments ) {
var typeListeners = this . _listeners [ eventType ] ;
if ( ! typeListeners || ! typeListeners . length ) {
if ( this . _strictMode ) {
throw 'No listeners specified for event: ' + eventType ;
} else {
return ;
}
}
var removableListeners = [ ] ;
typeListeners . forEach ( function ( eeListener , idx ) {
eeListener . fn . apply ( null , eventArguments ) ;
if ( eeListener . once ) {
removableListeners . unshift ( idx ) ;
}
} ) ;
removableListeners . forEach ( function ( idx ) {
typeListeners . splice ( idx , 1 ) ;
} ) ;
}
/ * *
* Emits event with specified type and params .
* @ param { string } type
* @ param eventArgs
* /
} , {
key : 'emit' ,
value : function emit ( type ) {
var _this2 = this ;
for ( var _len = arguments . length , eventArgs = Array ( _len > 1 ? _len - 1 : 0 ) , _key = 1 ; _key < _len ; _key ++ ) {
eventArgs [ _key - 1 ] = arguments [ _key ] ;
}
if ( this . _emitDelay ) {
setTimeout ( function ( ) {
_this2 . _applyEvents . call ( _this2 , type , eventArgs ) ;
} , this . _emitDelay ) ;
} else {
this . _applyEvents ( type , eventArgs ) ;
}
}
/ * *
* Emits event with specified type and params synchronously .
* @ param { string } type
* @ param eventArgs
* /
} , {
key : 'emitSync' ,
value : function emitSync ( type ) {
for ( var _len2 = arguments . length , eventArgs = Array ( _len2 > 1 ? _len2 - 1 : 0 ) , _key2 = 1 ; _key2 < _len2 ; _key2 ++ ) {
eventArgs [ _key2 - 1 ] = arguments [ _key2 ] ;
}
this . _applyEvents ( type , eventArgs ) ;
}
/ * *
* Destroys EventEmitter
* /
} , {
key : 'destroy' ,
value : function destroy ( ) {
this . _listeners = { } ;
this . events = [ ] ;
}
} ] ) ;
return EventEmitter ;
} ( ) ;
module . exports = EventEmitter ;
2017-02-04 21:26:48 +00:00
} , { } ] , 4 : [ function ( require , module , exports ) {
2017-01-21 17:06:19 +00:00
( function ( root , factory ) {
if ( typeof define === 'function' && define . amd ) {
// AMD. Register as an anonymous module.
define ( [ ] , factory ) ;
} else if ( typeof exports === 'object' ) {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module . exports = factory ( ) ;
} else {
// Browser globals (root is window)
root . FaviconNotification = factory ( ) ;
}
} ( this , function ( ) {
// Just return a value to define the module export.
// This example returns an object, but the module
// can return a function as the exported value.
// Only run in browser
if ( typeof document === 'undefined' ) {
console . log ( 'This script only run in browsers.' ) ;
return ;
}
// Private properties
var _options = { } ;
var _defaults = {
url : '/favicon.ico' ,
color : '#eb361e' ,
lineColor : '#ffffff'
} ;
var _generatedFavicon ;
var _iconElement ;
// Provate methods
var _addFavicon = function ( src ) {
var head = document . getElementsByTagName ( 'head' ) [ 0 ] ;
_iconElement = document . createElement ( 'link' ) ;
_iconElement . type = 'image/x-icon' ;
_iconElement . rel = 'icon' ;
_iconElement . href = src ;
// remove existing favicons
var links = document . getElementsByTagName ( 'link' ) ;
for ( var i = 0 , len = links . length ; i < len ; i ++ ) {
var exists = ( typeof ( links [ i ] ) !== 'undefined' ) ;
if ( exists && ( links [ i ] . getAttribute ( 'rel' ) || '' ) . match ( /\bicon\b/ ) ) {
head . removeChild ( links [ i ] ) ;
}
}
head . appendChild ( _iconElement ) ;
} ;
var _generateIcon = function ( cb ) {
var img = document . createElement ( 'img' ) ;
img . src = _options . url ;
img . onload = function ( ) {
var lineWidth = 2 ;
var canvas = document . createElement ( 'canvas' ) ;
canvas . width = img . width ;
canvas . height = img . height ;
var context = canvas . getContext ( '2d' ) ;
context . clearRect ( 0 , 0 , img . width , img . height ) ;
context . drawImage ( img , 0 , 0 ) ;
var centerX = img . width - ( img . width / 4.5 ) - lineWidth ;
var centerY = img . height - ( img . height / 4.5 ) - lineWidth ;
var radius = img . width / 4.5 ;
context . fillStyle = _options . color ;
context . strokeStyle = _options . lineColor ;
context . lineWidth = lineWidth ;
context . beginPath ( ) ;
context . arc ( centerX , centerY , radius , 0 , Math . PI * 2 , false ) ;
context . closePath ( ) ;
context . fill ( ) ;
context . stroke ( ) ;
cb ( null , context . canvas . toDataURL ( ) ) ;
} ;
} ;
var _setOptions = function ( options ) {
if ( ! options ) {
_options = _defaults ;
return ;
}
_options = { } ;
for ( var key in _defaults ) {
_options [ key ] = options . hasOwnProperty ( key ) ? options [ key ] : _defaults [ key ] ;
}
} ;
var FaviconNotification = {
init : function ( options ) {
_setOptions ( options ) ;
_generateIcon ( function ( err , url ) {
_generatedFavicon = url ;
} ) ;
_addFavicon ( _options . url ) ;
} ,
add : function ( ) {
if ( ! _generatedFavicon && ! _iconElement ) {
_setOptions ( ) ;
_generateIcon ( function ( err , url ) {
_generatedFavicon = url ;
_addFavicon ( url ) ;
} ) ;
} else {
_iconElement . href = _generatedFavicon ;
}
} ,
remove : function ( ) {
_iconElement . href = _options . url ;
}
} ;
return FaviconNotification ;
} ) ) ;
2017-02-04 21:26:48 +00:00
} , { } ] , 5 : [ function ( require , module , exports ) {
2017-01-22 13:05:59 +00:00
/ * *
* @ module fps - indicator
* /
const raf = require ( 'raf' ) ;
const now = require ( 'right-now' ) ;
module . exports = fps ;
function fps ( opts ) {
if ( ! ( this instanceof fps ) ) return new fps ( opts ) ;
opts = opts || { } ;
if ( opts . container ) {
if ( typeof opts . container === 'string' ) {
this . container = document . querySelector ( opts . container ) ;
}
else {
this . container = opts . container ;
}
}
else {
this . container = document . body || document . documentElement ;
}
//init fps
this . element = document . createElement ( 'div' ) ;
this . element . classList . add ( 'fps' ) ;
this . element . innerHTML = `
< div class = "fps-bg" > < / d i v >
< canvas class = "fps-canvas" > < / c a n v a s >
< span class = "fps-text" > fps < span class = "fps-value" > 60.0 < / s p a n > < / s p a n >
` ;
this . container . appendChild ( this . element ) ;
this . canvas = this . element . querySelector ( '.fps-canvas' ) ;
this . textEl = this . element . querySelector ( '.fps-text' ) ;
this . valueEl = this . element . querySelector ( '.fps-value' ) ;
this . bgEl = this . element . querySelector ( '.fps-bg' ) ;
this . element . style . cssText = `
line - height : 1 ;
position : absolute ;
z - index : 1 ;
top : 0 ;
right : 0 ;
` ;
this . canvas . style . cssText = `
position : relative ;
width : 2 em ;
height : 1 em ;
display : block ;
float : left ;
margin - right : . 333 em ;
` ;
this . bgEl . style . cssText = `
position : absolute ;
height : 1 em ;
width : 2 em ;
background : currentcolor ;
opacity : . 1 ;
` ;
this . canvas . width = parseInt ( getComputedStyle ( this . canvas ) . width ) || 1 ;
this . canvas . height = parseInt ( getComputedStyle ( this . canvas ) . height ) || 1 ;
this . context = this . canvas . getContext ( '2d' ) ;
let ctx = this . context ;
let w = this . canvas . width ;
let h = this . canvas . height ;
let count = 0 ;
let lastTime = 0 ;
let values = opts . values || Array ( this . canvas . width ) ;
let updatePeriod = opts . updatePeriod || 1000 ;
let maxFps = opts . maxFps || 100 ;
//enable update routine
let that = this ;
raf ( function measure ( ) {
count ++ ;
let t = now ( ) ;
if ( t - lastTime > updatePeriod ) {
let color = that . color ;
lastTime = t ;
values . push ( count / ( maxFps * updatePeriod * 0.001 ) ) ;
values = values . slice ( - w ) ;
count = 0 ;
ctx . clearRect ( 0 , 0 , w , h ) ;
ctx . fillStyle = getComputedStyle ( that . canvas ) . color ;
for ( let i = w ; i -- ; ) {
let value = values [ i ] ;
if ( value == null ) break ;
ctx . fillRect ( i , h - h * value , 1 , h * value ) ;
}
that . valueEl . innerHTML = ( values [ values . length - 1 ] * maxFps ) . toFixed ( 1 ) ;
}
raf ( measure ) ;
} ) ;
}
2017-02-04 21:26:48 +00:00
} , { "raf" : 13 , "right-now" : 14 } ] , 6 : [ function ( require , module , exports ) {
module . exports = distance
/ * *
* Calculates the euclidian distance between two vec2 ' s
*
* @ param { vec2 } a the first operand
* @ param { vec2 } b the second operand
* @ returns { Number } distance between a and b
* /
function distance ( a , b ) {
var x = b [ 0 ] - a [ 0 ] ,
y = b [ 1 ] - a [ 1 ]
return Math . sqrt ( x * x + y * y )
}
} , { } ] , 7 : [ function ( require , module , exports ) {
( function ( global , factory ) {
if ( typeof define === 'function' && define . amd ) {
define ( [ 'exports' , 'module' ] , factory ) ;
} else if ( typeof exports !== 'undefined' && typeof module !== 'undefined' ) {
factory ( exports , module ) ;
} else {
var mod = {
exports : { }
} ;
factory ( mod . exports , mod ) ;
global . Impetus = mod . exports ;
}
} ) ( this , function ( exports , module ) {
'use strict' ;
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( 'Cannot call a class as a function' ) ; } }
var stopThresholdDefault = 0.3 ;
var bounceDeceleration = 0.04 ;
var bounceAcceleration = 0.11 ;
var Impetus = function Impetus ( _ref ) {
var _ref$source = _ref . source ;
var sourceEl = _ref$source === undefined ? document : _ref$source ;
var updateCallback = _ref . update ;
var _ref$multiplier = _ref . multiplier ;
var multiplier = _ref$multiplier === undefined ? 1 : _ref$multiplier ;
var _ref$friction = _ref . friction ;
var friction = _ref$friction === undefined ? 0.92 : _ref$friction ;
var initialValues = _ref . initialValues ;
var boundX = _ref . boundX ;
var boundY = _ref . boundY ;
var _ref$bounce = _ref . bounce ;
var bounce = _ref$bounce === undefined ? true : _ref$bounce ;
_classCallCheck ( this , Impetus ) ;
var boundXmin , boundXmax , boundYmin , boundYmax , pointerLastX , pointerLastY , pointerCurrentX , pointerCurrentY , pointerId , decVelX , decVelY ;
var targetX = 0 ;
var targetY = 0 ;
var stopThreshold = stopThresholdDefault * multiplier ;
var ticking = false ;
var pointerActive = false ;
var paused = false ;
var decelerating = false ;
var trackingPoints = [ ] ;
/ * *
* Initialize instance
* /
( function init ( ) {
sourceEl = typeof sourceEl === 'string' ? document . querySelector ( sourceEl ) : sourceEl ;
if ( ! sourceEl ) {
throw new Error ( 'IMPETUS: source not found.' ) ;
}
if ( ! updateCallback ) {
throw new Error ( 'IMPETUS: update function not defined.' ) ;
}
if ( initialValues ) {
if ( initialValues [ 0 ] ) {
targetX = initialValues [ 0 ] ;
}
if ( initialValues [ 1 ] ) {
targetY = initialValues [ 1 ] ;
}
callUpdateCallback ( ) ;
}
// Initialize bound values
if ( boundX ) {
boundXmin = boundX [ 0 ] ;
boundXmax = boundX [ 1 ] ;
}
if ( boundY ) {
boundYmin = boundY [ 0 ] ;
boundYmax = boundY [ 1 ] ;
}
sourceEl . addEventListener ( 'touchstart' , onDown ) ;
sourceEl . addEventListener ( 'mousedown' , onDown ) ;
} ) ( ) ;
/ * *
* Disable movement processing
* @ public
* /
this . pause = function ( ) {
pointerActive = false ;
paused = true ;
} ;
/ * *
* Enable movement processing
* @ public
* /
this . resume = function ( ) {
paused = false ;
} ;
/ * *
* Update the current x and y values
* @ public
* @ param { Number } x
* @ param { Number } y
* /
this . setValues = function ( x , y ) {
if ( typeof x === 'number' ) {
targetX = x ;
}
if ( typeof y === 'number' ) {
targetY = y ;
}
} ;
/ * *
* Update the multiplier value
* @ public
* @ param { Number } val
* /
this . setMultiplier = function ( val ) {
multiplier = val ;
stopThreshold = stopThresholdDefault * multiplier ;
} ;
/ * *
* Executes the update function
* /
function callUpdateCallback ( ) {
updateCallback . call ( sourceEl , targetX , targetY ) ;
}
/ * *
* Creates a custom normalized event object from touch and mouse events
* @ param { Event } ev
* @ returns { Object } with x , y , and id properties
* /
function normalizeEvent ( ev ) {
if ( ev . type === 'touchmove' || ev . type === 'touchstart' || ev . type === 'touchend' ) {
var touch = ev . targetTouches [ 0 ] || ev . changedTouches [ 0 ] ;
return {
x : touch . clientX ,
y : touch . clientY ,
id : touch . identifier
} ;
} else {
// mouse events
return {
x : ev . clientX ,
y : ev . clientY ,
id : null
} ;
}
}
/ * *
* Initializes movement tracking
* @ param { Object } ev Normalized event
* /
function onDown ( ev ) {
var event = normalizeEvent ( ev ) ;
if ( ! pointerActive && ! paused ) {
pointerActive = true ;
decelerating = false ;
pointerId = event . id ;
pointerLastX = pointerCurrentX = event . x ;
pointerLastY = pointerCurrentY = event . y ;
trackingPoints = [ ] ;
addTrackingPoint ( pointerLastX , pointerLastY ) ;
document . addEventListener ( 'touchmove' , onMove ) ;
document . addEventListener ( 'touchend' , onUp ) ;
document . addEventListener ( 'touchcancel' , stopTracking ) ;
document . addEventListener ( 'mousemove' , onMove ) ;
document . addEventListener ( 'mouseup' , onUp ) ;
}
}
/ * *
* Handles move events
* @ param { Object } ev Normalized event
* /
function onMove ( ev ) {
ev . preventDefault ( ) ;
var event = normalizeEvent ( ev ) ;
if ( pointerActive && event . id === pointerId ) {
pointerCurrentX = event . x ;
pointerCurrentY = event . y ;
addTrackingPoint ( pointerLastX , pointerLastY ) ;
requestTick ( ) ;
}
}
/ * *
* Handles up / end events
* @ param { Object } ev Normalized event
* /
function onUp ( ev ) {
var event = normalizeEvent ( ev ) ;
if ( pointerActive && event . id === pointerId ) {
stopTracking ( ) ;
}
}
/ * *
* Stops movement tracking , starts animation
* /
function stopTracking ( ) {
pointerActive = false ;
addTrackingPoint ( pointerLastX , pointerLastY ) ;
startDecelAnim ( ) ;
document . removeEventListener ( 'touchmove' , onMove ) ;
document . removeEventListener ( 'touchend' , onUp ) ;
document . removeEventListener ( 'touchcancel' , stopTracking ) ;
document . removeEventListener ( 'mouseup' , onUp ) ;
document . removeEventListener ( 'mousemove' , onMove ) ;
}
/ * *
* Records movement for the last 100 ms
* @ param { number } x
* @ param { number } y [ description ]
* /
function addTrackingPoint ( x , y ) {
var time = Date . now ( ) ;
while ( trackingPoints . length > 0 ) {
if ( time - trackingPoints [ 0 ] . time <= 100 ) {
break ;
}
trackingPoints . shift ( ) ;
}
trackingPoints . push ( { x : x , y : y , time : time } ) ;
}
/ * *
* Calculate new values , call update function
* /
function updateAndRender ( ) {
var pointerChangeX = pointerCurrentX - pointerLastX ;
var pointerChangeY = pointerCurrentY - pointerLastY ;
targetX += pointerChangeX * multiplier ;
targetY += pointerChangeY * multiplier ;
if ( bounce ) {
var diff = checkBounds ( ) ;
if ( diff . x !== 0 ) {
targetX -= pointerChangeX * dragOutOfBoundsMultiplier ( diff . x ) * multiplier ;
}
if ( diff . y !== 0 ) {
targetY -= pointerChangeY * dragOutOfBoundsMultiplier ( diff . y ) * multiplier ;
}
} else {
checkBounds ( true ) ;
}
callUpdateCallback ( ) ;
pointerLastX = pointerCurrentX ;
pointerLastY = pointerCurrentY ;
ticking = false ;
}
/ * *
* Returns a value from around 0.5 to 1 , based on distance
* @ param { Number } val
* /
function dragOutOfBoundsMultiplier ( val ) {
return 0.000005 * Math . pow ( val , 2 ) + 0.0001 * val + 0.55 ;
}
/ * *
* prevents animating faster than current framerate
* /
function requestTick ( ) {
if ( ! ticking ) {
requestAnimFrame ( updateAndRender ) ;
}
ticking = true ;
}
/ * *
* Determine position relative to bounds
* @ param { Boolean } restrict Whether to restrict target to bounds
* /
function checkBounds ( restrict ) {
var xDiff = 0 ;
var yDiff = 0 ;
if ( boundXmin !== undefined && targetX < boundXmin ) {
xDiff = boundXmin - targetX ;
} else if ( boundXmax !== undefined && targetX > boundXmax ) {
xDiff = boundXmax - targetX ;
}
if ( boundYmin !== undefined && targetY < boundYmin ) {
yDiff = boundYmin - targetY ;
} else if ( boundYmax !== undefined && targetY > boundYmax ) {
yDiff = boundYmax - targetY ;
}
if ( restrict ) {
if ( xDiff !== 0 ) {
targetX = xDiff > 0 ? boundXmin : boundXmax ;
}
if ( yDiff !== 0 ) {
targetY = yDiff > 0 ? boundYmin : boundYmax ;
}
}
return {
x : xDiff ,
y : yDiff ,
inBounds : xDiff === 0 && yDiff === 0
} ;
}
/ * *
* Initialize animation of values coming to a stop
* /
function startDecelAnim ( ) {
var firstPoint = trackingPoints [ 0 ] ;
var lastPoint = trackingPoints [ trackingPoints . length - 1 ] ;
var xOffset = lastPoint . x - firstPoint . x ;
var yOffset = lastPoint . y - firstPoint . y ;
var timeOffset = lastPoint . time - firstPoint . time ;
var D = timeOffset / 15 / multiplier ;
decVelX = xOffset / D || 0 ; // prevent NaN
decVelY = yOffset / D || 0 ;
var diff = checkBounds ( ) ;
if ( Math . abs ( decVelX ) > 1 || Math . abs ( decVelY ) > 1 || ! diff . inBounds ) {
decelerating = true ;
requestAnimFrame ( stepDecelAnim ) ;
}
}
/ * *
* Animates values slowing down
* /
function stepDecelAnim ( ) {
if ( ! decelerating ) {
return ;
}
decVelX *= friction ;
decVelY *= friction ;
targetX += decVelX ;
targetY += decVelY ;
var diff = checkBounds ( ) ;
if ( Math . abs ( decVelX ) > stopThreshold || Math . abs ( decVelY ) > stopThreshold || ! diff . inBounds ) {
if ( bounce ) {
var reboundAdjust = 2.5 ;
if ( diff . x !== 0 ) {
if ( diff . x * decVelX <= 0 ) {
decVelX += diff . x * bounceDeceleration ;
} else {
var adjust = diff . x > 0 ? reboundAdjust : - reboundAdjust ;
decVelX = ( diff . x + adjust ) * bounceAcceleration ;
}
}
if ( diff . y !== 0 ) {
if ( diff . y * decVelY <= 0 ) {
decVelY += diff . y * bounceDeceleration ;
} else {
var adjust = diff . y > 0 ? reboundAdjust : - reboundAdjust ;
decVelY = ( diff . y + adjust ) * bounceAcceleration ;
}
}
} else {
if ( diff . x !== 0 ) {
if ( diff . x > 0 ) {
targetX = boundXmin ;
} else {
targetX = boundXmax ;
}
decVelX = 0 ;
}
if ( diff . y !== 0 ) {
if ( diff . y > 0 ) {
targetY = boundYmin ;
} else {
targetY = boundYmax ;
}
decVelY = 0 ;
}
}
callUpdateCallback ( ) ;
requestAnimFrame ( stepDecelAnim ) ;
} else {
decelerating = false ;
}
}
}
/ * *
* @ see http : //www.paulirish.com/2011/requestanimationframe-for-smart-animating/
* /
;
module . exports = Impetus ;
var requestAnimFrame = ( function ( ) {
return window . requestAnimationFrame || window . webkitRequestAnimationFrame || window . mozRequestAnimationFrame || function ( callback ) {
window . setTimeout ( callback , 1000 / 60 ) ;
} ;
} ) ( ) ;
} ) ;
} , { } ] , 8 : [ function ( require , module , exports ) {
var rootPosition = { left : 0 , top : 0 }
module . exports = mouseEventOffset
function mouseEventOffset ( ev , target , out ) {
target = target || ev . currentTarget || ev . srcElement
if ( ! Array . isArray ( out ) ) {
out = [ 0 , 0 ]
}
var cx = ev . clientX || 0
var cy = ev . clientY || 0
var rect = getBoundingClientOffset ( target )
out [ 0 ] = cx - rect . left
out [ 1 ] = cy - rect . top
return out
}
function getBoundingClientOffset ( element ) {
if ( element === window ||
element === document ||
element === document . body ) {
return rootPosition
} else {
return element . getBoundingClientRect ( )
}
}
} , { } ] , 9 : [ function ( require , module , exports ) {
'use strict'
var toPX = require ( 'to-px' )
module . exports = mouseWheelListen
function mouseWheelListen ( element , callback , noScroll ) {
if ( typeof element === 'function' ) {
noScroll = ! ! callback
callback = element
element = window
}
var lineHeight = toPX ( 'ex' , element )
var listener = function ( ev ) {
if ( noScroll ) {
ev . preventDefault ( )
}
var dx = ev . deltaX || 0
var dy = ev . deltaY || 0
var dz = ev . deltaZ || 0
var mode = ev . deltaMode
var scale = 1
switch ( mode ) {
case 1 :
scale = lineHeight
break
case 2 :
scale = window . innerHeight
break
}
dx *= scale
dy *= scale
dz *= scale
if ( dx || dy || dz ) {
return callback ( dx , dy , dz , ev )
}
}
element . addEventListener ( 'wheel' , listener )
return listener
}
} , { "to-px" : 15 } ] , 10 : [ function ( require , module , exports ) {
/ * *
* @ module pan - zoom
*
* Events for pan and zoom
* /
'use strict' ;
const Impetus = require ( 'impetus' ) ;
const wheel = require ( 'mouse-wheel' ) ;
const touchPinch = require ( 'touch-pinch' ) ;
const position = require ( 'touch-position' ) ;
module . exports = panzoom ;
function panzoom ( target , cb ) {
if ( ! target || ! ( cb instanceof Function ) ) return false ;
//enable panning
let pos = position ( {
element : target
} ) ;
let impetus ;
let lastY = 0 , lastX = 0 ;
impetus = new Impetus ( {
source : target ,
update : ( x , y ) => {
let e = {
type : 'mouse' ,
dx : x - lastX , dy : y - lastY , dz : 0 ,
x : pos [ 0 ] , y : pos [ 1 ]
} ;
lastX = x ;
lastY = y ;
cb ( e ) ;
} ,
multiplier : 1 ,
friction : . 75
} ) ;
//enable zooming
wheel ( target , ( dx , dy , dz , e ) => {
e . preventDefault ( ) ;
cb ( {
type : 'mouse' ,
dx : 0 , dy : 0 , dz : dy ,
x : pos [ 0 ] , y : pos [ 1 ]
} ) ;
} ) ;
//mobile pinch zoom
let pinch = touchPinch ( target ) ;
let mult = 2 ;
let initialCoords ;
pinch . on ( 'start' , ( curr ) => {
impetus && impetus . pause ( ) ;
let [ f1 , f2 ] = pinch . fingers ;
initialCoords = [ f2 . position [ 0 ] * . 5 + f1 . position [ 0 ] * . 5 , f2 . position [ 1 ] * . 5 + f1 . position [ 1 ] * . 5 ] ;
} ) ;
pinch . on ( 'end' , ( ) => {
initialCoords = null ;
impetus && impetus . resume ( ) ;
} ) ;
pinch . on ( 'change' , ( curr , prev ) => {
if ( ! pinch . pinching || ! initialCoords ) return ;
cb ( {
type : 'touch' ,
dx : 0 , dy : 0 , dz : - ( curr - prev ) * mult ,
x : initialCoords [ 0 ] , y : initialCoords [ 1 ]
} ) ;
} ) ;
}
} , { "impetus" : 7 , "mouse-wheel" : 9 , "touch-pinch" : 16 , "touch-position" : 17 } ] , 11 : [ function ( require , module , exports ) {
module . exports = function parseUnit ( str , out ) {
if ( ! out )
out = [ 0 , '' ]
str = String ( str )
var num = parseFloat ( str , 10 )
out [ 0 ] = num
out [ 1 ] = str . match ( /[\d.\-\+]*\s*(.*)/ ) [ 1 ] || ''
return out
}
} , { } ] , 12 : [ function ( require , module , exports ) {
2017-01-22 13:05:59 +00:00
( function ( process ) {
// Generated by CoffeeScript 1.7.1
( function ( ) {
var getNanoSeconds , hrtime , loadTime ;
if ( ( typeof performance !== "undefined" && performance !== null ) && performance . now ) {
module . exports = function ( ) {
return performance . now ( ) ;
} ;
} else if ( ( typeof process !== "undefined" && process !== null ) && process . hrtime ) {
module . exports = function ( ) {
return ( getNanoSeconds ( ) - loadTime ) / 1e6 ;
} ;
hrtime = process . hrtime ;
getNanoSeconds = function ( ) {
var hr ;
hr = hrtime ( ) ;
return hr [ 0 ] * 1e9 + hr [ 1 ] ;
} ;
loadTime = getNanoSeconds ( ) ;
} else if ( Date . now ) {
module . exports = function ( ) {
return Date . now ( ) - loadTime ;
} ;
loadTime = Date . now ( ) ;
} else {
module . exports = function ( ) {
return new Date ( ) . getTime ( ) - loadTime ;
} ;
loadTime = new Date ( ) . getTime ( ) ;
}
} ) . call ( this ) ;
} ) . call ( this , require ( '_process' ) )
2017-02-04 21:26:48 +00:00
} , { "_process" : 19 } ] , 13 : [ function ( require , module , exports ) {
2017-01-22 13:05:59 +00:00
( function ( global ) {
var now = require ( 'performance-now' )
, root = typeof window === 'undefined' ? global : window
, vendors = [ 'moz' , 'webkit' ]
, suffix = 'AnimationFrame'
, raf = root [ 'request' + suffix ]
, caf = root [ 'cancel' + suffix ] || root [ 'cancelRequest' + suffix ]
for ( var i = 0 ; ! raf && i < vendors . length ; i ++ ) {
raf = root [ vendors [ i ] + 'Request' + suffix ]
caf = root [ vendors [ i ] + 'Cancel' + suffix ]
|| root [ vendors [ i ] + 'CancelRequest' + suffix ]
}
// Some versions of FF have rAF but not cAF
if ( ! raf || ! caf ) {
var last = 0
, id = 0
, queue = [ ]
, frameDuration = 1000 / 60
raf = function ( callback ) {
if ( queue . length === 0 ) {
var _now = now ( )
, next = Math . max ( 0 , frameDuration - ( _now - last ) )
last = next + _now
setTimeout ( function ( ) {
var cp = queue . slice ( 0 )
// Clear queue here to prevent
// callbacks from appending listeners
// to the current frame's queue
queue . length = 0
for ( var i = 0 ; i < cp . length ; i ++ ) {
if ( ! cp [ i ] . cancelled ) {
try {
cp [ i ] . callback ( last )
} catch ( e ) {
setTimeout ( function ( ) { throw e } , 0 )
}
}
}
} , Math . round ( next ) )
}
queue . push ( {
handle : ++ id ,
callback : callback ,
cancelled : false
} )
return id
}
caf = function ( handle ) {
for ( var i = 0 ; i < queue . length ; i ++ ) {
if ( queue [ i ] . handle === handle ) {
queue [ i ] . cancelled = true
}
}
}
}
module . exports = function ( fn ) {
// Wrap in a new function to prevent
// `cancel` potentially being assigned
// to the native rAF function
return raf . call ( root , fn )
}
module . exports . cancel = function ( ) {
caf . apply ( root , arguments )
}
module . exports . polyfill = function ( ) {
root . requestAnimationFrame = raf
root . cancelAnimationFrame = caf
}
} ) . call ( this , typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : { } )
2017-02-04 21:26:48 +00:00
} , { "performance-now" : 12 } ] , 14 : [ function ( require , module , exports ) {
2017-01-22 13:05:59 +00:00
( function ( global ) {
module . exports =
global . performance &&
global . performance . now ? function now ( ) {
return performance . now ( )
} : Date . now || function now ( ) {
return + new Date
}
} ) . call ( this , typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : { } )
2017-02-04 21:26:48 +00:00
} , { } ] , 15 : [ function ( require , module , exports ) {
'use strict'
var parseUnit = require ( 'parse-unit' )
module . exports = toPX
var PIXELS _PER _INCH = 96
function getPropertyInPX ( element , prop ) {
var parts = parseUnit ( getComputedStyle ( element ) . getPropertyValue ( prop ) )
return parts [ 0 ] * toPX ( parts [ 1 ] , element )
}
//This brutal hack is needed
function getSizeBrutal ( unit , element ) {
var testDIV = document . createElement ( 'div' )
testDIV . style [ 'font-size' ] = '128' + unit
element . appendChild ( testDIV )
var size = getPropertyInPX ( testDIV , 'font-size' ) / 128
element . removeChild ( testDIV )
return size
}
function toPX ( str , element ) {
element = element || document . body
str = ( str || 'px' ) . trim ( ) . toLowerCase ( )
if ( element === window || element === document ) {
element = document . body
}
switch ( str ) {
case '%' : //Ambiguous, not sure if we should use width or height
return element . clientHeight / 100.0
case 'ch' :
case 'ex' :
return getSizeBrutal ( str , element )
case 'em' :
return getPropertyInPX ( element , 'font-size' )
case 'rem' :
return getPropertyInPX ( document . body , 'font-size' )
case 'vw' :
return window . innerWidth / 100
case 'vh' :
return window . innerHeight / 100
case 'vmin' :
return Math . min ( window . innerWidth , window . innerHeight ) / 100
case 'vmax' :
return Math . max ( window . innerWidth , window . innerHeight ) / 100
case 'in' :
return PIXELS _PER _INCH
case 'cm' :
return PIXELS _PER _INCH / 2.54
case 'mm' :
return PIXELS _PER _INCH / 25.4
case 'pt' :
return PIXELS _PER _INCH / 72
case 'pc' :
return PIXELS _PER _INCH / 6
}
return 1
}
} , { "parse-unit" : 11 } ] , 16 : [ function ( require , module , exports ) {
var getDistance = require ( 'gl-vec2/distance' )
var EventEmitter = require ( 'events' ) . EventEmitter
var dprop = require ( 'dprop' )
var eventOffset = require ( 'mouse-event-offset' )
module . exports = touchPinch
function touchPinch ( target ) {
target = target || window
var emitter = new EventEmitter ( )
var fingers = [ null , null ]
var activeCount = 0
var lastDistance = 0
var ended = false
var enabled = false
// some read-only values
Object . defineProperties ( emitter , {
pinching : dprop ( function ( ) {
return activeCount === 2
} ) ,
fingers : dprop ( function ( ) {
return fingers
} )
} )
enable ( )
emitter . enable = enable
emitter . disable = disable
emitter . indexOfTouch = indexOfTouch
return emitter
function indexOfTouch ( touch ) {
var id = touch . identifier
for ( var i = 0 ; i < fingers . length ; i ++ ) {
if ( fingers [ i ] &&
fingers [ i ] . touch &&
fingers [ i ] . touch . identifier === id ) {
return i
}
}
return - 1
}
function enable ( ) {
if ( enabled ) return
enabled = true
target . addEventListener ( 'touchstart' , onTouchStart , false )
target . addEventListener ( 'touchmove' , onTouchMove , false )
target . addEventListener ( 'touchend' , onTouchRemoved , false )
target . addEventListener ( 'touchcancel' , onTouchRemoved , false )
}
function disable ( ) {
if ( ! enabled ) return
enabled = false
target . removeEventListener ( 'touchstart' , onTouchStart , false )
target . removeEventListener ( 'touchmove' , onTouchMove , false )
target . removeEventListener ( 'touchend' , onTouchRemoved , false )
target . removeEventListener ( 'touchcancel' , onTouchRemoved , false )
}
function onTouchStart ( ev ) {
for ( var i = 0 ; i < ev . changedTouches . length ; i ++ ) {
var newTouch = ev . changedTouches [ i ]
var id = newTouch . identifier
var idx = indexOfTouch ( id )
if ( idx === - 1 && activeCount < 2 ) {
var first = activeCount === 0
// newest and previous finger (previous may be undefined)
var newIndex = fingers [ 0 ] ? 1 : 0
var oldIndex = fingers [ 0 ] ? 0 : 1
var newFinger = new Finger ( )
// add to stack
fingers [ newIndex ] = newFinger
activeCount ++
// update touch event & position
newFinger . touch = newTouch
eventOffset ( newTouch , target , newFinger . position )
var oldTouch = fingers [ oldIndex ] ? fingers [ oldIndex ] . touch : undefined
emitter . emit ( 'place' , newTouch , oldTouch )
if ( ! first ) {
var initialDistance = computeDistance ( )
ended = false
emitter . emit ( 'start' , initialDistance )
lastDistance = initialDistance
}
}
}
}
function onTouchMove ( ev ) {
var changed = false
for ( var i = 0 ; i < ev . changedTouches . length ; i ++ ) {
var movedTouch = ev . changedTouches [ i ]
var idx = indexOfTouch ( movedTouch )
if ( idx !== - 1 ) {
changed = true
fingers [ idx ] . touch = movedTouch // avoid caching touches
eventOffset ( movedTouch , target , fingers [ idx ] . position )
}
}
if ( activeCount === 2 && changed ) {
var currentDistance = computeDistance ( )
emitter . emit ( 'change' , currentDistance , lastDistance )
lastDistance = currentDistance
}
}
function onTouchRemoved ( ev ) {
for ( var i = 0 ; i < ev . changedTouches . length ; i ++ ) {
var removed = ev . changedTouches [ i ]
var idx = indexOfTouch ( removed )
if ( idx !== - 1 ) {
fingers [ idx ] = null
activeCount --
var otherIdx = idx === 0 ? 1 : 0
var otherTouch = fingers [ otherIdx ] ? fingers [ otherIdx ] . touch : undefined
emitter . emit ( 'lift' , removed , otherTouch )
}
}
if ( ! ended && activeCount !== 2 ) {
ended = true
emitter . emit ( 'end' )
}
}
function computeDistance ( ) {
if ( activeCount < 2 ) return 0
return getDistance ( fingers [ 0 ] . position , fingers [ 1 ] . position )
}
}
function Finger ( ) {
this . position = [ 0 , 0 ]
this . touch = null
}
} , { "dprop" : 2 , "events" : 18 , "gl-vec2/distance" : 6 , "mouse-event-offset" : 8 } ] , 17 : [ function ( require , module , exports ) {
var offset = require ( 'mouse-event-offset' ) ;
var EventEmitter = require ( 'events' ) . EventEmitter ;
function attach ( opt ) {
opt = opt || { } ;
var element = opt . element || window ;
var emitter = new EventEmitter ( ) ;
var position = opt . position || [ 0 , 0 ] ;
if ( opt . touchstart !== false ) {
element . addEventListener ( 'mousedown' , update , false ) ;
element . addEventListener ( 'touchstart' , updateTouch , false ) ;
}
element . addEventListener ( 'mousemove' , update , false ) ;
element . addEventListener ( 'touchmove' , updateTouch , false ) ;
emitter . position = position ;
emitter . dispose = dispose ;
return emitter ;
function updateTouch ( ev ) {
var touch = ev . targetTouches [ 0 ] ;
update ( touch ) ;
}
function update ( ev ) {
offset ( ev , element , position ) ;
emitter . emit ( 'move' , ev ) ;
}
function dispose ( ) {
element . removeEventListener ( 'mousemove' , update , false ) ;
element . removeEventListener ( 'mousedown' , update , false ) ;
element . removeEventListener ( 'touchmove' , updateTouch , false ) ;
element . removeEventListener ( 'touchstart' , updateTouch , false ) ;
}
}
module . exports = function ( opt ) {
return attach ( opt ) . position ;
} ;
module . exports . emitter = function ( opt ) {
return attach ( opt ) ;
} ;
} , { "events" : 18 , "mouse-event-offset" : 8 } ] , 18 : [ function ( require , module , exports ) {
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
function EventEmitter ( ) {
this . _events = this . _events || { } ;
this . _maxListeners = this . _maxListeners || undefined ;
}
module . exports = EventEmitter ;
// Backwards-compat with node 0.10.x
EventEmitter . EventEmitter = EventEmitter ;
EventEmitter . prototype . _events = undefined ;
EventEmitter . prototype . _maxListeners = undefined ;
// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
EventEmitter . defaultMaxListeners = 10 ;
// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
EventEmitter . prototype . setMaxListeners = function ( n ) {
if ( ! isNumber ( n ) || n < 0 || isNaN ( n ) )
throw TypeError ( 'n must be a positive number' ) ;
this . _maxListeners = n ;
return this ;
} ;
EventEmitter . prototype . emit = function ( type ) {
var er , handler , len , args , i , listeners ;
if ( ! this . _events )
this . _events = { } ;
// If there is no 'error' event listener then throw.
if ( type === 'error' ) {
if ( ! this . _events . error ||
( isObject ( this . _events . error ) && ! this . _events . error . length ) ) {
er = arguments [ 1 ] ;
if ( er instanceof Error ) {
throw er ; // Unhandled 'error' event
} else {
// At least give some kind of context to the user
var err = new Error ( 'Uncaught, unspecified "error" event. (' + er + ')' ) ;
err . context = er ;
throw err ;
}
}
}
handler = this . _events [ type ] ;
if ( isUndefined ( handler ) )
return false ;
if ( isFunction ( handler ) ) {
switch ( arguments . length ) {
// fast cases
case 1 :
handler . call ( this ) ;
break ;
case 2 :
handler . call ( this , arguments [ 1 ] ) ;
break ;
case 3 :
handler . call ( this , arguments [ 1 ] , arguments [ 2 ] ) ;
break ;
// slower
default :
args = Array . prototype . slice . call ( arguments , 1 ) ;
handler . apply ( this , args ) ;
}
} else if ( isObject ( handler ) ) {
args = Array . prototype . slice . call ( arguments , 1 ) ;
listeners = handler . slice ( ) ;
len = listeners . length ;
for ( i = 0 ; i < len ; i ++ )
listeners [ i ] . apply ( this , args ) ;
}
return true ;
} ;
EventEmitter . prototype . addListener = function ( type , listener ) {
var m ;
if ( ! isFunction ( listener ) )
throw TypeError ( 'listener must be a function' ) ;
if ( ! this . _events )
this . _events = { } ;
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if ( this . _events . newListener )
this . emit ( 'newListener' , type ,
isFunction ( listener . listener ) ?
listener . listener : listener ) ;
if ( ! this . _events [ type ] )
// Optimize the case of one listener. Don't need the extra array object.
this . _events [ type ] = listener ;
else if ( isObject ( this . _events [ type ] ) )
// If we've already got an array, just append.
this . _events [ type ] . push ( listener ) ;
else
// Adding the second element, need to change to array.
this . _events [ type ] = [ this . _events [ type ] , listener ] ;
// Check for listener leak
if ( isObject ( this . _events [ type ] ) && ! this . _events [ type ] . warned ) {
if ( ! isUndefined ( this . _maxListeners ) ) {
m = this . _maxListeners ;
} else {
m = EventEmitter . defaultMaxListeners ;
}
if ( m && m > 0 && this . _events [ type ] . length > m ) {
this . _events [ type ] . warned = true ;
console . error ( '(node) warning: possible EventEmitter memory ' +
'leak detected. %d listeners added. ' +
'Use emitter.setMaxListeners() to increase limit.' ,
this . _events [ type ] . length ) ;
if ( typeof console . trace === 'function' ) {
// not supported in IE 10
console . trace ( ) ;
}
}
}
return this ;
} ;
EventEmitter . prototype . on = EventEmitter . prototype . addListener ;
EventEmitter . prototype . once = function ( type , listener ) {
if ( ! isFunction ( listener ) )
throw TypeError ( 'listener must be a function' ) ;
var fired = false ;
function g ( ) {
this . removeListener ( type , g ) ;
if ( ! fired ) {
fired = true ;
listener . apply ( this , arguments ) ;
}
}
g . listener = listener ;
this . on ( type , g ) ;
return this ;
} ;
// emits a 'removeListener' event iff the listener was removed
EventEmitter . prototype . removeListener = function ( type , listener ) {
var list , position , length , i ;
if ( ! isFunction ( listener ) )
throw TypeError ( 'listener must be a function' ) ;
if ( ! this . _events || ! this . _events [ type ] )
return this ;
list = this . _events [ type ] ;
length = list . length ;
position = - 1 ;
if ( list === listener ||
( isFunction ( list . listener ) && list . listener === listener ) ) {
delete this . _events [ type ] ;
if ( this . _events . removeListener )
this . emit ( 'removeListener' , type , listener ) ;
} else if ( isObject ( list ) ) {
for ( i = length ; i -- > 0 ; ) {
if ( list [ i ] === listener ||
( list [ i ] . listener && list [ i ] . listener === listener ) ) {
position = i ;
break ;
}
}
if ( position < 0 )
return this ;
if ( list . length === 1 ) {
list . length = 0 ;
delete this . _events [ type ] ;
} else {
list . splice ( position , 1 ) ;
}
if ( this . _events . removeListener )
this . emit ( 'removeListener' , type , listener ) ;
}
return this ;
} ;
EventEmitter . prototype . removeAllListeners = function ( type ) {
var key , listeners ;
if ( ! this . _events )
return this ;
// not listening for removeListener, no need to emit
if ( ! this . _events . removeListener ) {
if ( arguments . length === 0 )
this . _events = { } ;
else if ( this . _events [ type ] )
delete this . _events [ type ] ;
return this ;
}
// emit removeListener for all listeners on all events
if ( arguments . length === 0 ) {
for ( key in this . _events ) {
if ( key === 'removeListener' ) continue ;
this . removeAllListeners ( key ) ;
}
this . removeAllListeners ( 'removeListener' ) ;
this . _events = { } ;
return this ;
}
listeners = this . _events [ type ] ;
if ( isFunction ( listeners ) ) {
this . removeListener ( type , listeners ) ;
} else if ( listeners ) {
// LIFO order
while ( listeners . length )
this . removeListener ( type , listeners [ listeners . length - 1 ] ) ;
}
delete this . _events [ type ] ;
return this ;
} ;
EventEmitter . prototype . listeners = function ( type ) {
var ret ;
if ( ! this . _events || ! this . _events [ type ] )
ret = [ ] ;
else if ( isFunction ( this . _events [ type ] ) )
ret = [ this . _events [ type ] ] ;
else
ret = this . _events [ type ] . slice ( ) ;
return ret ;
} ;
EventEmitter . prototype . listenerCount = function ( type ) {
if ( this . _events ) {
var evlistener = this . _events [ type ] ;
if ( isFunction ( evlistener ) )
return 1 ;
else if ( evlistener )
return evlistener . length ;
}
return 0 ;
} ;
EventEmitter . listenerCount = function ( emitter , type ) {
return emitter . listenerCount ( type ) ;
} ;
function isFunction ( arg ) {
return typeof arg === 'function' ;
}
function isNumber ( arg ) {
return typeof arg === 'number' ;
}
function isObject ( arg ) {
return typeof arg === 'object' && arg !== null ;
}
function isUndefined ( arg ) {
return arg === void 0 ;
}
} , { } ] , 19 : [ function ( require , module , exports ) {
2017-01-22 13:05:59 +00:00
// shim for using process in browser
var process = module . exports = { } ;
// cached from whatever global is present so that test runners that stub it
// don't break things. But we need to wrap it in a try catch in case it is
// wrapped in strict mode code which doesn't define any globals. It's inside a
// function because try/catches deoptimize in certain engines.
var cachedSetTimeout ;
var cachedClearTimeout ;
function defaultSetTimout ( ) {
throw new Error ( 'setTimeout has not been defined' ) ;
}
function defaultClearTimeout ( ) {
throw new Error ( 'clearTimeout has not been defined' ) ;
}
( function ( ) {
try {
if ( typeof setTimeout === 'function' ) {
cachedSetTimeout = setTimeout ;
} else {
cachedSetTimeout = defaultSetTimout ;
}
} catch ( e ) {
cachedSetTimeout = defaultSetTimout ;
}
try {
if ( typeof clearTimeout === 'function' ) {
cachedClearTimeout = clearTimeout ;
} else {
cachedClearTimeout = defaultClearTimeout ;
}
} catch ( e ) {
cachedClearTimeout = defaultClearTimeout ;
}
} ( ) )
function runTimeout ( fun ) {
if ( cachedSetTimeout === setTimeout ) {
//normal enviroments in sane situations
return setTimeout ( fun , 0 ) ;
}
// if setTimeout wasn't available but was latter defined
if ( ( cachedSetTimeout === defaultSetTimout || ! cachedSetTimeout ) && setTimeout ) {
cachedSetTimeout = setTimeout ;
return setTimeout ( fun , 0 ) ;
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedSetTimeout ( fun , 0 ) ;
} catch ( e ) {
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedSetTimeout . call ( null , fun , 0 ) ;
} catch ( e ) {
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
return cachedSetTimeout . call ( this , fun , 0 ) ;
}
}
}
function runClearTimeout ( marker ) {
if ( cachedClearTimeout === clearTimeout ) {
//normal enviroments in sane situations
return clearTimeout ( marker ) ;
}
// if clearTimeout wasn't available but was latter defined
if ( ( cachedClearTimeout === defaultClearTimeout || ! cachedClearTimeout ) && clearTimeout ) {
cachedClearTimeout = clearTimeout ;
return clearTimeout ( marker ) ;
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedClearTimeout ( marker ) ;
} catch ( e ) {
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedClearTimeout . call ( null , marker ) ;
} catch ( e ) {
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
// Some versions of I.E. have different rules for clearTimeout vs setTimeout
return cachedClearTimeout . call ( this , marker ) ;
}
}
}
var queue = [ ] ;
var draining = false ;
var currentQueue ;
var queueIndex = - 1 ;
function cleanUpNextTick ( ) {
if ( ! draining || ! currentQueue ) {
return ;
}
draining = false ;
if ( currentQueue . length ) {
queue = currentQueue . concat ( queue ) ;
} else {
queueIndex = - 1 ;
}
if ( queue . length ) {
drainQueue ( ) ;
}
}
function drainQueue ( ) {
if ( draining ) {
return ;
}
var timeout = runTimeout ( cleanUpNextTick ) ;
draining = true ;
var len = queue . length ;
while ( len ) {
currentQueue = queue ;
queue = [ ] ;
while ( ++ queueIndex < len ) {
if ( currentQueue ) {
currentQueue [ queueIndex ] . run ( ) ;
}
}
queueIndex = - 1 ;
len = queue . length ;
}
currentQueue = null ;
draining = false ;
runClearTimeout ( timeout ) ;
}
process . nextTick = function ( fun ) {
var args = new Array ( arguments . length - 1 ) ;
if ( arguments . length > 1 ) {
for ( var i = 1 ; i < arguments . length ; i ++ ) {
args [ i - 1 ] = arguments [ i ] ;
}
}
queue . push ( new Item ( fun , args ) ) ;
if ( queue . length === 1 && ! draining ) {
runTimeout ( drainQueue ) ;
}
} ;
// v8 likes predictible objects
function Item ( fun , array ) {
this . fun = fun ;
this . array = array ;
}
Item . prototype . run = function ( ) {
this . fun . apply ( null , this . array ) ;
} ;
process . title = 'browser' ;
process . browser = true ;
process . env = { } ;
process . argv = [ ] ;
process . version = '' ; // empty string to avoid regexp issues
process . versions = { } ;
function noop ( ) { }
process . on = noop ;
process . addListener = noop ;
process . once = noop ;
process . off = noop ;
process . removeListener = noop ;
process . removeAllListeners = noop ;
process . emit = noop ;
process . binding = function ( name ) {
throw new Error ( 'process.binding is not supported' ) ;
} ;
process . cwd = function ( ) { return '/' } ;
process . chdir = function ( dir ) {
throw new Error ( 'process.chdir is not supported' ) ;
} ;
process . umask = function ( ) { return 0 ; } ;
2017-01-21 17:06:19 +00:00
} , { } ] } , { } , [ 1 ] ) ;