2903 lines
87 KiB
JavaScript
2903 lines
87 KiB
JavaScript
var ROS2D = (function (exports, createjs, ROSLIB) {
|
|
'use strict';
|
|
|
|
function _interopNamespace(e) {
|
|
if (e && e.__esModule) return e;
|
|
var n = Object.create(null);
|
|
if (e) {
|
|
Object.keys(e).forEach(function (k) {
|
|
if (k !== 'default') {
|
|
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
Object.defineProperty(n, k, d.get ? d : {
|
|
enumerable: true,
|
|
get: function () { return e[k]; }
|
|
});
|
|
}
|
|
});
|
|
}
|
|
n["default"] = e;
|
|
return Object.freeze(n);
|
|
}
|
|
|
|
var createjs__namespace = /*#__PURE__*/_interopNamespace(createjs);
|
|
var ROSLIB__namespace = /*#__PURE__*/_interopNamespace(ROSLIB);
|
|
|
|
// convert the given global Stage coordinates to ROS coordinates
|
|
createjs__namespace.Stage.prototype.globalToRos = function(x, y) {
|
|
var rosX = (x - this.x) / this.scaleX;
|
|
var rosY = (this.y - y) / this.scaleY;
|
|
return new ROSLIB__namespace.Vector3({
|
|
x : rosX,
|
|
y : rosY
|
|
});
|
|
};
|
|
|
|
// convert the given ROS coordinates to global Stage coordinates
|
|
createjs__namespace.Stage.prototype.rosToGlobal = function(pos) {
|
|
var x = pos.x * this.scaleX + this.x;
|
|
var y = pos.y * this.scaleY + this.y;
|
|
return {
|
|
x : x,
|
|
y : y
|
|
};
|
|
};
|
|
|
|
// convert a ROS quaternion to theta in degrees
|
|
createjs__namespace.Stage.prototype.rosQuaternionToGlobalTheta = function(orientation) {
|
|
// See https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Rotation_matrices
|
|
// here we use [x y z] = R * [1 0 0]
|
|
var q0 = orientation.w;
|
|
var q1 = orientation.x;
|
|
var q2 = orientation.y;
|
|
var q3 = orientation.z;
|
|
// Canvas rotation is clock wise and in degrees
|
|
return -Math.atan2(2 * (q0 * q3 + q1 * q2), 1 - 2 * (q2 * q2 + q3 * q3)) * 180.0 / Math.PI;
|
|
};
|
|
|
|
/**
|
|
* @fileOverview
|
|
* @author Russell Toris - rctoris@wpi.edu
|
|
*/
|
|
|
|
class ImageMap extends createjs__namespace.Bitmap {
|
|
|
|
/**
|
|
* An image map is a PNG image scaled to fit to the dimensions of a OccupancyGrid.
|
|
*
|
|
* @constructor
|
|
* @param options - object with following keys:
|
|
* * message - the occupancy grid map meta data message
|
|
* * image - the image URL to load
|
|
*/
|
|
constructor(options) {
|
|
options = options || {};
|
|
var message = options.message;
|
|
var image = options.image;
|
|
|
|
// create the bitmap
|
|
super(image);
|
|
|
|
// save the metadata we need
|
|
this.pose = new ROSLIB__namespace.Pose({
|
|
position : message.origin.position,
|
|
orientation : message.origin.orientation
|
|
});
|
|
|
|
// set the size
|
|
this.width = message.width;
|
|
this.height = message.height;
|
|
|
|
// change Y direction
|
|
this.y = -this.height * message.resolution;
|
|
|
|
// scale the image
|
|
this.scaleX = message.resolution;
|
|
this.scaleY = message.resolution;
|
|
this.width *= this.scaleX;
|
|
this.height *= this.scaleY;
|
|
|
|
// set the pose
|
|
this.x += this.pose.position.x;
|
|
this.y -= this.pose.position.y;
|
|
};
|
|
}
|
|
|
|
function getDefaultExportFromCjs (x) {
|
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
}
|
|
|
|
var eventemitter2 = {exports: {}};
|
|
|
|
/*!
|
|
* EventEmitter2
|
|
* https://github.com/hij1nx/EventEmitter2
|
|
*
|
|
* Copyright (c) 2013 hij1nx
|
|
* Licensed under the MIT license.
|
|
*/
|
|
eventemitter2.exports;
|
|
|
|
(function (module, exports) {
|
|
!function(undefined$1) {
|
|
var hasOwnProperty= Object.hasOwnProperty;
|
|
var isArray = Array.isArray ? Array.isArray : function _isArray(obj) {
|
|
return Object.prototype.toString.call(obj) === "[object Array]";
|
|
};
|
|
var defaultMaxListeners = 10;
|
|
var nextTickSupported= typeof process=='object' && typeof process.nextTick=='function';
|
|
var symbolsSupported= typeof Symbol==='function';
|
|
var reflectSupported= typeof Reflect === 'object';
|
|
var setImmediateSupported= typeof setImmediate === 'function';
|
|
var _setImmediate= setImmediateSupported ? setImmediate : setTimeout;
|
|
var ownKeys= symbolsSupported? (reflectSupported && typeof Reflect.ownKeys==='function'? Reflect.ownKeys : function(obj){
|
|
var arr= Object.getOwnPropertyNames(obj);
|
|
arr.push.apply(arr, Object.getOwnPropertySymbols(obj));
|
|
return arr;
|
|
}) : Object.keys;
|
|
|
|
function init() {
|
|
this._events = {};
|
|
if (this._conf) {
|
|
configure.call(this, this._conf);
|
|
}
|
|
}
|
|
|
|
function configure(conf) {
|
|
if (conf) {
|
|
this._conf = conf;
|
|
|
|
conf.delimiter && (this.delimiter = conf.delimiter);
|
|
|
|
if(conf.maxListeners!==undefined$1){
|
|
this._maxListeners= conf.maxListeners;
|
|
}
|
|
|
|
conf.wildcard && (this.wildcard = conf.wildcard);
|
|
conf.newListener && (this._newListener = conf.newListener);
|
|
conf.removeListener && (this._removeListener = conf.removeListener);
|
|
conf.verboseMemoryLeak && (this.verboseMemoryLeak = conf.verboseMemoryLeak);
|
|
conf.ignoreErrors && (this.ignoreErrors = conf.ignoreErrors);
|
|
|
|
if (this.wildcard) {
|
|
this.listenerTree = {};
|
|
}
|
|
}
|
|
}
|
|
|
|
function logPossibleMemoryLeak(count, eventName) {
|
|
var errorMsg = '(node) warning: possible EventEmitter memory ' +
|
|
'leak detected. ' + count + ' listeners added. ' +
|
|
'Use emitter.setMaxListeners() to increase limit.';
|
|
|
|
if(this.verboseMemoryLeak){
|
|
errorMsg += ' Event name: ' + eventName + '.';
|
|
}
|
|
|
|
if(typeof process !== 'undefined' && process.emitWarning){
|
|
var e = new Error(errorMsg);
|
|
e.name = 'MaxListenersExceededWarning';
|
|
e.emitter = this;
|
|
e.count = count;
|
|
process.emitWarning(e);
|
|
} else {
|
|
console.error(errorMsg);
|
|
|
|
if (console.trace){
|
|
console.trace();
|
|
}
|
|
}
|
|
}
|
|
|
|
var toArray = function (a, b, c) {
|
|
var n = arguments.length;
|
|
switch (n) {
|
|
case 0:
|
|
return [];
|
|
case 1:
|
|
return [a];
|
|
case 2:
|
|
return [a, b];
|
|
case 3:
|
|
return [a, b, c];
|
|
default:
|
|
var arr = new Array(n);
|
|
while (n--) {
|
|
arr[n] = arguments[n];
|
|
}
|
|
return arr;
|
|
}
|
|
};
|
|
|
|
function toObject(keys, values) {
|
|
var obj = {};
|
|
var key;
|
|
var len = keys.length;
|
|
var valuesCount = values ? value.length : 0;
|
|
for (var i = 0; i < len; i++) {
|
|
key = keys[i];
|
|
obj[key] = i < valuesCount ? values[i] : undefined$1;
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
function TargetObserver(emitter, target, options) {
|
|
this._emitter = emitter;
|
|
this._target = target;
|
|
this._listeners = {};
|
|
this._listenersCount = 0;
|
|
|
|
var on, off;
|
|
|
|
if (options.on || options.off) {
|
|
on = options.on;
|
|
off = options.off;
|
|
}
|
|
|
|
if (target.addEventListener) {
|
|
on = target.addEventListener;
|
|
off = target.removeEventListener;
|
|
} else if (target.addListener) {
|
|
on = target.addListener;
|
|
off = target.removeListener;
|
|
} else if (target.on) {
|
|
on = target.on;
|
|
off = target.off;
|
|
}
|
|
|
|
if (!on && !off) {
|
|
throw Error('target does not implement any known event API');
|
|
}
|
|
|
|
if (typeof on !== 'function') {
|
|
throw TypeError('on method must be a function');
|
|
}
|
|
|
|
if (typeof off !== 'function') {
|
|
throw TypeError('off method must be a function');
|
|
}
|
|
|
|
this._on = on;
|
|
this._off = off;
|
|
|
|
var _observers= emitter._observers;
|
|
if(_observers){
|
|
_observers.push(this);
|
|
}else {
|
|
emitter._observers= [this];
|
|
}
|
|
}
|
|
|
|
Object.assign(TargetObserver.prototype, {
|
|
subscribe: function(event, localEvent, reducer){
|
|
var observer= this;
|
|
var target= this._target;
|
|
var emitter= this._emitter;
|
|
var listeners= this._listeners;
|
|
var handler= function(){
|
|
var args= toArray.apply(null, arguments);
|
|
var eventObj= {
|
|
data: args,
|
|
name: localEvent,
|
|
original: event
|
|
};
|
|
if(reducer){
|
|
var result= reducer.call(target, eventObj);
|
|
if(result!==false){
|
|
emitter.emit.apply(emitter, [eventObj.name].concat(args));
|
|
}
|
|
return;
|
|
}
|
|
emitter.emit.apply(emitter, [localEvent].concat(args));
|
|
};
|
|
|
|
|
|
if(listeners[event]){
|
|
throw Error('Event \'' + event + '\' is already listening');
|
|
}
|
|
|
|
this._listenersCount++;
|
|
|
|
if(emitter._newListener && emitter._removeListener && !observer._onNewListener){
|
|
|
|
this._onNewListener = function (_event) {
|
|
if (_event === localEvent && listeners[event] === null) {
|
|
listeners[event] = handler;
|
|
observer._on.call(target, event, handler);
|
|
}
|
|
};
|
|
|
|
emitter.on('newListener', this._onNewListener);
|
|
|
|
this._onRemoveListener= function(_event){
|
|
if(_event === localEvent && !emitter.hasListeners(_event) && listeners[event]){
|
|
listeners[event]= null;
|
|
observer._off.call(target, event, handler);
|
|
}
|
|
};
|
|
|
|
listeners[event]= null;
|
|
|
|
emitter.on('removeListener', this._onRemoveListener);
|
|
}else {
|
|
listeners[event]= handler;
|
|
observer._on.call(target, event, handler);
|
|
}
|
|
},
|
|
|
|
unsubscribe: function(event){
|
|
var observer= this;
|
|
var listeners= this._listeners;
|
|
var emitter= this._emitter;
|
|
var handler;
|
|
var events;
|
|
var off= this._off;
|
|
var target= this._target;
|
|
var i;
|
|
|
|
if(event && typeof event!=='string'){
|
|
throw TypeError('event must be a string');
|
|
}
|
|
|
|
function clearRefs(){
|
|
if(observer._onNewListener){
|
|
emitter.off('newListener', observer._onNewListener);
|
|
emitter.off('removeListener', observer._onRemoveListener);
|
|
observer._onNewListener= null;
|
|
observer._onRemoveListener= null;
|
|
}
|
|
var index= findTargetIndex.call(emitter, observer);
|
|
emitter._observers.splice(index, 1);
|
|
}
|
|
|
|
if(event){
|
|
handler= listeners[event];
|
|
if(!handler) return;
|
|
off.call(target, event, handler);
|
|
delete listeners[event];
|
|
if(!--this._listenersCount){
|
|
clearRefs();
|
|
}
|
|
}else {
|
|
events= ownKeys(listeners);
|
|
i= events.length;
|
|
while(i-->0){
|
|
event= events[i];
|
|
off.call(target, event, listeners[event]);
|
|
}
|
|
this._listeners= {};
|
|
this._listenersCount= 0;
|
|
clearRefs();
|
|
}
|
|
}
|
|
});
|
|
|
|
function resolveOptions(options, schema, reducers, allowUnknown) {
|
|
var computedOptions = Object.assign({}, schema);
|
|
|
|
if (!options) return computedOptions;
|
|
|
|
if (typeof options !== 'object') {
|
|
throw TypeError('options must be an object')
|
|
}
|
|
|
|
var keys = Object.keys(options);
|
|
var length = keys.length;
|
|
var option, value;
|
|
var reducer;
|
|
|
|
function reject(reason) {
|
|
throw Error('Invalid "' + option + '" option value' + (reason ? '. Reason: ' + reason : ''))
|
|
}
|
|
|
|
for (var i = 0; i < length; i++) {
|
|
option = keys[i];
|
|
if (!allowUnknown && !hasOwnProperty.call(schema, option)) {
|
|
throw Error('Unknown "' + option + '" option');
|
|
}
|
|
value = options[option];
|
|
if (value !== undefined$1) {
|
|
reducer = reducers[option];
|
|
computedOptions[option] = reducer ? reducer(value, reject) : value;
|
|
}
|
|
}
|
|
return computedOptions;
|
|
}
|
|
|
|
function constructorReducer(value, reject) {
|
|
if (typeof value !== 'function' || !value.hasOwnProperty('prototype')) {
|
|
reject('value must be a constructor');
|
|
}
|
|
return value;
|
|
}
|
|
|
|
function makeTypeReducer(types) {
|
|
var message= 'value must be type of ' + types.join('|');
|
|
var len= types.length;
|
|
var firstType= types[0];
|
|
var secondType= types[1];
|
|
|
|
if (len === 1) {
|
|
return function (v, reject) {
|
|
if (typeof v === firstType) {
|
|
return v;
|
|
}
|
|
reject(message);
|
|
}
|
|
}
|
|
|
|
if (len === 2) {
|
|
return function (v, reject) {
|
|
var kind= typeof v;
|
|
if (kind === firstType || kind === secondType) return v;
|
|
reject(message);
|
|
}
|
|
}
|
|
|
|
return function (v, reject) {
|
|
var kind = typeof v;
|
|
var i = len;
|
|
while (i-- > 0) {
|
|
if (kind === types[i]) return v;
|
|
}
|
|
reject(message);
|
|
}
|
|
}
|
|
|
|
var functionReducer= makeTypeReducer(['function']);
|
|
|
|
var objectFunctionReducer= makeTypeReducer(['object', 'function']);
|
|
|
|
function makeCancelablePromise(Promise, executor, options) {
|
|
var isCancelable;
|
|
var callbacks;
|
|
var timer= 0;
|
|
var subscriptionClosed;
|
|
|
|
var promise = new Promise(function (resolve, reject, onCancel) {
|
|
options= resolveOptions(options, {
|
|
timeout: 0,
|
|
overload: false
|
|
}, {
|
|
timeout: function(value, reject){
|
|
value*= 1;
|
|
if (typeof value !== 'number' || value < 0 || !Number.isFinite(value)) {
|
|
reject('timeout must be a positive number');
|
|
}
|
|
return value;
|
|
}
|
|
});
|
|
|
|
isCancelable = !options.overload && typeof Promise.prototype.cancel === 'function' && typeof onCancel === 'function';
|
|
|
|
function cleanup() {
|
|
if (callbacks) {
|
|
callbacks = null;
|
|
}
|
|
if (timer) {
|
|
clearTimeout(timer);
|
|
timer = 0;
|
|
}
|
|
}
|
|
|
|
var _resolve= function(value){
|
|
cleanup();
|
|
resolve(value);
|
|
};
|
|
|
|
var _reject= function(err){
|
|
cleanup();
|
|
reject(err);
|
|
};
|
|
|
|
if (isCancelable) {
|
|
executor(_resolve, _reject, onCancel);
|
|
} else {
|
|
callbacks = [function(reason){
|
|
_reject(reason || Error('canceled'));
|
|
}];
|
|
executor(_resolve, _reject, function (cb) {
|
|
if (subscriptionClosed) {
|
|
throw Error('Unable to subscribe on cancel event asynchronously')
|
|
}
|
|
if (typeof cb !== 'function') {
|
|
throw TypeError('onCancel callback must be a function');
|
|
}
|
|
callbacks.push(cb);
|
|
});
|
|
subscriptionClosed= true;
|
|
}
|
|
|
|
if (options.timeout > 0) {
|
|
timer= setTimeout(function(){
|
|
var reason= Error('timeout');
|
|
reason.code = 'ETIMEDOUT';
|
|
timer= 0;
|
|
promise.cancel(reason);
|
|
reject(reason);
|
|
}, options.timeout);
|
|
}
|
|
});
|
|
|
|
if (!isCancelable) {
|
|
promise.cancel = function (reason) {
|
|
if (!callbacks) {
|
|
return;
|
|
}
|
|
var length = callbacks.length;
|
|
for (var i = 1; i < length; i++) {
|
|
callbacks[i](reason);
|
|
}
|
|
// internal callback to reject the promise
|
|
callbacks[0](reason);
|
|
callbacks = null;
|
|
};
|
|
}
|
|
|
|
return promise;
|
|
}
|
|
|
|
function findTargetIndex(observer) {
|
|
var observers = this._observers;
|
|
if(!observers){
|
|
return -1;
|
|
}
|
|
var len = observers.length;
|
|
for (var i = 0; i < len; i++) {
|
|
if (observers[i]._target === observer) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// Attention, function return type now is array, always !
|
|
// It has zero elements if no any matches found and one or more
|
|
// elements (leafs) if there are matches
|
|
//
|
|
function searchListenerTree(handlers, type, tree, i, typeLength) {
|
|
if (!tree) {
|
|
return null;
|
|
}
|
|
|
|
if (i === 0) {
|
|
var kind = typeof type;
|
|
if (kind === 'string') {
|
|
var ns, n, l = 0, j = 0, delimiter = this.delimiter, dl = delimiter.length;
|
|
if ((n = type.indexOf(delimiter)) !== -1) {
|
|
ns = new Array(5);
|
|
do {
|
|
ns[l++] = type.slice(j, n);
|
|
j = n + dl;
|
|
} while ((n = type.indexOf(delimiter, j)) !== -1);
|
|
|
|
ns[l++] = type.slice(j);
|
|
type = ns;
|
|
typeLength = l;
|
|
} else {
|
|
type = [type];
|
|
typeLength = 1;
|
|
}
|
|
} else if (kind === 'object') {
|
|
typeLength = type.length;
|
|
} else {
|
|
type = [type];
|
|
typeLength = 1;
|
|
}
|
|
}
|
|
|
|
var listeners= null, branch, xTree, xxTree, isolatedBranch, endReached, currentType = type[i],
|
|
nextType = type[i + 1], branches, _listeners;
|
|
|
|
if (i === typeLength) {
|
|
//
|
|
// If at the end of the event(s) list and the tree has listeners
|
|
// invoke those listeners.
|
|
//
|
|
|
|
if(tree._listeners) {
|
|
if (typeof tree._listeners === 'function') {
|
|
handlers && handlers.push(tree._listeners);
|
|
listeners = [tree];
|
|
} else {
|
|
handlers && handlers.push.apply(handlers, tree._listeners);
|
|
listeners = [tree];
|
|
}
|
|
}
|
|
} else {
|
|
|
|
if (currentType === '*') {
|
|
//
|
|
// If the event emitted is '*' at this part
|
|
// or there is a concrete match at this patch
|
|
//
|
|
branches = ownKeys(tree);
|
|
n = branches.length;
|
|
while (n-- > 0) {
|
|
branch = branches[n];
|
|
if (branch !== '_listeners') {
|
|
_listeners = searchListenerTree(handlers, type, tree[branch], i + 1, typeLength);
|
|
if (_listeners) {
|
|
if (listeners) {
|
|
listeners.push.apply(listeners, _listeners);
|
|
} else {
|
|
listeners = _listeners;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return listeners;
|
|
} else if (currentType === '**') {
|
|
endReached = (i + 1 === typeLength || (i + 2 === typeLength && nextType === '*'));
|
|
if (endReached && tree._listeners) {
|
|
// The next element has a _listeners, add it to the handlers.
|
|
listeners = searchListenerTree(handlers, type, tree, typeLength, typeLength);
|
|
}
|
|
|
|
branches = ownKeys(tree);
|
|
n = branches.length;
|
|
while (n-- > 0) {
|
|
branch = branches[n];
|
|
if (branch !== '_listeners') {
|
|
if (branch === '*' || branch === '**') {
|
|
if (tree[branch]._listeners && !endReached) {
|
|
_listeners = searchListenerTree(handlers, type, tree[branch], typeLength, typeLength);
|
|
if (_listeners) {
|
|
if (listeners) {
|
|
listeners.push.apply(listeners, _listeners);
|
|
} else {
|
|
listeners = _listeners;
|
|
}
|
|
}
|
|
}
|
|
_listeners = searchListenerTree(handlers, type, tree[branch], i, typeLength);
|
|
} else if (branch === nextType) {
|
|
_listeners = searchListenerTree(handlers, type, tree[branch], i + 2, typeLength);
|
|
} else {
|
|
// No match on this one, shift into the tree but not in the type array.
|
|
_listeners = searchListenerTree(handlers, type, tree[branch], i, typeLength);
|
|
}
|
|
if (_listeners) {
|
|
if (listeners) {
|
|
listeners.push.apply(listeners, _listeners);
|
|
} else {
|
|
listeners = _listeners;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return listeners;
|
|
} else if (tree[currentType]) {
|
|
listeners = searchListenerTree(handlers, type, tree[currentType], i + 1, typeLength);
|
|
}
|
|
}
|
|
|
|
xTree = tree['*'];
|
|
if (xTree) {
|
|
//
|
|
// If the listener tree will allow any match for this part,
|
|
// then recursively explore all branches of the tree
|
|
//
|
|
searchListenerTree(handlers, type, xTree, i + 1, typeLength);
|
|
}
|
|
|
|
xxTree = tree['**'];
|
|
if (xxTree) {
|
|
if (i < typeLength) {
|
|
if (xxTree._listeners) {
|
|
// If we have a listener on a '**', it will catch all, so add its handler.
|
|
searchListenerTree(handlers, type, xxTree, typeLength, typeLength);
|
|
}
|
|
|
|
// Build arrays of matching next branches and others.
|
|
branches= ownKeys(xxTree);
|
|
n= branches.length;
|
|
while(n-->0){
|
|
branch= branches[n];
|
|
if (branch !== '_listeners') {
|
|
if (branch === nextType) {
|
|
// We know the next element will match, so jump twice.
|
|
searchListenerTree(handlers, type, xxTree[branch], i + 2, typeLength);
|
|
} else if (branch === currentType) {
|
|
// Current node matches, move into the tree.
|
|
searchListenerTree(handlers, type, xxTree[branch], i + 1, typeLength);
|
|
} else {
|
|
isolatedBranch = {};
|
|
isolatedBranch[branch] = xxTree[branch];
|
|
searchListenerTree(handlers, type, {'**': isolatedBranch}, i + 1, typeLength);
|
|
}
|
|
}
|
|
}
|
|
} else if (xxTree._listeners) {
|
|
// We have reached the end and still on a '**'
|
|
searchListenerTree(handlers, type, xxTree, typeLength, typeLength);
|
|
} else if (xxTree['*'] && xxTree['*']._listeners) {
|
|
searchListenerTree(handlers, type, xxTree['*'], typeLength, typeLength);
|
|
}
|
|
}
|
|
|
|
return listeners;
|
|
}
|
|
|
|
function growListenerTree(type, listener, prepend) {
|
|
var len = 0, j = 0, i, delimiter = this.delimiter, dl= delimiter.length, ns;
|
|
|
|
if(typeof type==='string') {
|
|
if ((i = type.indexOf(delimiter)) !== -1) {
|
|
ns = new Array(5);
|
|
do {
|
|
ns[len++] = type.slice(j, i);
|
|
j = i + dl;
|
|
} while ((i = type.indexOf(delimiter, j)) !== -1);
|
|
|
|
ns[len++] = type.slice(j);
|
|
}else {
|
|
ns= [type];
|
|
len= 1;
|
|
}
|
|
}else {
|
|
ns= type;
|
|
len= type.length;
|
|
}
|
|
|
|
//
|
|
// Looks for two consecutive '**', if so, don't add the event at all.
|
|
//
|
|
if (len > 1) {
|
|
for (i = 0; i + 1 < len; i++) {
|
|
if (ns[i] === '**' && ns[i + 1] === '**') {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
var tree = this.listenerTree, name;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
name = ns[i];
|
|
|
|
tree = tree[name] || (tree[name] = {});
|
|
|
|
if (i === len - 1) {
|
|
if (!tree._listeners) {
|
|
tree._listeners = listener;
|
|
} else {
|
|
if (typeof tree._listeners === 'function') {
|
|
tree._listeners = [tree._listeners];
|
|
}
|
|
|
|
if (prepend) {
|
|
tree._listeners.unshift(listener);
|
|
} else {
|
|
tree._listeners.push(listener);
|
|
}
|
|
|
|
if (
|
|
!tree._listeners.warned &&
|
|
this._maxListeners > 0 &&
|
|
tree._listeners.length > this._maxListeners
|
|
) {
|
|
tree._listeners.warned = true;
|
|
logPossibleMemoryLeak.call(this, tree._listeners.length, name);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function collectTreeEvents(tree, events, root, asArray){
|
|
var branches= ownKeys(tree);
|
|
var i= branches.length;
|
|
var branch, branchName, path;
|
|
var hasListeners= tree['_listeners'];
|
|
var isArrayPath;
|
|
|
|
while(i-->0){
|
|
branchName= branches[i];
|
|
|
|
branch= tree[branchName];
|
|
|
|
if(branchName==='_listeners'){
|
|
path= root;
|
|
}else {
|
|
path = root ? root.concat(branchName) : [branchName];
|
|
}
|
|
|
|
isArrayPath= asArray || typeof branchName==='symbol';
|
|
|
|
hasListeners && events.push(isArrayPath? path : path.join(this.delimiter));
|
|
|
|
if(typeof branch==='object'){
|
|
collectTreeEvents.call(this, branch, events, path, isArrayPath);
|
|
}
|
|
}
|
|
|
|
return events;
|
|
}
|
|
|
|
function recursivelyGarbageCollect(root) {
|
|
var keys = ownKeys(root);
|
|
var i= keys.length;
|
|
var obj, key, flag;
|
|
while(i-->0){
|
|
key = keys[i];
|
|
obj = root[key];
|
|
|
|
if(obj){
|
|
flag= true;
|
|
if(key !== '_listeners' && !recursivelyGarbageCollect(obj)){
|
|
delete root[key];
|
|
}
|
|
}
|
|
}
|
|
|
|
return flag;
|
|
}
|
|
|
|
function Listener(emitter, event, listener){
|
|
this.emitter= emitter;
|
|
this.event= event;
|
|
this.listener= listener;
|
|
}
|
|
|
|
Listener.prototype.off= function(){
|
|
this.emitter.off(this.event, this.listener);
|
|
return this;
|
|
};
|
|
|
|
function setupListener(event, listener, options){
|
|
if (options === true) {
|
|
promisify = true;
|
|
} else if (options === false) {
|
|
async = true;
|
|
} else {
|
|
if (!options || typeof options !== 'object') {
|
|
throw TypeError('options should be an object or true');
|
|
}
|
|
var async = options.async;
|
|
var promisify = options.promisify;
|
|
var nextTick = options.nextTick;
|
|
var objectify = options.objectify;
|
|
}
|
|
|
|
if (async || nextTick || promisify) {
|
|
var _listener = listener;
|
|
var _origin = listener._origin || listener;
|
|
|
|
if (nextTick && !nextTickSupported) {
|
|
throw Error('process.nextTick is not supported');
|
|
}
|
|
|
|
if (promisify === undefined$1) {
|
|
promisify = listener.constructor.name === 'AsyncFunction';
|
|
}
|
|
|
|
listener = function () {
|
|
var args = arguments;
|
|
var context = this;
|
|
var event = this.event;
|
|
|
|
return promisify ? (nextTick ? Promise.resolve() : new Promise(function (resolve) {
|
|
_setImmediate(resolve);
|
|
}).then(function () {
|
|
context.event = event;
|
|
return _listener.apply(context, args)
|
|
})) : (nextTick ? process.nextTick : _setImmediate)(function () {
|
|
context.event = event;
|
|
_listener.apply(context, args);
|
|
});
|
|
};
|
|
|
|
listener._async = true;
|
|
listener._origin = _origin;
|
|
}
|
|
|
|
return [listener, objectify? new Listener(this, event, listener): this];
|
|
}
|
|
|
|
function EventEmitter(conf) {
|
|
this._events = {};
|
|
this._newListener = false;
|
|
this._removeListener = false;
|
|
this.verboseMemoryLeak = false;
|
|
configure.call(this, conf);
|
|
}
|
|
|
|
EventEmitter.EventEmitter2 = EventEmitter; // backwards compatibility for exporting EventEmitter property
|
|
|
|
EventEmitter.prototype.listenTo= function(target, events, options){
|
|
if(typeof target!=='object'){
|
|
throw TypeError('target musts be an object');
|
|
}
|
|
|
|
var emitter= this;
|
|
|
|
options = resolveOptions(options, {
|
|
on: undefined$1,
|
|
off: undefined$1,
|
|
reducers: undefined$1
|
|
}, {
|
|
on: functionReducer,
|
|
off: functionReducer,
|
|
reducers: objectFunctionReducer
|
|
});
|
|
|
|
function listen(events){
|
|
if(typeof events!=='object'){
|
|
throw TypeError('events must be an object');
|
|
}
|
|
|
|
var reducers= options.reducers;
|
|
var index= findTargetIndex.call(emitter, target);
|
|
var observer;
|
|
|
|
if(index===-1){
|
|
observer= new TargetObserver(emitter, target, options);
|
|
}else {
|
|
observer= emitter._observers[index];
|
|
}
|
|
|
|
var keys= ownKeys(events);
|
|
var len= keys.length;
|
|
var event;
|
|
var isSingleReducer= typeof reducers==='function';
|
|
|
|
for(var i=0; i<len; i++){
|
|
event= keys[i];
|
|
observer.subscribe(
|
|
event,
|
|
events[event] || event,
|
|
isSingleReducer ? reducers : reducers && reducers[event]
|
|
);
|
|
}
|
|
}
|
|
|
|
isArray(events)?
|
|
listen(toObject(events)) :
|
|
(typeof events==='string'? listen(toObject(events.split(/\s+/))): listen(events));
|
|
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.stopListeningTo = function (target, event) {
|
|
var observers = this._observers;
|
|
|
|
if(!observers){
|
|
return false;
|
|
}
|
|
|
|
var i = observers.length;
|
|
var observer;
|
|
var matched= false;
|
|
|
|
if(target && typeof target!=='object'){
|
|
throw TypeError('target should be an object');
|
|
}
|
|
|
|
while (i-- > 0) {
|
|
observer = observers[i];
|
|
if (!target || observer._target === target) {
|
|
observer.unsubscribe(event);
|
|
matched= true;
|
|
}
|
|
}
|
|
|
|
return matched;
|
|
};
|
|
|
|
// 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.
|
|
//
|
|
// Obviously not all Emitters should be limited to 10. This function allows
|
|
// that to be increased. Set to zero for unlimited.
|
|
|
|
EventEmitter.prototype.delimiter = '.';
|
|
|
|
EventEmitter.prototype.setMaxListeners = function(n) {
|
|
if (n !== undefined$1) {
|
|
this._maxListeners = n;
|
|
if (!this._conf) this._conf = {};
|
|
this._conf.maxListeners = n;
|
|
}
|
|
};
|
|
|
|
EventEmitter.prototype.getMaxListeners = function() {
|
|
return this._maxListeners;
|
|
};
|
|
|
|
EventEmitter.prototype.event = '';
|
|
|
|
EventEmitter.prototype.once = function(event, fn, options) {
|
|
return this._once(event, fn, false, options);
|
|
};
|
|
|
|
EventEmitter.prototype.prependOnceListener = function(event, fn, options) {
|
|
return this._once(event, fn, true, options);
|
|
};
|
|
|
|
EventEmitter.prototype._once = function(event, fn, prepend, options) {
|
|
return this._many(event, 1, fn, prepend, options);
|
|
};
|
|
|
|
EventEmitter.prototype.many = function(event, ttl, fn, options) {
|
|
return this._many(event, ttl, fn, false, options);
|
|
};
|
|
|
|
EventEmitter.prototype.prependMany = function(event, ttl, fn, options) {
|
|
return this._many(event, ttl, fn, true, options);
|
|
};
|
|
|
|
EventEmitter.prototype._many = function(event, ttl, fn, prepend, options) {
|
|
var self = this;
|
|
|
|
if (typeof fn !== 'function') {
|
|
throw new Error('many only accepts instances of Function');
|
|
}
|
|
|
|
function listener() {
|
|
if (--ttl === 0) {
|
|
self.off(event, listener);
|
|
}
|
|
return fn.apply(this, arguments);
|
|
}
|
|
|
|
listener._origin = fn;
|
|
|
|
return this._on(event, listener, prepend, options);
|
|
};
|
|
|
|
EventEmitter.prototype.emit = function() {
|
|
if (!this._events && !this._all) {
|
|
return false;
|
|
}
|
|
|
|
this._events || init.call(this);
|
|
|
|
var type = arguments[0], ns, wildcard= this.wildcard;
|
|
var args,l,i,j, containsSymbol;
|
|
|
|
if (type === 'newListener' && !this._newListener) {
|
|
if (!this._events.newListener) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (wildcard) {
|
|
ns= type;
|
|
if(type!=='newListener' && type!=='removeListener'){
|
|
if (typeof type === 'object') {
|
|
l = type.length;
|
|
if (symbolsSupported) {
|
|
for (i = 0; i < l; i++) {
|
|
if (typeof type[i] === 'symbol') {
|
|
containsSymbol = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!containsSymbol) {
|
|
type = type.join(this.delimiter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var al = arguments.length;
|
|
var handler;
|
|
|
|
if (this._all && this._all.length) {
|
|
handler = this._all.slice();
|
|
|
|
for (i = 0, l = handler.length; i < l; i++) {
|
|
this.event = type;
|
|
switch (al) {
|
|
case 1:
|
|
handler[i].call(this, type);
|
|
break;
|
|
case 2:
|
|
handler[i].call(this, type, arguments[1]);
|
|
break;
|
|
case 3:
|
|
handler[i].call(this, type, arguments[1], arguments[2]);
|
|
break;
|
|
default:
|
|
handler[i].apply(this, arguments);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (wildcard) {
|
|
handler = [];
|
|
searchListenerTree.call(this, handler, ns, this.listenerTree, 0, l);
|
|
} else {
|
|
handler = this._events[type];
|
|
if (typeof handler === 'function') {
|
|
this.event = type;
|
|
switch (al) {
|
|
case 1:
|
|
handler.call(this);
|
|
break;
|
|
case 2:
|
|
handler.call(this, arguments[1]);
|
|
break;
|
|
case 3:
|
|
handler.call(this, arguments[1], arguments[2]);
|
|
break;
|
|
default:
|
|
args = new Array(al - 1);
|
|
for (j = 1; j < al; j++) args[j - 1] = arguments[j];
|
|
handler.apply(this, args);
|
|
}
|
|
return true;
|
|
} else if (handler) {
|
|
// need to make copy of handlers because list can change in the middle
|
|
// of emit call
|
|
handler = handler.slice();
|
|
}
|
|
}
|
|
|
|
if (handler && handler.length) {
|
|
if (al > 3) {
|
|
args = new Array(al - 1);
|
|
for (j = 1; j < al; j++) args[j - 1] = arguments[j];
|
|
}
|
|
for (i = 0, l = handler.length; i < l; i++) {
|
|
this.event = type;
|
|
switch (al) {
|
|
case 1:
|
|
handler[i].call(this);
|
|
break;
|
|
case 2:
|
|
handler[i].call(this, arguments[1]);
|
|
break;
|
|
case 3:
|
|
handler[i].call(this, arguments[1], arguments[2]);
|
|
break;
|
|
default:
|
|
handler[i].apply(this, args);
|
|
}
|
|
}
|
|
return true;
|
|
} else if (!this.ignoreErrors && !this._all && type === 'error') {
|
|
if (arguments[1] instanceof Error) {
|
|
throw arguments[1]; // Unhandled 'error' event
|
|
} else {
|
|
throw new Error("Uncaught, unspecified 'error' event.");
|
|
}
|
|
}
|
|
|
|
return !!this._all;
|
|
};
|
|
|
|
EventEmitter.prototype.emitAsync = function() {
|
|
if (!this._events && !this._all) {
|
|
return false;
|
|
}
|
|
|
|
this._events || init.call(this);
|
|
|
|
var type = arguments[0], wildcard= this.wildcard, ns, containsSymbol;
|
|
var args,l,i,j;
|
|
|
|
if (type === 'newListener' && !this._newListener) {
|
|
if (!this._events.newListener) { return Promise.resolve([false]); }
|
|
}
|
|
|
|
if (wildcard) {
|
|
ns= type;
|
|
if(type!=='newListener' && type!=='removeListener'){
|
|
if (typeof type === 'object') {
|
|
l = type.length;
|
|
if (symbolsSupported) {
|
|
for (i = 0; i < l; i++) {
|
|
if (typeof type[i] === 'symbol') {
|
|
containsSymbol = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!containsSymbol) {
|
|
type = type.join(this.delimiter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var promises= [];
|
|
|
|
var al = arguments.length;
|
|
var handler;
|
|
|
|
if (this._all) {
|
|
for (i = 0, l = this._all.length; i < l; i++) {
|
|
this.event = type;
|
|
switch (al) {
|
|
case 1:
|
|
promises.push(this._all[i].call(this, type));
|
|
break;
|
|
case 2:
|
|
promises.push(this._all[i].call(this, type, arguments[1]));
|
|
break;
|
|
case 3:
|
|
promises.push(this._all[i].call(this, type, arguments[1], arguments[2]));
|
|
break;
|
|
default:
|
|
promises.push(this._all[i].apply(this, arguments));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (wildcard) {
|
|
handler = [];
|
|
searchListenerTree.call(this, handler, ns, this.listenerTree, 0);
|
|
} else {
|
|
handler = this._events[type];
|
|
}
|
|
|
|
if (typeof handler === 'function') {
|
|
this.event = type;
|
|
switch (al) {
|
|
case 1:
|
|
promises.push(handler.call(this));
|
|
break;
|
|
case 2:
|
|
promises.push(handler.call(this, arguments[1]));
|
|
break;
|
|
case 3:
|
|
promises.push(handler.call(this, arguments[1], arguments[2]));
|
|
break;
|
|
default:
|
|
args = new Array(al - 1);
|
|
for (j = 1; j < al; j++) args[j - 1] = arguments[j];
|
|
promises.push(handler.apply(this, args));
|
|
}
|
|
} else if (handler && handler.length) {
|
|
handler = handler.slice();
|
|
if (al > 3) {
|
|
args = new Array(al - 1);
|
|
for (j = 1; j < al; j++) args[j - 1] = arguments[j];
|
|
}
|
|
for (i = 0, l = handler.length; i < l; i++) {
|
|
this.event = type;
|
|
switch (al) {
|
|
case 1:
|
|
promises.push(handler[i].call(this));
|
|
break;
|
|
case 2:
|
|
promises.push(handler[i].call(this, arguments[1]));
|
|
break;
|
|
case 3:
|
|
promises.push(handler[i].call(this, arguments[1], arguments[2]));
|
|
break;
|
|
default:
|
|
promises.push(handler[i].apply(this, args));
|
|
}
|
|
}
|
|
} else if (!this.ignoreErrors && !this._all && type === 'error') {
|
|
if (arguments[1] instanceof Error) {
|
|
return Promise.reject(arguments[1]); // Unhandled 'error' event
|
|
} else {
|
|
return Promise.reject("Uncaught, unspecified 'error' event.");
|
|
}
|
|
}
|
|
|
|
return Promise.all(promises);
|
|
};
|
|
|
|
EventEmitter.prototype.on = function(type, listener, options) {
|
|
return this._on(type, listener, false, options);
|
|
};
|
|
|
|
EventEmitter.prototype.prependListener = function(type, listener, options) {
|
|
return this._on(type, listener, true, options);
|
|
};
|
|
|
|
EventEmitter.prototype.onAny = function(fn) {
|
|
return this._onAny(fn, false);
|
|
};
|
|
|
|
EventEmitter.prototype.prependAny = function(fn) {
|
|
return this._onAny(fn, true);
|
|
};
|
|
|
|
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
|
|
|
|
EventEmitter.prototype._onAny = function(fn, prepend){
|
|
if (typeof fn !== 'function') {
|
|
throw new Error('onAny only accepts instances of Function');
|
|
}
|
|
|
|
if (!this._all) {
|
|
this._all = [];
|
|
}
|
|
|
|
// Add the function to the event listener collection.
|
|
if(prepend){
|
|
this._all.unshift(fn);
|
|
}else {
|
|
this._all.push(fn);
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype._on = function(type, listener, prepend, options) {
|
|
if (typeof type === 'function') {
|
|
this._onAny(type, listener);
|
|
return this;
|
|
}
|
|
|
|
if (typeof listener !== 'function') {
|
|
throw new Error('on only accepts instances of Function');
|
|
}
|
|
this._events || init.call(this);
|
|
|
|
var returnValue= this, temp;
|
|
|
|
if (options !== undefined$1) {
|
|
temp = setupListener.call(this, type, listener, options);
|
|
listener = temp[0];
|
|
returnValue = temp[1];
|
|
}
|
|
|
|
// To avoid recursion in the case that type == "newListeners"! Before
|
|
// adding it to the listeners, first emit "newListeners".
|
|
if (this._newListener) {
|
|
this.emit('newListener', type, listener);
|
|
}
|
|
|
|
if (this.wildcard) {
|
|
growListenerTree.call(this, type, listener, prepend);
|
|
return returnValue;
|
|
}
|
|
|
|
if (!this._events[type]) {
|
|
// Optimize the case of one listener. Don't need the extra array object.
|
|
this._events[type] = listener;
|
|
} else {
|
|
if (typeof this._events[type] === 'function') {
|
|
// Change to array.
|
|
this._events[type] = [this._events[type]];
|
|
}
|
|
|
|
// If we've already got an array, just add
|
|
if(prepend){
|
|
this._events[type].unshift(listener);
|
|
}else {
|
|
this._events[type].push(listener);
|
|
}
|
|
|
|
// Check for listener leak
|
|
if (
|
|
!this._events[type].warned &&
|
|
this._maxListeners > 0 &&
|
|
this._events[type].length > this._maxListeners
|
|
) {
|
|
this._events[type].warned = true;
|
|
logPossibleMemoryLeak.call(this, this._events[type].length, type);
|
|
}
|
|
}
|
|
|
|
return returnValue;
|
|
};
|
|
|
|
EventEmitter.prototype.off = function(type, listener) {
|
|
if (typeof listener !== 'function') {
|
|
throw new Error('removeListener only takes instances of Function');
|
|
}
|
|
|
|
var handlers,leafs=[];
|
|
|
|
if(this.wildcard) {
|
|
var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
|
|
leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0);
|
|
if(!leafs) return this;
|
|
} else {
|
|
// does not use listeners(), so no side effect of creating _events[type]
|
|
if (!this._events[type]) return this;
|
|
handlers = this._events[type];
|
|
leafs.push({_listeners:handlers});
|
|
}
|
|
|
|
for (var iLeaf=0; iLeaf<leafs.length; iLeaf++) {
|
|
var leaf = leafs[iLeaf];
|
|
handlers = leaf._listeners;
|
|
if (isArray(handlers)) {
|
|
|
|
var position = -1;
|
|
|
|
for (var i = 0, length = handlers.length; i < length; i++) {
|
|
if (handlers[i] === listener ||
|
|
(handlers[i].listener && handlers[i].listener === listener) ||
|
|
(handlers[i]._origin && handlers[i]._origin === listener)) {
|
|
position = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (position < 0) {
|
|
continue;
|
|
}
|
|
|
|
if(this.wildcard) {
|
|
leaf._listeners.splice(position, 1);
|
|
}
|
|
else {
|
|
this._events[type].splice(position, 1);
|
|
}
|
|
|
|
if (handlers.length === 0) {
|
|
if(this.wildcard) {
|
|
delete leaf._listeners;
|
|
}
|
|
else {
|
|
delete this._events[type];
|
|
}
|
|
}
|
|
if (this._removeListener)
|
|
this.emit("removeListener", type, listener);
|
|
|
|
return this;
|
|
}
|
|
else if (handlers === listener ||
|
|
(handlers.listener && handlers.listener === listener) ||
|
|
(handlers._origin && handlers._origin === listener)) {
|
|
if(this.wildcard) {
|
|
delete leaf._listeners;
|
|
}
|
|
else {
|
|
delete this._events[type];
|
|
}
|
|
if (this._removeListener)
|
|
this.emit("removeListener", type, listener);
|
|
}
|
|
}
|
|
|
|
this.listenerTree && recursivelyGarbageCollect(this.listenerTree);
|
|
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.offAny = function(fn) {
|
|
var i = 0, l = 0, fns;
|
|
if (fn && this._all && this._all.length > 0) {
|
|
fns = this._all;
|
|
for(i = 0, l = fns.length; i < l; i++) {
|
|
if(fn === fns[i]) {
|
|
fns.splice(i, 1);
|
|
if (this._removeListener)
|
|
this.emit("removeListenerAny", fn);
|
|
return this;
|
|
}
|
|
}
|
|
} else {
|
|
fns = this._all;
|
|
if (this._removeListener) {
|
|
for(i = 0, l = fns.length; i < l; i++)
|
|
this.emit("removeListenerAny", fns[i]);
|
|
}
|
|
this._all = [];
|
|
}
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.removeListener = EventEmitter.prototype.off;
|
|
|
|
EventEmitter.prototype.removeAllListeners = function (type) {
|
|
if (type === undefined$1) {
|
|
!this._events || init.call(this);
|
|
return this;
|
|
}
|
|
|
|
if (this.wildcard) {
|
|
var leafs = searchListenerTree.call(this, null, type, this.listenerTree, 0), leaf, i;
|
|
if (!leafs) return this;
|
|
for (i = 0; i < leafs.length; i++) {
|
|
leaf = leafs[i];
|
|
leaf._listeners = null;
|
|
}
|
|
this.listenerTree && recursivelyGarbageCollect(this.listenerTree);
|
|
} else if (this._events) {
|
|
this._events[type] = null;
|
|
}
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.listeners = function (type) {
|
|
var _events = this._events;
|
|
var keys, listeners, allListeners;
|
|
var i;
|
|
var listenerTree;
|
|
|
|
if (type === undefined$1) {
|
|
if (this.wildcard) {
|
|
throw Error('event name required for wildcard emitter');
|
|
}
|
|
|
|
if (!_events) {
|
|
return [];
|
|
}
|
|
|
|
keys = ownKeys(_events);
|
|
i = keys.length;
|
|
allListeners = [];
|
|
while (i-- > 0) {
|
|
listeners = _events[keys[i]];
|
|
if (typeof listeners === 'function') {
|
|
allListeners.push(listeners);
|
|
} else {
|
|
allListeners.push.apply(allListeners, listeners);
|
|
}
|
|
}
|
|
return allListeners;
|
|
} else {
|
|
if (this.wildcard) {
|
|
listenerTree= this.listenerTree;
|
|
if(!listenerTree) return [];
|
|
var handlers = [];
|
|
var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
|
|
searchListenerTree.call(this, handlers, ns, listenerTree, 0);
|
|
return handlers;
|
|
}
|
|
|
|
if (!_events) {
|
|
return [];
|
|
}
|
|
|
|
listeners = _events[type];
|
|
|
|
if (!listeners) {
|
|
return [];
|
|
}
|
|
return typeof listeners === 'function' ? [listeners] : listeners;
|
|
}
|
|
};
|
|
|
|
EventEmitter.prototype.eventNames = function(nsAsArray){
|
|
var _events= this._events;
|
|
return this.wildcard? collectTreeEvents.call(this, this.listenerTree, [], null, nsAsArray) : (_events? ownKeys(_events) : []);
|
|
};
|
|
|
|
EventEmitter.prototype.listenerCount = function(type) {
|
|
return this.listeners(type).length;
|
|
};
|
|
|
|
EventEmitter.prototype.hasListeners = function (type) {
|
|
if (this.wildcard) {
|
|
var handlers = [];
|
|
var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
|
|
searchListenerTree.call(this, handlers, ns, this.listenerTree, 0);
|
|
return handlers.length > 0;
|
|
}
|
|
|
|
var _events = this._events;
|
|
var _all = this._all;
|
|
|
|
return !!(_all && _all.length || _events && (type === undefined$1 ? ownKeys(_events).length : _events[type]));
|
|
};
|
|
|
|
EventEmitter.prototype.listenersAny = function() {
|
|
|
|
if(this._all) {
|
|
return this._all;
|
|
}
|
|
else {
|
|
return [];
|
|
}
|
|
|
|
};
|
|
|
|
EventEmitter.prototype.waitFor = function (event, options) {
|
|
var self = this;
|
|
var type = typeof options;
|
|
if (type === 'number') {
|
|
options = {timeout: options};
|
|
} else if (type === 'function') {
|
|
options = {filter: options};
|
|
}
|
|
|
|
options= resolveOptions(options, {
|
|
timeout: 0,
|
|
filter: undefined$1,
|
|
handleError: false,
|
|
Promise: Promise,
|
|
overload: false
|
|
}, {
|
|
filter: functionReducer,
|
|
Promise: constructorReducer
|
|
});
|
|
|
|
return makeCancelablePromise(options.Promise, function (resolve, reject, onCancel) {
|
|
function listener() {
|
|
var filter= options.filter;
|
|
if (filter && !filter.apply(self, arguments)) {
|
|
return;
|
|
}
|
|
self.off(event, listener);
|
|
if (options.handleError) {
|
|
var err = arguments[0];
|
|
err ? reject(err) : resolve(toArray.apply(null, arguments).slice(1));
|
|
} else {
|
|
resolve(toArray.apply(null, arguments));
|
|
}
|
|
}
|
|
|
|
onCancel(function(){
|
|
self.off(event, listener);
|
|
});
|
|
|
|
self._on(event, listener, false);
|
|
}, {
|
|
timeout: options.timeout,
|
|
overload: options.overload
|
|
})
|
|
};
|
|
|
|
function once(emitter, name, options) {
|
|
options= resolveOptions(options, {
|
|
Promise: Promise,
|
|
timeout: 0,
|
|
overload: false
|
|
}, {
|
|
Promise: constructorReducer
|
|
});
|
|
|
|
var _Promise= options.Promise;
|
|
|
|
return makeCancelablePromise(_Promise, function(resolve, reject, onCancel){
|
|
var handler;
|
|
if (typeof emitter.addEventListener === 'function') {
|
|
handler= function () {
|
|
resolve(toArray.apply(null, arguments));
|
|
};
|
|
|
|
onCancel(function(){
|
|
emitter.removeEventListener(name, handler);
|
|
});
|
|
|
|
emitter.addEventListener(
|
|
name,
|
|
handler,
|
|
{once: true}
|
|
);
|
|
return;
|
|
}
|
|
|
|
var eventListener = function(){
|
|
errorListener && emitter.removeListener('error', errorListener);
|
|
resolve(toArray.apply(null, arguments));
|
|
};
|
|
|
|
var errorListener;
|
|
|
|
if (name !== 'error') {
|
|
errorListener = function (err){
|
|
emitter.removeListener(name, eventListener);
|
|
reject(err);
|
|
};
|
|
|
|
emitter.once('error', errorListener);
|
|
}
|
|
|
|
onCancel(function(){
|
|
errorListener && emitter.removeListener('error', errorListener);
|
|
emitter.removeListener(name, eventListener);
|
|
});
|
|
|
|
emitter.once(name, eventListener);
|
|
}, {
|
|
timeout: options.timeout,
|
|
overload: options.overload
|
|
});
|
|
}
|
|
|
|
var prototype= EventEmitter.prototype;
|
|
|
|
Object.defineProperties(EventEmitter, {
|
|
defaultMaxListeners: {
|
|
get: function () {
|
|
return prototype._maxListeners;
|
|
},
|
|
set: function (n) {
|
|
if (typeof n !== 'number' || n < 0 || Number.isNaN(n)) {
|
|
throw TypeError('n must be a non-negative number')
|
|
}
|
|
prototype._maxListeners = n;
|
|
},
|
|
enumerable: true
|
|
},
|
|
once: {
|
|
value: once,
|
|
writable: true,
|
|
configurable: true
|
|
}
|
|
});
|
|
|
|
Object.defineProperties(prototype, {
|
|
_maxListeners: {
|
|
value: defaultMaxListeners,
|
|
writable: true,
|
|
configurable: true
|
|
},
|
|
_observers: {value: null, writable: true, configurable: true}
|
|
});
|
|
|
|
if (typeof undefined$1 === 'function' && undefined$1.amd) {
|
|
// AMD. Register as an anonymous module.
|
|
undefined$1(function() {
|
|
return EventEmitter;
|
|
});
|
|
} else {
|
|
// CommonJS
|
|
module.exports = EventEmitter;
|
|
}
|
|
}();
|
|
} (eventemitter2, eventemitter2.exports));
|
|
|
|
var eventemitter2Exports = eventemitter2.exports;
|
|
var EventEmitter2 = /*@__PURE__*/getDefaultExportFromCjs(eventemitter2Exports);
|
|
|
|
/**
|
|
* @fileOverview
|
|
* @author Russell Toris - rctoris@wpi.edu
|
|
*/
|
|
|
|
class ImageMapClient extends EventEmitter2 {
|
|
|
|
/**
|
|
* A image map is a PNG image scaled to fit to the dimensions of a OccupancyGrid.
|
|
*
|
|
* Emits the following events:
|
|
* * 'change' - there was an update or change in the map
|
|
*
|
|
* @constructor
|
|
* @param options - object with following keys:
|
|
* * ros - the ROSLIB.Ros connection handle
|
|
* * topic (optional) - the map meta data topic to listen to
|
|
* * image - the image URL to load
|
|
* * rootObject (optional) - the root object to add this marker to
|
|
*/
|
|
constructor(options) {
|
|
super();
|
|
options = options || {};
|
|
var ros = options.ros;
|
|
var topic = options.topic || '/map_metadata';
|
|
this.image = options.image;
|
|
this.rootObject = options.rootObject || new createjs__namespace.Container();
|
|
|
|
// create an empty shape to start with
|
|
this.currentImage = new createjs__namespace.Shape();
|
|
|
|
// subscribe to the topic
|
|
var rosTopic = new ROSLIB__namespace.Topic({
|
|
ros : ros,
|
|
name : topic,
|
|
messageType : 'nav_msgs/MapMetaData'
|
|
});
|
|
|
|
rosTopic.subscribe(function(message) {
|
|
// we only need this once
|
|
rosTopic.unsubscribe();
|
|
|
|
// create the image
|
|
this.currentImage = new ImageMap({
|
|
message : message,
|
|
image : this.image
|
|
});
|
|
this.rootObject.addChild(this.currentImage);
|
|
|
|
this.emit('change');
|
|
}.bind(this));
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @fileOverview
|
|
* @author Russell Toris - rctoris@wpi.edu
|
|
*/
|
|
|
|
class OccupancyGrid extends createjs__namespace.Bitmap {
|
|
|
|
/**
|
|
* An OccupancyGrid can convert a ROS occupancy grid message into a createjs Bitmap object.
|
|
*
|
|
* @constructor
|
|
* @param options - object with following keys:
|
|
* * message - the occupancy grid message
|
|
*/
|
|
constructor(options) {
|
|
options = options || {};
|
|
var message = options.message;
|
|
|
|
// internal drawing canvas
|
|
var canvas = document.createElement('canvas');
|
|
var context = canvas.getContext('2d');
|
|
|
|
// set the size
|
|
canvas.width = message.info.width;
|
|
canvas.height = message.info.height;
|
|
|
|
var imageData = context.createImageData(canvas.width, canvas.height);
|
|
for ( var row = 0; row < canvas.height; row++) {
|
|
for ( var col = 0; col < canvas.width; col++) {
|
|
// determine the index into the map data
|
|
var mapI = col + ((canvas.height - row - 1) * canvas.width);
|
|
// determine the value
|
|
var data = message.data[mapI];
|
|
var val;
|
|
if (data === 100) {
|
|
val = 0;
|
|
} else if (data === 0) {
|
|
val = 255;
|
|
} else {
|
|
val = 127;
|
|
}
|
|
|
|
// determine the index into the image data array
|
|
var i = (col + (row * canvas.width)) * 4;
|
|
// r
|
|
imageData.data[i] = val;
|
|
// g
|
|
imageData.data[++i] = val;
|
|
// b
|
|
imageData.data[++i] = val;
|
|
// a
|
|
imageData.data[++i] = 255;
|
|
}
|
|
}
|
|
context.putImageData(imageData, 0, 0);
|
|
|
|
// create the bitmap
|
|
super(canvas);
|
|
|
|
this.width = canvas.width;
|
|
this.height = canvas.height;
|
|
|
|
// save the metadata we need
|
|
this.pose = new ROSLIB__namespace.Pose({
|
|
position : message.info.origin.position,
|
|
orientation : message.info.origin.orientation
|
|
});
|
|
|
|
// change Y direction
|
|
this.y = -this.height * message.info.resolution;
|
|
|
|
// scale the image
|
|
this.scaleX = message.info.resolution;
|
|
this.scaleY = message.info.resolution;
|
|
this.width *= this.scaleX;
|
|
this.height *= this.scaleY;
|
|
|
|
// set the pose
|
|
this.x += this.pose.position.x;
|
|
this.y -= this.pose.position.y;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @fileOverview
|
|
* @author Raffaello Bonghi - raffaello.bonghi@officinerobotiche.it
|
|
*/
|
|
|
|
class Grid extends createjs__namespace.Shape {
|
|
|
|
/**
|
|
* A Grid object draw in map.
|
|
*
|
|
* @constructor
|
|
* @param options - object with following keys:
|
|
* * size (optional) - the size of the grid
|
|
* * cellSize (optional) - the cell size of map
|
|
* * lineWidth (optional) - the width of the lines in the grid
|
|
*/
|
|
constructor(options) {
|
|
options = options || {};
|
|
var size = options.size || 10;
|
|
var cellSize = options.cellSize || 0.1;
|
|
var lineWidth = options.lineWidth || 0.001;
|
|
// draw the arrow
|
|
var graphics = new createjs__namespace.Graphics();
|
|
// line width
|
|
graphics.setStrokeStyle(lineWidth*5);
|
|
graphics.beginStroke(createjs__namespace.Graphics.getRGB(0, 0, 0));
|
|
graphics.beginFill(createjs__namespace.Graphics.getRGB(255, 0, 0));
|
|
graphics.moveTo(-size*cellSize, 0);
|
|
graphics.lineTo(size*cellSize, 0);
|
|
graphics.moveTo(0, -size*cellSize);
|
|
graphics.lineTo(0, size*cellSize);
|
|
graphics.endFill();
|
|
graphics.endStroke();
|
|
|
|
graphics.setStrokeStyle(lineWidth);
|
|
graphics.beginStroke(createjs__namespace.Graphics.getRGB(0, 0, 0));
|
|
graphics.beginFill(createjs__namespace.Graphics.getRGB(255, 0, 0));
|
|
for (var i = -size; i <= size; i++) {
|
|
graphics.moveTo(-size*cellSize, i * cellSize);
|
|
graphics.lineTo(size*cellSize, i * cellSize);
|
|
graphics.moveTo(i * cellSize, -size*cellSize);
|
|
graphics.lineTo(i * cellSize, size*cellSize);
|
|
}
|
|
graphics.endFill();
|
|
graphics.endStroke();
|
|
// create the shape
|
|
super(graphics);
|
|
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @fileOverview
|
|
* @author Russell Toris - rctoris@wpi.edu
|
|
*/
|
|
|
|
class OccupancyGridClient extends EventEmitter2 {
|
|
|
|
/**
|
|
* A map that listens to a given occupancy grid topic.
|
|
*
|
|
* Emits the following events:
|
|
* * 'change' - there was an update or change in the map
|
|
*
|
|
* @constructor
|
|
* @param options - object with following keys:
|
|
* * ros - the ROSLIB.Ros connection handle
|
|
* * topic (optional) - the map topic to listen to
|
|
* * rootObject (optional) - the root object to add this marker to
|
|
* * continuous (optional) - if the map should be continuously loaded (e.g., for SLAM)
|
|
*/
|
|
constructor(options) {
|
|
super();
|
|
var that = this;
|
|
options = options || {};
|
|
var ros = options.ros;
|
|
var topic = options.topic || '/map';
|
|
this.continuous = options.continuous;
|
|
this.rootObject = options.rootObject || new createjs__namespace.Container();
|
|
|
|
// current grid that is displayed
|
|
// create an empty shape to start with, so that the order remains correct.
|
|
this.currentGrid = new createjs__namespace.Shape();
|
|
this.rootObject.addChild(this.currentGrid);
|
|
// work-around for a bug in easeljs -- needs a second object to render correctly
|
|
this.rootObject.addChild(new Grid({size:1}));
|
|
|
|
// subscribe to the topic
|
|
var rosTopic = new ROSLIB__namespace.Topic({
|
|
ros : ros,
|
|
name : topic,
|
|
messageType : 'nav_msgs/OccupancyGrid',
|
|
compression : 'png'
|
|
});
|
|
|
|
rosTopic.subscribe(function(message) {
|
|
// check for an old map
|
|
var index = null;
|
|
if (that.currentGrid) {
|
|
index = that.rootObject.getChildIndex(that.currentGrid);
|
|
that.rootObject.removeChild(that.currentGrid);
|
|
}
|
|
|
|
that.currentGrid = new OccupancyGrid({
|
|
message : message
|
|
});
|
|
if (index !== null) {
|
|
that.rootObject.addChildAt(that.currentGrid, index);
|
|
}
|
|
else {
|
|
that.rootObject.addChild(that.currentGrid);
|
|
}
|
|
|
|
that.emit('change');
|
|
|
|
// check if we should unsubscribe
|
|
if (!that.continuous) {
|
|
rosTopic.unsubscribe();
|
|
}
|
|
});
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @fileOverview
|
|
* @author Jihoon Lee- jihoonlee.in@gmail.com
|
|
* @author Russell Toris - rctoris@wpi.edu
|
|
*/
|
|
|
|
class OccupancyGridSrvClient extends EventEmitter2 {
|
|
|
|
/**
|
|
* A static map that receives from map_server.
|
|
*
|
|
* Emits the following events:
|
|
* * 'change' - there was an update or change in the map
|
|
*
|
|
* @constructor
|
|
* @param options - object with following keys:
|
|
* * ros - the ROSLIB.Ros connection handle
|
|
* * service (optional) - the map topic to listen to, like '/static_map'
|
|
* * rootObject (optional) - the root object to add this marker to
|
|
*/
|
|
constructor(options) {
|
|
super();
|
|
var that = this;
|
|
options = options || {};
|
|
var ros = options.ros;
|
|
var service = options.service || '/static_map';
|
|
this.rootObject = options.rootObject || new createjs__namespace.Container();
|
|
|
|
// current grid that is displayed
|
|
this.currentGrid = null;
|
|
|
|
// Setting up to the service
|
|
var rosService = new ROSLIB__namespace.Service({
|
|
ros : ros,
|
|
name : service,
|
|
serviceType : 'nav_msgs/GetMap',
|
|
compression : 'png'
|
|
});
|
|
|
|
rosService.callService(new ROSLIB__namespace.ServiceRequest(),function(response) {
|
|
// check for an old map
|
|
if (that.currentGrid) {
|
|
that.rootObject.removeChild(that.currentGrid);
|
|
}
|
|
|
|
that.currentGrid = new OccupancyGrid({
|
|
message : response.map
|
|
});
|
|
that.rootObject.addChild(that.currentGrid);
|
|
|
|
that.emit('change', that.currentGrid);
|
|
});
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @fileOverview
|
|
* @author Bart van Vliet - bart@dobots.nl
|
|
*/
|
|
|
|
class ArrowShape extends createjs__namespace.Shape {
|
|
|
|
/**
|
|
* An arrow with line and triangular head, based on the navigation arrow.
|
|
* Aims to the left at 0 rotation, as would be expected.
|
|
*
|
|
* @constructor
|
|
* @param {Object} options
|
|
* @param {Int} [options.size] - The size of the marker
|
|
* @param {Int} [options.strokeSize] - The size of the outline
|
|
* @param {String} [options.strokeColor] - The createjs color for the stroke
|
|
* @param {String} [options.fillColor] - The createjs color for the fill
|
|
* @param {Bool} [options.pulse] - If the marker should "pulse" over time
|
|
*/
|
|
constructor(options) {
|
|
var that = this;
|
|
options = options || {};
|
|
var size = options.size || 10;
|
|
var strokeSize = options.strokeSize || 3;
|
|
var strokeColor = options.strokeColor || createjs__namespace.Graphics.getRGB(0, 0, 0);
|
|
var fillColor = options.fillColor || createjs__namespace.Graphics.getRGB(255, 0, 0);
|
|
var pulse = options.pulse;
|
|
|
|
// draw the arrow
|
|
var graphics = new createjs__namespace.Graphics();
|
|
|
|
var headLen = size / 3.0;
|
|
var headWidth = headLen * 2.0 / 3.0;
|
|
|
|
graphics.setStrokeStyle(strokeSize);
|
|
graphics.beginStroke(strokeColor);
|
|
graphics.moveTo(0, 0);
|
|
graphics.lineTo(size-headLen, 0);
|
|
|
|
graphics.beginFill(fillColor);
|
|
graphics.moveTo(size, 0);
|
|
graphics.lineTo(size-headLen, headWidth / 2.0);
|
|
graphics.lineTo(size-headLen, -headWidth / 2.0);
|
|
graphics.closePath();
|
|
graphics.endFill();
|
|
graphics.endStroke();
|
|
|
|
// create the shape
|
|
super(graphics);
|
|
|
|
// check if we are pulsing
|
|
if (pulse) {
|
|
// have the model "pulse"
|
|
var growCount = 0;
|
|
var growing = true;
|
|
createjs__namespace.Ticker.addEventListener('tick', function() {
|
|
if (growing) {
|
|
that.scaleX *= 1.035;
|
|
that.scaleY *= 1.035;
|
|
growing = (++growCount < 10);
|
|
} else {
|
|
that.scaleX /= 1.035;
|
|
that.scaleY /= 1.035;
|
|
growing = (--growCount < 0);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @fileOverview
|
|
* @author Russell Toris - rctoris@wpi.edu
|
|
*/
|
|
|
|
class NavigationArrow extends createjs__namespace.Shape {
|
|
|
|
/**
|
|
* A navigation arrow is a directed triangle that can be used to display orientation.
|
|
*
|
|
* @constructor
|
|
* @param options - object with following keys:
|
|
* * size (optional) - the size of the marker
|
|
* * strokeSize (optional) - the size of the outline
|
|
* * strokeColor (optional) - the createjs color for the stroke
|
|
* * fillColor (optional) - the createjs color for the fill
|
|
* * pulse (optional) - if the marker should "pulse" over time
|
|
*/
|
|
constructor(options) {
|
|
var that = this;
|
|
options = options || {};
|
|
var size = options.size || 10;
|
|
var strokeSize = options.strokeSize || 3;
|
|
var strokeColor = options.strokeColor || createjs__namespace.Graphics.getRGB(0, 0, 0);
|
|
var fillColor = options.fillColor || createjs__namespace.Graphics.getRGB(255, 0, 0);
|
|
var pulse = options.pulse;
|
|
|
|
// draw the arrow
|
|
var graphics = new createjs__namespace.Graphics();
|
|
// line width
|
|
graphics.setStrokeStyle(strokeSize);
|
|
graphics.moveTo(-size / 2.0, -size / 2.0);
|
|
graphics.beginStroke(strokeColor);
|
|
graphics.beginFill(fillColor);
|
|
graphics.lineTo(size, 0);
|
|
graphics.lineTo(-size / 2.0, size / 2.0);
|
|
graphics.closePath();
|
|
graphics.endFill();
|
|
graphics.endStroke();
|
|
|
|
// create the shape
|
|
super(graphics);
|
|
|
|
// check if we are pulsing
|
|
if (pulse) {
|
|
// have the model "pulse"
|
|
var growCount = 0;
|
|
var growing = true;
|
|
createjs__namespace.Ticker.addEventListener('tick', function() {
|
|
if (growing) {
|
|
that.scaleX *= 1.035;
|
|
that.scaleY *= 1.035;
|
|
growing = (++growCount < 10);
|
|
} else {
|
|
that.scaleX /= 1.035;
|
|
that.scaleY /= 1.035;
|
|
growing = (--growCount < 0);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @fileOverview
|
|
* @author Inigo Gonzalez - ingonza85@gmail.com
|
|
*/
|
|
|
|
class NavigationImage extends createjs__namespace.Bitmap {
|
|
|
|
/**
|
|
* A navigation image that can be used to display orientation.
|
|
*
|
|
* @constructor
|
|
* @param options - object with following keys:
|
|
* * size (optional) - the size of the marker
|
|
* * image - the image to use as a marker
|
|
* * pulse (optional) - if the marker should "pulse" over time
|
|
*/
|
|
constructor(options) {
|
|
options = options || {};
|
|
var size = options.size || 10;
|
|
var image_url = options.image;
|
|
var pulse = options.pulse;
|
|
var alpha = options.alpha || 1;
|
|
|
|
var originals = {};
|
|
|
|
var image = new Image();
|
|
|
|
super(image);
|
|
|
|
var paintImage = function() {
|
|
var scale = calculateScale(size);
|
|
this.alpha = alpha;
|
|
this.scaleX = scale;
|
|
this.scaleY = scale;
|
|
this.regY = this.image.height/2;
|
|
this.regX = this.image.width/2;
|
|
originals['rotation'] = this.rotation;
|
|
Object.defineProperty(this, 'rotation', {
|
|
get: function(){ return originals['rotation'] + 90; },
|
|
set: function(value){ originals['rotation'] = value; }
|
|
});
|
|
if (pulse) {
|
|
// have the model "pulse"
|
|
var growCount = 0;
|
|
var growing = true;
|
|
var SCALE_SIZE = 1.020;
|
|
createjs__namespace.Ticker.addEventListener('tick', function() {
|
|
if (growing) {
|
|
this.scaleX *= SCALE_SIZE;
|
|
this.scaleY *= SCALE_SIZE;
|
|
growing = (++growCount < 10);
|
|
} else {
|
|
this.scaleX /= SCALE_SIZE;
|
|
this.scaleY /= SCALE_SIZE;
|
|
growing = (--growCount < 0);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
image.onload = paintImage.bind(this);
|
|
image.src = image_url;
|
|
|
|
var calculateScale = function(_size){
|
|
return _size / image.width;
|
|
};
|
|
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @fileOverview
|
|
* @author Bart van Vliet - bart@dobots.nl
|
|
*/
|
|
|
|
class PathShape extends createjs__namespace.Shape {
|
|
|
|
/**
|
|
* A shape to draw a nav_msgs/Path msg
|
|
*
|
|
* @constructor
|
|
* @param options - object with following keys:
|
|
* * path (optional) - the initial path to draw
|
|
* * strokeSize (optional) - the size of the outline
|
|
* * strokeColor (optional) - the createjs color for the stroke
|
|
*/
|
|
constructor(options) {
|
|
options = options || {};
|
|
var path = options.path;
|
|
this.strokeSize = options.strokeSize || 3;
|
|
this.strokeColor = options.strokeColor || createjs__namespace.Graphics.getRGB(0, 0, 0);
|
|
|
|
// draw the line
|
|
this.graphics = new createjs__namespace.Graphics();
|
|
|
|
if (path !== null && typeof path !== 'undefined') {
|
|
this.graphics.setStrokeStyle(this.strokeSize);
|
|
this.graphics.beginStroke(this.strokeColor);
|
|
this.graphics.moveTo(path.poses[0].pose.position.x / this.scaleX, path.poses[0].pose.position.y / -this.scaleY);
|
|
for (var i=1; i<path.poses.length; ++i) {
|
|
this.graphics.lineTo(path.poses[i].pose.position.x / this.scaleX, path.poses[i].pose.position.y / -this.scaleY);
|
|
}
|
|
this.graphics.endStroke();
|
|
}
|
|
|
|
// create the shape
|
|
super(this.graphics);
|
|
};
|
|
|
|
/**
|
|
* Set the path to draw
|
|
*
|
|
* @param path of type nav_msgs/Path
|
|
*/
|
|
setPath(path) {
|
|
this.graphics.clear();
|
|
if (path !== null && typeof path !== 'undefined') {
|
|
this.graphics.setStrokeStyle(this.strokeSize);
|
|
this.graphics.beginStroke(this.strokeColor);
|
|
this.graphics.moveTo(path.poses[0].pose.position.x / this.scaleX, path.poses[0].pose.position.y / -this.scaleY);
|
|
for (var i=1; i<path.poses.length; ++i) {
|
|
this.graphics.lineTo(path.poses[i].pose.position.x / this.scaleX, path.poses[i].pose.position.y / -this.scaleY);
|
|
}
|
|
this.graphics.endStroke();
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @fileOverview
|
|
* @author Bart van Vliet - bart@dobots.nl
|
|
*/
|
|
|
|
class PolygonMarker extends createjs__namespace.Container {
|
|
|
|
/**
|
|
* A polygon that can be edited by an end user
|
|
*
|
|
* @constructor
|
|
* @param options - object with following keys:
|
|
* * pose (optional) - the first pose of the trace
|
|
* * lineSize (optional) - the width of the lines
|
|
* * lineColor (optional) - the createjs color of the lines
|
|
* * pointSize (optional) - the size of the points
|
|
* * pointColor (optional) - the createjs color of the points
|
|
* * fillColor (optional) - the createjs color to fill the polygon
|
|
* * lineCallBack (optional) - callback function for mouse interaction with a line
|
|
* * pointCallBack (optional) - callback function for mouse interaction with a point
|
|
*/
|
|
constructor(options) {
|
|
// var that = this;
|
|
super();
|
|
options = options || {};
|
|
this.lineSize = options.lineSize || 3;
|
|
this.lineColor = options.lineColor || createjs__namespace.Graphics.getRGB(0, 0, 255, 0.66);
|
|
this.pointSize = options.pointSize || 10;
|
|
this.pointColor = options.pointColor || createjs__namespace.Graphics.getRGB(255, 0, 0, 0.66);
|
|
this.fillColor = options.pointColor || createjs__namespace.Graphics.getRGB(0, 255, 0, 0.33);
|
|
this.lineCallBack = options.lineCallBack;
|
|
this.pointCallBack = options.pointCallBack;
|
|
|
|
// Array of point shapes
|
|
// this.points = [];
|
|
this.pointContainer = new createjs__namespace.Container();
|
|
|
|
// Array of line shapes
|
|
// this.lines = [];
|
|
this.lineContainer = new createjs__namespace.Container();
|
|
|
|
this.fillShape = new createjs__namespace.Shape();
|
|
|
|
// Container with all the lines and points
|
|
this.addChild(this.fillShape);
|
|
this.addChild(this.lineContainer);
|
|
this.addChild(this.pointContainer);
|
|
};
|
|
|
|
/**
|
|
* Internal use only
|
|
*/
|
|
createLineShape(startPoint, endPoint) {
|
|
var line = new createjs__namespace.Shape();
|
|
// line.graphics.setStrokeStyle(this.strokeSize);
|
|
// line.graphics.beginStroke(this.strokeColor);
|
|
// line.graphics.moveTo(startPoint.x, startPoint.y);
|
|
// line.graphics.lineTo(endPoint.x, endPoint.y);
|
|
this.editLineShape(line, startPoint, endPoint);
|
|
|
|
var that = this;
|
|
line.addEventListener('mousedown', function(event) {
|
|
if (that.lineCallBack !== null && typeof that.lineCallBack !== 'undefined') {
|
|
that.lineCallBack('mousedown', event, that.lineContainer.getChildIndex(event.target));
|
|
}
|
|
});
|
|
|
|
return line;
|
|
};
|
|
|
|
/**
|
|
* Internal use only
|
|
*/
|
|
editLineShape(line, startPoint, endPoint) {
|
|
line.graphics.clear();
|
|
line.graphics.setStrokeStyle(this.lineSize);
|
|
line.graphics.beginStroke(this.lineColor);
|
|
line.graphics.moveTo(startPoint.x, startPoint.y);
|
|
line.graphics.lineTo(endPoint.x, endPoint.y);
|
|
};
|
|
|
|
/**
|
|
* Internal use only
|
|
*/
|
|
createPointShape(pos) {
|
|
var point = new createjs__namespace.Shape();
|
|
point.graphics.beginFill(this.pointColor);
|
|
point.graphics.drawCircle(0, 0, this.pointSize);
|
|
point.x = pos.x;
|
|
point.y = -pos.y;
|
|
|
|
var that = this;
|
|
point.addEventListener('mousedown', function(event) {
|
|
if (that.pointCallBack !== null && typeof that.pointCallBack !== 'undefined') {
|
|
that.pointCallBack('mousedown', event, that.pointContainer.getChildIndex(event.target));
|
|
}
|
|
});
|
|
|
|
return point;
|
|
};
|
|
|
|
/**
|
|
* Adds a point to the polygon
|
|
*
|
|
* @param position of type ROSLIB.Vector3
|
|
*/
|
|
addPoint(pos) {
|
|
var point = this.createPointShape(pos);
|
|
this.pointContainer.addChild(point);
|
|
var numPoints = this.pointContainer.numChildren;
|
|
|
|
// 0 points -> 1 point, 0 lines
|
|
// 1 point -> 2 points, lines: add line between previous and new point, add line between new point and first point
|
|
// 2 points -> 3 points, 3 lines: change last line, add line between new point and first point
|
|
// 3 points -> 4 points, 4 lines: change last line, add line between new point and first point
|
|
// etc
|
|
|
|
if (numPoints < 2) ;
|
|
else if (numPoints < 3) {
|
|
// Now 2 points: add line between previous and new point
|
|
var line = this.createLineShape(this.pointContainer.getChildAt(numPoints-2), point);
|
|
this.lineContainer.addChild(line);
|
|
}
|
|
if (numPoints > 2) {
|
|
// Now 3 or more points: change last line
|
|
this.editLineShape(this.lineContainer.getChildAt(numPoints-2), this.pointContainer.getChildAt(numPoints-2), point);
|
|
}
|
|
if (numPoints > 1) {
|
|
// Now 2 or more points: add line between new point and first point
|
|
var lineEnd = this.createLineShape(point, this.pointContainer.getChildAt(0));
|
|
this.lineContainer.addChild(lineEnd);
|
|
}
|
|
|
|
this.drawFill();
|
|
};
|
|
|
|
/**
|
|
* Removes a point from the polygon
|
|
*
|
|
* @param obj either an index (integer) or a point shape of the polygon
|
|
*/
|
|
remPoint(obj) {
|
|
var index;
|
|
// var point;
|
|
if (obj instanceof createjs__namespace.Shape) {
|
|
index = this.pointContainer.getChildIndex(obj);
|
|
// point = obj;
|
|
}
|
|
else {
|
|
index = obj;
|
|
// point = this.pointContainer.getChildAt(index);
|
|
}
|
|
|
|
// 0 points -> 0 points, 0 lines
|
|
// 1 point -> 0 points, 0 lines
|
|
// 2 points -> 1 point, 0 lines: remove all lines
|
|
// 3 points -> 2 points, 2 lines: change line before point to remove, remove line after point to remove
|
|
// 4 points -> 3 points, 3 lines: change line before point to remove, remove line after point to remove
|
|
// etc
|
|
|
|
var numPoints = this.pointContainer.numChildren;
|
|
|
|
if (numPoints < 2) ;
|
|
else if (numPoints < 3) {
|
|
// 2 points: remove all lines
|
|
this.lineContainer.removeAllChildren();
|
|
}
|
|
else {
|
|
// 3 or more points: change line before point to remove, remove line after point to remove
|
|
this.editLineShape(
|
|
this.lineContainer.getChildAt((index-1+numPoints)%numPoints),
|
|
this.pointContainer.getChildAt((index-1+numPoints)%numPoints),
|
|
this.pointContainer.getChildAt((index+1)%numPoints)
|
|
);
|
|
this.lineContainer.removeChildAt(index);
|
|
}
|
|
this.pointContainer.removeChildAt(index);
|
|
// this.points.splice(index, 1);
|
|
|
|
this.drawFill();
|
|
};
|
|
|
|
/**
|
|
* Moves a point of the polygon
|
|
*
|
|
* @param obj either an index (integer) or a point shape of the polygon
|
|
* @param position of type ROSLIB.Vector3
|
|
*/
|
|
movePoint(obj, newPos) {
|
|
var index;
|
|
var point;
|
|
if (obj instanceof createjs__namespace.Shape) {
|
|
index = this.pointContainer.getChildIndex(obj);
|
|
point = obj;
|
|
}
|
|
else {
|
|
index = obj;
|
|
point = this.pointContainer.getChildAt(index);
|
|
}
|
|
point.x = newPos.x;
|
|
point.y = -newPos.y;
|
|
|
|
var numPoints = this.pointContainer.numChildren;
|
|
if (numPoints > 1) {
|
|
// line before moved point
|
|
var line1 = this.lineContainer.getChildAt((index-1+numPoints)%numPoints);
|
|
this.editLineShape(line1, this.pointContainer.getChildAt((index-1+numPoints)%numPoints), point);
|
|
|
|
// line after moved point
|
|
var line2 = this.lineContainer.getChildAt(index);
|
|
this.editLineShape(line2, point, this.pointContainer.getChildAt((index+1)%numPoints));
|
|
}
|
|
|
|
this.drawFill();
|
|
};
|
|
|
|
/**
|
|
* Splits a line of the polygon: inserts a point at the center of the line
|
|
*
|
|
* @param obj either an index (integer) or a line shape of the polygon
|
|
*/
|
|
splitLine(obj) {
|
|
var index;
|
|
var line;
|
|
if (obj instanceof createjs__namespace.Shape) {
|
|
index = this.lineContainer.getChildIndex(obj);
|
|
line = obj;
|
|
}
|
|
else {
|
|
index = obj;
|
|
line = this.lineContainer.getChildAt(index);
|
|
}
|
|
var numPoints = this.pointContainer.numChildren;
|
|
var xs = this.pointContainer.getChildAt(index).x;
|
|
var ys = this.pointContainer.getChildAt(index).y;
|
|
var xe = this.pointContainer.getChildAt((index+1)%numPoints).x;
|
|
var ye = this.pointContainer.getChildAt((index+1)%numPoints).y;
|
|
var xh = (xs+xe)/2.0;
|
|
var yh = (ys+ye)/2.0;
|
|
var pos = new ROSLIB__namespace.Vector3({ x:xh, y:-yh });
|
|
|
|
// Add a point in the center of the line to split
|
|
var point = this.createPointShape(pos);
|
|
this.pointContainer.addChildAt(point, index+1);
|
|
++numPoints;
|
|
|
|
// Add a line between the new point and the end of the line to split
|
|
var lineNew = this.createLineShape(point, this.pointContainer.getChildAt((index+2)%numPoints));
|
|
this.lineContainer.addChildAt(lineNew, index+1);
|
|
|
|
// Set the endpoint of the line to split to the new point
|
|
this.editLineShape(line, this.pointContainer.getChildAt(index), point);
|
|
|
|
this.drawFill();
|
|
};
|
|
|
|
/**
|
|
* Internal use only
|
|
*/
|
|
drawFill() {
|
|
var numPoints = this.pointContainer.numChildren;
|
|
if (numPoints > 2) {
|
|
var g = this.fillShape.graphics;
|
|
g.clear();
|
|
g.setStrokeStyle(0);
|
|
g.beginStroke();
|
|
g.beginFill(this.fillColor);
|
|
g.moveTo(this.pointContainer.getChildAt(0).x, this.pointContainer.getChildAt(0).y);
|
|
for (var i=1; i<numPoints; ++i) {
|
|
g.lineTo(this.pointContainer.getChildAt(i).x, this.pointContainer.getChildAt(i).y);
|
|
}
|
|
g.closePath();
|
|
g.endFill();
|
|
g.endStroke();
|
|
}
|
|
else {
|
|
this.fillShape.graphics.clear();
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @fileOverview
|
|
* @author Bart van Vliet - bart@dobots.nl
|
|
*/
|
|
|
|
class TraceShape extends createjs__namespace.Shape {
|
|
|
|
/**
|
|
* A trace of poses, handy to see where a robot has been
|
|
*
|
|
* @constructor
|
|
* @param options - object with following keys:
|
|
* * pose (optional) - the first pose of the trace
|
|
* * strokeSize (optional) - the size of the outline
|
|
* * strokeColor (optional) - the createjs color for the stroke
|
|
* * maxPoses (optional) - the maximum number of poses to keep, 0 for infinite
|
|
* * minDist (optional) - the minimal distance between poses to use the pose for drawing (default 0.05)
|
|
*/
|
|
constructor(options) {
|
|
// var that = this;
|
|
options = options || {};
|
|
var pose = options.pose;
|
|
this.strokeSize = options.strokeSize || 3;
|
|
this.strokeColor = options.strokeColor || createjs__namespace.Graphics.getRGB(0, 0, 0);
|
|
this.maxPoses = (options.maxPoses || options.maxPoses === 0) ? options.maxPoses : 100;
|
|
this.minDist = options.minDist || 0.05;
|
|
|
|
// Store minDist as the square of it
|
|
this.minDist = this.minDist*this.minDist;
|
|
|
|
// Array of the poses
|
|
// TODO: do we need this?
|
|
this.poses = [];
|
|
|
|
// Create the graphics
|
|
this.graphics = new createjs__namespace.Graphics();
|
|
this.graphics.setStrokeStyle(this.strokeSize);
|
|
this.graphics.beginStroke(this.strokeColor);
|
|
|
|
// Add first pose if given
|
|
if (pose !== null && typeof pose !== 'undefined') {
|
|
this.poses.push(pose);
|
|
}
|
|
|
|
// Create the shape
|
|
super(this.graphics);
|
|
};
|
|
|
|
/**
|
|
* Adds a pose to the trace and updates the graphics
|
|
*
|
|
* @param pose of type ROSLIB.Pose
|
|
*/
|
|
addPose(pose) {
|
|
var last = this.poses.length-1;
|
|
if (last < 0) {
|
|
this.poses.push(pose);
|
|
this.graphics.moveTo(pose.position.x / this.scaleX, pose.position.y / -this.scaleY);
|
|
}
|
|
else {
|
|
var prevX = this.poses[last].position.x;
|
|
var prevY = this.poses[last].position.y;
|
|
var dx = (pose.position.x - prevX);
|
|
var dy = (pose.position.y - prevY);
|
|
if (dx*dx + dy*dy > this.minDist) {
|
|
this.graphics.lineTo(pose.position.x / this.scaleX, pose.position.y / -this.scaleY);
|
|
this.poses.push(pose);
|
|
}
|
|
}
|
|
if (this.maxPoses > 0 && this.maxPoses < this.poses.length) {
|
|
this.popFront();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Removes front pose and updates the graphics
|
|
*/
|
|
popFront() {
|
|
if (this.poses.length > 0) {
|
|
this.poses.shift();
|
|
// TODO: shift drawing instructions rather than doing it all over
|
|
this.graphics.clear();
|
|
this.graphics.setStrokeStyle(this.strokeSize);
|
|
this.graphics.beginStroke(this.strokeColor);
|
|
this.graphics.lineTo(this.poses[0].position.x / this.scaleX, this.poses[0].position.y / -this.scaleY);
|
|
for (var i=1; i<this.poses.length; ++i) {
|
|
this.graphics.lineTo(this.poses[i].position.x / this.scaleX, this.poses[i].position.y / -this.scaleY);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @fileOverview
|
|
* @author Bart van Vliet - bart@dobots.nl
|
|
*/
|
|
|
|
class PanView {
|
|
|
|
/**
|
|
* Adds panning to a view
|
|
*
|
|
* @constructor
|
|
* @param options - object with following keys:
|
|
* * rootObject (optional) - the root object to apply panning to
|
|
*/
|
|
constructor(options) {
|
|
options = options || {};
|
|
this.rootObject = options.rootObject;
|
|
|
|
// get a handle to the stage
|
|
if (this.rootObject instanceof createjs__namespace.Stage) {
|
|
this.stage = this.rootObject;
|
|
}
|
|
else {
|
|
this.stage = this.rootObject.getStage();
|
|
}
|
|
|
|
this.startPos = new ROSLIB__namespace.Vector3();
|
|
};
|
|
|
|
|
|
startPan(startX, startY) {
|
|
this.startPos.x = startX;
|
|
this.startPos.y = startY;
|
|
};
|
|
|
|
pan(curX, curY) {
|
|
this.stage.x += curX - this.startPos.x;
|
|
this.startPos.x = curX;
|
|
this.stage.y += curY - this.startPos.y;
|
|
this.startPos.y = curY;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @fileOverview
|
|
* @author Russell Toris - rctoris@wpi.edu
|
|
*/
|
|
|
|
class Viewer {
|
|
|
|
/**
|
|
* A Viewer can be used to render an interactive 2D scene to a HTML5 canvas.
|
|
*
|
|
* @constructor
|
|
* @param options - object with following keys:
|
|
* * divID - the ID of the div to place the viewer in
|
|
* * width - the initial width, in pixels, of the canvas
|
|
* * height - the initial height, in pixels, of the canvas
|
|
* * background (optional) - the color to render the background, like '#efefef'
|
|
*/
|
|
constructor(options) {
|
|
options = options || {};
|
|
var divID = options.divID;
|
|
this.width = options.width;
|
|
this.height = options.height;
|
|
var background = options.background || '#111111';
|
|
|
|
// create the canvas to render to
|
|
var canvas = document.createElement('canvas');
|
|
canvas.width = this.width;
|
|
canvas.height = this.height;
|
|
canvas.style.background = background;
|
|
document.getElementById(divID).appendChild(canvas);
|
|
// create the easel to use
|
|
this.scene = new createjs__namespace.Stage(canvas);
|
|
|
|
// change Y axis center
|
|
this.scene.y = this.height;
|
|
|
|
// add the renderer to the page
|
|
document.getElementById(divID).appendChild(canvas);
|
|
|
|
// update at 30fps
|
|
createjs__namespace.Ticker.framerate = 30;
|
|
createjs__namespace.Ticker.addEventListener('tick', this.scene);
|
|
};
|
|
|
|
/**
|
|
* Add the given createjs object to the global scene in the viewer.
|
|
*
|
|
* @param object - the object to add
|
|
*/
|
|
addObject(object) {
|
|
this.scene.addChild(object);
|
|
};
|
|
|
|
/**
|
|
* Scale the scene to fit the given width and height into the current canvas.
|
|
*
|
|
* @param width - the width to scale to in meters
|
|
* @param height - the height to scale to in meters
|
|
*/
|
|
scaleToDimensions(width, height) {
|
|
// restore to values before shifting, if ocurred
|
|
this.scene.x = typeof this.scene.x_prev_shift !== 'undefined' ? this.scene.x_prev_shift : this.scene.x;
|
|
this.scene.y = typeof this.scene.y_prev_shift !== 'undefined' ? this.scene.y_prev_shift : this.scene.y;
|
|
|
|
// save scene scaling
|
|
this.scene.scaleX = this.width / width;
|
|
this.scene.scaleY = this.height / height;
|
|
};
|
|
|
|
/**
|
|
* Shift the main view of the canvas by the given amount. This is based on the
|
|
* ROS coordinate system. That is, Y is opposite that of a traditional canvas.
|
|
*
|
|
* @param x - the amount to shift by in the x direction in meters
|
|
* @param y - the amount to shift by in the y direction in meters
|
|
*/
|
|
shift(x, y) {
|
|
// save current offset
|
|
this.scene.x_prev_shift = this.scene.x;
|
|
this.scene.y_prev_shift = this.scene.y;
|
|
|
|
// shift scene by scaling the desired offset
|
|
this.scene.x -= (x * this.scene.scaleX);
|
|
this.scene.y += (y * this.scene.scaleY);
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @fileOverview
|
|
* @author Bart van Vliet - bart@dobots.nl
|
|
*/
|
|
|
|
class ZoomView {
|
|
|
|
/**
|
|
* Adds zooming to a view
|
|
*
|
|
* @constructor
|
|
* @param options - object with following keys:
|
|
* * rootObject (optional) - the root object to apply zoom to
|
|
* * minScale (optional) - minimum scale to set to preserve precision
|
|
*/
|
|
constructor(options) {
|
|
options = options || {};
|
|
this.rootObject = options.rootObject;
|
|
this.minScale = options.minScale || 0.001;
|
|
|
|
// get a handle to the stage
|
|
if (this.rootObject instanceof createjs__namespace.Stage) {
|
|
this.stage = this.rootObject;
|
|
}
|
|
else {
|
|
this.stage = this.rootObject.getStage();
|
|
}
|
|
|
|
this.center = new ROSLIB__namespace.Vector3();
|
|
this.startShift = new ROSLIB__namespace.Vector3();
|
|
this.startScale = new ROSLIB__namespace.Vector3();
|
|
};
|
|
|
|
|
|
startZoom(centerX, centerY) {
|
|
this.center.x = centerX;
|
|
this.center.y = centerY;
|
|
this.startShift.x = this.stage.x;
|
|
this.startShift.y = this.stage.y;
|
|
this.startScale.x = this.stage.scaleX;
|
|
this.startScale.y = this.stage.scaleY;
|
|
};
|
|
|
|
zoom(zoom) {
|
|
// Make sure scale doesn't become too small
|
|
if (this.startScale.x*zoom < this.minScale) {
|
|
zoom = this.minScale/this.startScale.x;
|
|
}
|
|
if (this.startScale.y*zoom < this.minScale) {
|
|
zoom = this.minScale/this.startScale.y;
|
|
}
|
|
|
|
this.stage.scaleX = this.startScale.x*zoom;
|
|
this.stage.scaleY = this.startScale.y*zoom;
|
|
|
|
this.stage.x = this.startShift.x - (this.center.x-this.startShift.x) * (this.stage.scaleX/this.startScale.x - 1);
|
|
this.stage.y = this.startShift.y - (this.center.y-this.startShift.y) * (this.stage.scaleY/this.startScale.y - 1);
|
|
};
|
|
}
|
|
|
|
exports.ArrowShape = ArrowShape;
|
|
exports.Grid = Grid;
|
|
exports.ImageMap = ImageMap;
|
|
exports.ImageMapClient = ImageMapClient;
|
|
exports.NavigationArrow = NavigationArrow;
|
|
exports.NavigationImage = NavigationImage;
|
|
exports.OccupancyGrid = OccupancyGrid;
|
|
exports.OccupancyGridClient = OccupancyGridClient;
|
|
exports.OccupancyGridSrvClient = OccupancyGridSrvClient;
|
|
exports.PanView = PanView;
|
|
exports.PathShape = PathShape;
|
|
exports.PolygonMarker = PolygonMarker;
|
|
exports.TraceShape = TraceShape;
|
|
exports.Viewer = Viewer;
|
|
exports.ZoomView = ZoomView;
|
|
|
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
|
return exports;
|
|
|
|
})({}, createjs, ROSLIB);
|