Last active
January 4, 2016 03:28
-
-
Save abernier/8561651 to your computer and use it in GitHub Desktop.
box2d-demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
box2d.org |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Backbone.js 0.9.2 | |
// (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc. | |
// Backbone may be freely distributed under the MIT license. | |
// For all details and documentation: | |
// http://backbonejs.org | |
(function(){ | |
// Initial Setup | |
// ------------- | |
// Save a reference to the global object (`window` in the browser, `global` | |
// on the server). | |
var root = this; | |
// Save the previous value of the `Backbone` variable, so that it can be | |
// restored later on, if `noConflict` is used. | |
var previousBackbone = root.Backbone; | |
// Create a local reference to slice/splice. | |
var slice = Array.prototype.slice; | |
var splice = Array.prototype.splice; | |
// The top-level namespace. All public Backbone classes and modules will | |
// be attached to this. Exported for both CommonJS and the browser. | |
var Backbone; | |
if (typeof exports !== 'undefined') { | |
Backbone = exports; | |
} else { | |
Backbone = root.Backbone = {}; | |
} | |
// Current version of the library. Keep in sync with `package.json`. | |
Backbone.VERSION = '0.9.2'; | |
// Require Underscore, if we're on the server, and it's not already present. | |
var _ = root._; | |
if (!_ && (typeof require !== 'undefined')) _ = require('underscore'); | |
// For Backbone's purposes, jQuery, Zepto, or Ender owns the `$` variable. | |
var $ = root.jQuery || root.Zepto || root.ender; | |
// Set the JavaScript library that will be used for DOM manipulation and | |
// Ajax calls (a.k.a. the `$` variable). By default Backbone will use: jQuery, | |
// Zepto, or Ender; but the `setDomLibrary()` method lets you inject an | |
// alternate JavaScript library (or a mock library for testing your views | |
// outside of a browser). | |
Backbone.setDomLibrary = function(lib) { | |
$ = lib; | |
}; | |
// Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable | |
// to its previous owner. Returns a reference to this Backbone object. | |
Backbone.noConflict = function() { | |
root.Backbone = previousBackbone; | |
return this; | |
}; | |
// Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option | |
// will fake `"PUT"` and `"DELETE"` requests via the `_method` parameter and | |
// set a `X-Http-Method-Override` header. | |
Backbone.emulateHTTP = false; | |
// Turn on `emulateJSON` to support legacy servers that can't deal with direct | |
// `application/json` requests ... will encode the body as | |
// `application/x-www-form-urlencoded` instead and will send the model in a | |
// form param named `model`. | |
Backbone.emulateJSON = false; | |
// Backbone.Events | |
// ----------------- | |
// Regular expression used to split event strings | |
var eventSplitter = /\s+/; | |
// A module that can be mixed in to *any object* in order to provide it with | |
// custom events. You may bind with `on` or remove with `off` callback functions | |
// to an event; trigger`-ing an event fires all callbacks in succession. | |
// | |
// var object = {}; | |
// _.extend(object, Backbone.Events); | |
// object.on('expand', function(){ alert('expanded'); }); | |
// object.trigger('expand'); | |
// | |
var Events = Backbone.Events = { | |
// Bind one or more space separated events, `events`, to a `callback` | |
// function. Passing `"all"` will bind the callback to all events fired. | |
on: function(events, callback, context) { | |
var calls, event, node, tail, list; | |
if (!callback) return this; | |
events = events.split(eventSplitter); | |
calls = this._callbacks || (this._callbacks = {}); | |
// Create an immutable callback list, allowing traversal during | |
// modification. The tail is an empty object that will always be used | |
// as the next node. | |
while (event = events.shift()) { | |
list = calls[event]; | |
node = list ? list.tail : {}; | |
node.next = tail = {}; | |
node.context = context; | |
node.callback = callback; | |
calls[event] = {tail: tail, next: list ? list.next : node}; | |
} | |
return this; | |
}, | |
// Remove one or many callbacks. If `context` is null, removes all callbacks | |
// with that function. If `callback` is null, removes all callbacks for the | |
// event. If `events` is null, removes all bound callbacks for all events. | |
off: function(events, callback, context) { | |
var event, calls, node, tail, cb, ctx; | |
// No events, or removing *all* events. | |
if (!(calls = this._callbacks)) return; | |
if (!(events || callback || context)) { | |
delete this._callbacks; | |
return this; | |
} | |
// Loop through the listed events and contexts, splicing them out of the | |
// linked list of callbacks if appropriate. | |
events = events ? events.split(eventSplitter) : _.keys(calls); | |
while (event = events.shift()) { | |
node = calls[event]; | |
delete calls[event]; | |
if (!node || !(callback || context)) continue; | |
// Create a new list, omitting the indicated callbacks. | |
tail = node.tail; | |
while ((node = node.next) !== tail) { | |
cb = node.callback; | |
ctx = node.context; | |
if ((callback && cb !== callback) || (context && ctx !== context)) { | |
this.on(event, cb, ctx); | |
} | |
} | |
} | |
return this; | |
}, | |
// Trigger one or many events, firing all bound callbacks. Callbacks are | |
// passed the same arguments as `trigger` is, apart from the event name | |
// (unless you're listening on `"all"`, which will cause your callback to | |
// receive the true name of the event as the first argument). | |
trigger: function(events) { | |
var event, node, calls, tail, args, all, rest; | |
if (!(calls = this._callbacks)) return this; | |
all = calls.all; | |
events = events.split(eventSplitter); | |
rest = slice.call(arguments, 1); | |
// For each event, walk through the linked list of callbacks twice, | |
// first to trigger the event, then to trigger any `"all"` callbacks. | |
while (event = events.shift()) { | |
if (node = calls[event]) { | |
tail = node.tail; | |
while ((node = node.next) !== tail) { | |
node.callback.apply(node.context || this, rest); | |
} | |
} | |
if (node = all) { | |
tail = node.tail; | |
args = [event].concat(rest); | |
while ((node = node.next) !== tail) { | |
node.callback.apply(node.context || this, args); | |
} | |
} | |
} | |
return this; | |
} | |
}; | |
// Aliases for backwards compatibility. | |
Events.bind = Events.on; | |
Events.unbind = Events.off; | |
// Backbone.Model | |
// -------------- | |
// Create a new model, with defined attributes. A client id (`cid`) | |
// is automatically generated and assigned for you. | |
var Model = Backbone.Model = function(attributes, options) { | |
var defaults; | |
attributes || (attributes = {}); | |
if (options && options.parse) attributes = this.parse(attributes); | |
if (defaults = getValue(this, 'defaults')) { | |
attributes = _.extend({}, defaults, attributes); | |
} | |
if (options && options.collection) this.collection = options.collection; | |
this.attributes = {}; | |
this._escapedAttributes = {}; | |
this.cid = _.uniqueId('c'); | |
this.changed = {}; | |
this._silent = {}; | |
this._pending = {}; | |
this.set(attributes, {silent: true}); | |
// Reset change tracking. | |
this.changed = {}; | |
this._silent = {}; | |
this._pending = {}; | |
this._previousAttributes = _.clone(this.attributes); | |
this.initialize.apply(this, arguments); | |
}; | |
// Attach all inheritable methods to the Model prototype. | |
_.extend(Model.prototype, Events, { | |
// A hash of attributes whose current and previous value differ. | |
changed: null, | |
// A hash of attributes that have silently changed since the last time | |
// `change` was called. Will become pending attributes on the next call. | |
_silent: null, | |
// A hash of attributes that have changed since the last `'change'` event | |
// began. | |
_pending: null, | |
// The default name for the JSON `id` attribute is `"id"`. MongoDB and | |
// CouchDB users may want to set this to `"_id"`. | |
idAttribute: 'id', | |
// Initialize is an empty function by default. Override it with your own | |
// initialization logic. | |
initialize: function(){}, | |
// Return a copy of the model's `attributes` object. | |
toJSON: function(options) { | |
return _.clone(this.attributes); | |
}, | |
// Get the value of an attribute. | |
get: function(attr) { | |
return this.attributes[attr]; | |
}, | |
// Get the HTML-escaped value of an attribute. | |
escape: function(attr) { | |
var html; | |
if (html = this._escapedAttributes[attr]) return html; | |
var val = this.get(attr); | |
return this._escapedAttributes[attr] = _.escape(val == null ? '' : '' + val); | |
}, | |
// Returns `true` if the attribute contains a value that is not null | |
// or undefined. | |
has: function(attr) { | |
return this.get(attr) != null; | |
}, | |
// Set a hash of model attributes on the object, firing `"change"` unless | |
// you choose to silence it. | |
set: function(key, value, options) { | |
var attrs, attr, val; | |
// Handle both `"key", value` and `{key: value}` -style arguments. | |
if (_.isObject(key) || key == null) { | |
attrs = key; | |
options = value; | |
} else { | |
attrs = {}; | |
attrs[key] = value; | |
} | |
// Extract attributes and options. | |
options || (options = {}); | |
if (!attrs) return this; | |
if (attrs instanceof Model) attrs = attrs.attributes; | |
if (options.unset) for (attr in attrs) attrs[attr] = void 0; | |
// Run validation. | |
if (!this._validate(attrs, options)) return false; | |
// Check for changes of `id`. | |
if (this.idAttribute in attrs) this.id = attrs[this.idAttribute]; | |
var changes = options.changes = {}; | |
var now = this.attributes; | |
var escaped = this._escapedAttributes; | |
var prev = this._previousAttributes || {}; | |
// For each `set` attribute... | |
for (attr in attrs) { | |
val = attrs[attr]; | |
// If the new and current value differ, record the change. | |
if (!_.isEqual(now[attr], val) || (options.unset && _.has(now, attr))) { | |
delete escaped[attr]; | |
(options.silent ? this._silent : changes)[attr] = true; | |
} | |
// Update or delete the current value. | |
options.unset ? delete now[attr] : now[attr] = val; | |
// If the new and previous value differ, record the change. If not, | |
// then remove changes for this attribute. | |
if (!_.isEqual(prev[attr], val) || (_.has(now, attr) != _.has(prev, attr))) { | |
this.changed[attr] = val; | |
if (!options.silent) this._pending[attr] = true; | |
} else { | |
delete this.changed[attr]; | |
delete this._pending[attr]; | |
} | |
} | |
// Fire the `"change"` events. | |
if (!options.silent) this.change(options); | |
return this; | |
}, | |
// Remove an attribute from the model, firing `"change"` unless you choose | |
// to silence it. `unset` is a noop if the attribute doesn't exist. | |
unset: function(attr, options) { | |
(options || (options = {})).unset = true; | |
return this.set(attr, null, options); | |
}, | |
// Clear all attributes on the model, firing `"change"` unless you choose | |
// to silence it. | |
clear: function(options) { | |
(options || (options = {})).unset = true; | |
return this.set(_.clone(this.attributes), options); | |
}, | |
// Fetch the model from the server. If the server's representation of the | |
// model differs from its current attributes, they will be overriden, | |
// triggering a `"change"` event. | |
fetch: function(options) { | |
options = options ? _.clone(options) : {}; | |
var model = this; | |
var success = options.success; | |
options.success = function(resp, status, xhr) { | |
if (!model.set(model.parse(resp, xhr), options)) return false; | |
if (success) success(model, resp); | |
}; | |
options.error = Backbone.wrapError(options.error, model, options); | |
return (this.sync || Backbone.sync).call(this, 'read', this, options); | |
}, | |
// Set a hash of model attributes, and sync the model to the server. | |
// If the server returns an attributes hash that differs, the model's | |
// state will be `set` again. | |
save: function(key, value, options) { | |
var attrs, current; | |
// Handle both `("key", value)` and `({key: value})` -style calls. | |
if (_.isObject(key) || key == null) { | |
attrs = key; | |
options = value; | |
} else { | |
attrs = {}; | |
attrs[key] = value; | |
} | |
options = options ? _.clone(options) : {}; | |
// If we're "wait"-ing to set changed attributes, validate early. | |
if (options.wait) { | |
if (!this._validate(attrs, options)) return false; | |
current = _.clone(this.attributes); | |
} | |
// Regular saves `set` attributes before persisting to the server. | |
var silentOptions = _.extend({}, options, {silent: true}); | |
if (attrs && !this.set(attrs, options.wait ? silentOptions : options)) { | |
return false; | |
} | |
// After a successful server-side save, the client is (optionally) | |
// updated with the server-side state. | |
var model = this; | |
var success = options.success; | |
options.success = function(resp, status, xhr) { | |
var serverAttrs = model.parse(resp, xhr); | |
if (options.wait) { | |
delete options.wait; | |
serverAttrs = _.extend(attrs || {}, serverAttrs); | |
} | |
if (!model.set(serverAttrs, options)) return false; | |
if (success) { | |
success(model, resp); | |
} else { | |
model.trigger('sync', model, resp, options); | |
} | |
}; | |
// Finish configuring and sending the Ajax request. | |
options.error = Backbone.wrapError(options.error, model, options); | |
var method = this.isNew() ? 'create' : 'update'; | |
var xhr = (this.sync || Backbone.sync).call(this, method, this, options); | |
if (options.wait) this.set(current, silentOptions); | |
return xhr; | |
}, | |
// Destroy this model on the server if it was already persisted. | |
// Optimistically removes the model from its collection, if it has one. | |
// If `wait: true` is passed, waits for the server to respond before removal. | |
destroy: function(options) { | |
options = options ? _.clone(options) : {}; | |
var model = this; | |
var success = options.success; | |
var triggerDestroy = function() { | |
model.trigger('destroy', model, model.collection, options); | |
}; | |
if (this.isNew()) { | |
triggerDestroy(); | |
return false; | |
} | |
options.success = function(resp) { | |
if (options.wait) triggerDestroy(); | |
if (success) { | |
success(model, resp); | |
} else { | |
model.trigger('sync', model, resp, options); | |
} | |
}; | |
options.error = Backbone.wrapError(options.error, model, options); | |
var xhr = (this.sync || Backbone.sync).call(this, 'delete', this, options); | |
if (!options.wait) triggerDestroy(); | |
return xhr; | |
}, | |
// Default URL for the model's representation on the server -- if you're | |
// using Backbone's restful methods, override this to change the endpoint | |
// that will be called. | |
url: function() { | |
var base = getValue(this, 'urlRoot') || getValue(this.collection, 'url') || urlError(); | |
if (this.isNew()) return base; | |
return base + (base.charAt(base.length - 1) == '/' ? '' : '/') + encodeURIComponent(this.id); | |
}, | |
// **parse** converts a response into the hash of attributes to be `set` on | |
// the model. The default implementation is just to pass the response along. | |
parse: function(resp, xhr) { | |
return resp; | |
}, | |
// Create a new model with identical attributes to this one. | |
clone: function() { | |
return new this.constructor(this.attributes); | |
}, | |
// A model is new if it has never been saved to the server, and lacks an id. | |
isNew: function() { | |
return this.id == null; | |
}, | |
// Call this method to manually fire a `"change"` event for this model and | |
// a `"change:attribute"` event for each changed attribute. | |
// Calling this will cause all objects observing the model to update. | |
change: function(options) { | |
options || (options = {}); | |
var changing = this._changing; | |
this._changing = true; | |
// Silent changes become pending changes. | |
for (var attr in this._silent) this._pending[attr] = true; | |
// Silent changes are triggered. | |
var changes = _.extend({}, options.changes, this._silent); | |
this._silent = {}; | |
for (var attr in changes) { | |
this.trigger('change:' + attr, this, this.get(attr), options); | |
} | |
if (changing) return this; | |
// Continue firing `"change"` events while there are pending changes. | |
while (!_.isEmpty(this._pending)) { | |
this._pending = {}; | |
this.trigger('change', this, options); | |
// Pending and silent changes still remain. | |
for (var attr in this.changed) { | |
if (this._pending[attr] || this._silent[attr]) continue; | |
delete this.changed[attr]; | |
} | |
this._previousAttributes = _.clone(this.attributes); | |
} | |
this._changing = false; | |
return this; | |
}, | |
// Determine if the model has changed since the last `"change"` event. | |
// If you specify an attribute name, determine if that attribute has changed. | |
hasChanged: function(attr) { | |
if (!arguments.length) return !_.isEmpty(this.changed); | |
return _.has(this.changed, attr); | |
}, | |
// Return an object containing all the attributes that have changed, or | |
// false if there are no changed attributes. Useful for determining what | |
// parts of a view need to be updated and/or what attributes need to be | |
// persisted to the server. Unset attributes will be set to undefined. | |
// You can also pass an attributes object to diff against the model, | |
// determining if there *would be* a change. | |
changedAttributes: function(diff) { | |
if (!diff) return this.hasChanged() ? _.clone(this.changed) : false; | |
var val, changed = false, old = this._previousAttributes; | |
for (var attr in diff) { | |
if (_.isEqual(old[attr], (val = diff[attr]))) continue; | |
(changed || (changed = {}))[attr] = val; | |
} | |
return changed; | |
}, | |
// Get the previous value of an attribute, recorded at the time the last | |
// `"change"` event was fired. | |
previous: function(attr) { | |
if (!arguments.length || !this._previousAttributes) return null; | |
return this._previousAttributes[attr]; | |
}, | |
// Get all of the attributes of the model at the time of the previous | |
// `"change"` event. | |
previousAttributes: function() { | |
return _.clone(this._previousAttributes); | |
}, | |
// Check if the model is currently in a valid state. It's only possible to | |
// get into an *invalid* state if you're using silent changes. | |
isValid: function() { | |
return !this.validate(this.attributes); | |
}, | |
// Run validation against the next complete set of model attributes, | |
// returning `true` if all is well. If a specific `error` callback has | |
// been passed, call that instead of firing the general `"error"` event. | |
_validate: function(attrs, options) { | |
if (options.silent || !this.validate) return true; | |
attrs = _.extend({}, this.attributes, attrs); | |
var error = this.validate(attrs, options); | |
if (!error) return true; | |
if (options && options.error) { | |
options.error(this, error, options); | |
} else { | |
this.trigger('error', this, error, options); | |
} | |
return false; | |
} | |
}); | |
// Backbone.Collection | |
// ------------------- | |
// Provides a standard collection class for our sets of models, ordered | |
// or unordered. If a `comparator` is specified, the Collection will maintain | |
// its models in sort order, as they're added and removed. | |
var Collection = Backbone.Collection = function(models, options) { | |
options || (options = {}); | |
if (options.model) this.model = options.model; | |
if (options.comparator) this.comparator = options.comparator; | |
this._reset(); | |
this.initialize.apply(this, arguments); | |
if (models) this.reset(models, {silent: true, parse: options.parse}); | |
}; | |
// Define the Collection's inheritable methods. | |
_.extend(Collection.prototype, Events, { | |
// The default model for a collection is just a **Backbone.Model**. | |
// This should be overridden in most cases. | |
model: Model, | |
// Initialize is an empty function by default. Override it with your own | |
// initialization logic. | |
initialize: function(){}, | |
// The JSON representation of a Collection is an array of the | |
// models' attributes. | |
toJSON: function(options) { | |
return this.map(function(model){ return model.toJSON(options); }); | |
}, | |
// Add a model, or list of models to the set. Pass **silent** to avoid | |
// firing the `add` event for every new model. | |
add: function(models, options) { | |
var i, index, length, model, cid, id, cids = {}, ids = {}, dups = []; | |
options || (options = {}); | |
models = _.isArray(models) ? models.slice() : [models]; | |
// Begin by turning bare objects into model references, and preventing | |
// invalid models or duplicate models from being added. | |
for (i = 0, length = models.length; i < length; i++) { | |
if (!(model = models[i] = this._prepareModel(models[i], options))) { | |
throw new Error("Can't add an invalid model to a collection"); | |
} | |
cid = model.cid; | |
id = model.id; | |
if (cids[cid] || this._byCid[cid] || ((id != null) && (ids[id] || this._byId[id]))) { | |
dups.push(i); | |
continue; | |
} | |
cids[cid] = ids[id] = model; | |
} | |
// Remove duplicates. | |
i = dups.length; | |
while (i--) { | |
models.splice(dups[i], 1); | |
} | |
// Listen to added models' events, and index models for lookup by | |
// `id` and by `cid`. | |
for (i = 0, length = models.length; i < length; i++) { | |
(model = models[i]).on('all', this._onModelEvent, this); | |
this._byCid[model.cid] = model; | |
if (model.id != null) this._byId[model.id] = model; | |
} | |
// Insert models into the collection, re-sorting if needed, and triggering | |
// `add` events unless silenced. | |
this.length += length; | |
index = options.at != null ? options.at : this.models.length; | |
splice.apply(this.models, [index, 0].concat(models)); | |
if (this.comparator) this.sort({silent: true}); | |
if (options.silent) return this; | |
for (i = 0, length = this.models.length; i < length; i++) { | |
if (!cids[(model = this.models[i]).cid]) continue; | |
options.index = i; | |
model.trigger('add', model, this, options); | |
} | |
return this; | |
}, | |
// Remove a model, or a list of models from the set. Pass silent to avoid | |
// firing the `remove` event for every model removed. | |
remove: function(models, options) { | |
var i, l, index, model; | |
options || (options = {}); | |
models = _.isArray(models) ? models.slice() : [models]; | |
for (i = 0, l = models.length; i < l; i++) { | |
model = this.getByCid(models[i]) || this.get(models[i]); | |
if (!model) continue; | |
delete this._byId[model.id]; | |
delete this._byCid[model.cid]; | |
index = this.indexOf(model); | |
this.models.splice(index, 1); | |
this.length--; | |
if (!options.silent) { | |
options.index = index; | |
model.trigger('remove', model, this, options); | |
} | |
this._removeReference(model); | |
} | |
return this; | |
}, | |
// Add a model to the end of the collection. | |
push: function(model, options) { | |
model = this._prepareModel(model, options); | |
this.add(model, options); | |
return model; | |
}, | |
// Remove a model from the end of the collection. | |
pop: function(options) { | |
var model = this.at(this.length - 1); | |
this.remove(model, options); | |
return model; | |
}, | |
// Add a model to the beginning of the collection. | |
unshift: function(model, options) { | |
model = this._prepareModel(model, options); | |
this.add(model, _.extend({at: 0}, options)); | |
return model; | |
}, | |
// Remove a model from the beginning of the collection. | |
shift: function(options) { | |
var model = this.at(0); | |
this.remove(model, options); | |
return model; | |
}, | |
// Get a model from the set by id. | |
get: function(id) { | |
if (id == null) return void 0; | |
return this._byId[id.id != null ? id.id : id]; | |
}, | |
// Get a model from the set by client id. | |
getByCid: function(cid) { | |
return cid && this._byCid[cid.cid || cid]; | |
}, | |
// Get the model at the given index. | |
at: function(index) { | |
return this.models[index]; | |
}, | |
// Return models with matching attributes. Useful for simple cases of `filter`. | |
where: function(attrs) { | |
if (_.isEmpty(attrs)) return []; | |
return this.filter(function(model) { | |
for (var key in attrs) { | |
if (attrs[key] !== model.get(key)) return false; | |
} | |
return true; | |
}); | |
}, | |
// Force the collection to re-sort itself. You don't need to call this under | |
// normal circumstances, as the set will maintain sort order as each item | |
// is added. | |
sort: function(options) { | |
options || (options = {}); | |
if (!this.comparator) throw new Error('Cannot sort a set without a comparator'); | |
var boundComparator = _.bind(this.comparator, this); | |
if (this.comparator.length == 1) { | |
this.models = this.sortBy(boundComparator); | |
} else { | |
this.models.sort(boundComparator); | |
} | |
if (!options.silent) this.trigger('reset', this, options); | |
return this; | |
}, | |
// Pluck an attribute from each model in the collection. | |
pluck: function(attr) { | |
return _.map(this.models, function(model){ return model.get(attr); }); | |
}, | |
// When you have more items than you want to add or remove individually, | |
// you can reset the entire set with a new list of models, without firing | |
// any `add` or `remove` events. Fires `reset` when finished. | |
reset: function(models, options) { | |
models || (models = []); | |
options || (options = {}); | |
for (var i = 0, l = this.models.length; i < l; i++) { | |
this._removeReference(this.models[i]); | |
} | |
this._reset(); | |
this.add(models, _.extend({silent: true}, options)); | |
if (!options.silent) this.trigger('reset', this, options); | |
return this; | |
}, | |
// Fetch the default set of models for this collection, resetting the | |
// collection when they arrive. If `add: true` is passed, appends the | |
// models to the collection instead of resetting. | |
fetch: function(options) { | |
options = options ? _.clone(options) : {}; | |
if (options.parse === undefined) options.parse = true; | |
var collection = this; | |
var success = options.success; | |
options.success = function(resp, status, xhr) { | |
collection[options.add ? 'add' : 'reset'](collection.parse(resp, xhr), options); | |
if (success) success(collection, resp); | |
}; | |
options.error = Backbone.wrapError(options.error, collection, options); | |
return (this.sync || Backbone.sync).call(this, 'read', this, options); | |
}, | |
// Create a new instance of a model in this collection. Add the model to the | |
// collection immediately, unless `wait: true` is passed, in which case we | |
// wait for the server to agree. | |
create: function(model, options) { | |
var coll = this; | |
options = options ? _.clone(options) : {}; | |
model = this._prepareModel(model, options); | |
if (!model) return false; | |
if (!options.wait) coll.add(model, options); | |
var success = options.success; | |
options.success = function(nextModel, resp, xhr) { | |
if (options.wait) coll.add(nextModel, options); | |
if (success) { | |
success(nextModel, resp); | |
} else { | |
nextModel.trigger('sync', model, resp, options); | |
} | |
}; | |
model.save(null, options); | |
return model; | |
}, | |
// **parse** converts a response into a list of models to be added to the | |
// collection. The default implementation is just to pass it through. | |
parse: function(resp, xhr) { | |
return resp; | |
}, | |
// Proxy to _'s chain. Can't be proxied the same way the rest of the | |
// underscore methods are proxied because it relies on the underscore | |
// constructor. | |
chain: function () { | |
return _(this.models).chain(); | |
}, | |
// Reset all internal state. Called when the collection is reset. | |
_reset: function(options) { | |
this.length = 0; | |
this.models = []; | |
this._byId = {}; | |
this._byCid = {}; | |
}, | |
// Prepare a model or hash of attributes to be added to this collection. | |
_prepareModel: function(model, options) { | |
options || (options = {}); | |
if (!(model instanceof Model)) { | |
var attrs = model; | |
options.collection = this; | |
model = new this.model(attrs, options); | |
if (!model._validate(model.attributes, options)) model = false; | |
} else if (!model.collection) { | |
model.collection = this; | |
} | |
return model; | |
}, | |
// Internal method to remove a model's ties to a collection. | |
_removeReference: function(model) { | |
if (this == model.collection) { | |
delete model.collection; | |
} | |
model.off('all', this._onModelEvent, this); | |
}, | |
// Internal method called every time a model in the set fires an event. | |
// Sets need to update their indexes when models change ids. All other | |
// events simply proxy through. "add" and "remove" events that originate | |
// in other collections are ignored. | |
_onModelEvent: function(event, model, collection, options) { | |
if ((event == 'add' || event == 'remove') && collection != this) return; | |
if (event == 'destroy') { | |
this.remove(model, options); | |
} | |
if (model && event === 'change:' + model.idAttribute) { | |
delete this._byId[model.previous(model.idAttribute)]; | |
this._byId[model.id] = model; | |
} | |
this.trigger.apply(this, arguments); | |
} | |
}); | |
// Underscore methods that we want to implement on the Collection. | |
var methods = ['forEach', 'each', 'map', 'reduce', 'reduceRight', 'find', | |
'detect', 'filter', 'select', 'reject', 'every', 'all', 'some', 'any', | |
'include', 'contains', 'invoke', 'max', 'min', 'sortBy', 'sortedIndex', | |
'toArray', 'size', 'first', 'initial', 'rest', 'last', 'without', 'indexOf', | |
'shuffle', 'lastIndexOf', 'isEmpty', 'groupBy']; | |
// Mix in each Underscore method as a proxy to `Collection#models`. | |
_.each(methods, function(method) { | |
Collection.prototype[method] = function() { | |
return _[method].apply(_, [this.models].concat(_.toArray(arguments))); | |
}; | |
}); | |
// Backbone.Router | |
// ------------------- | |
// Routers map faux-URLs to actions, and fire events when routes are | |
// matched. Creating a new one sets its `routes` hash, if not set statically. | |
var Router = Backbone.Router = function(options) { | |
options || (options = {}); | |
if (options.routes) this.routes = options.routes; | |
this._bindRoutes(); | |
this.initialize.apply(this, arguments); | |
}; | |
// Cached regular expressions for matching named param parts and splatted | |
// parts of route strings. | |
var namedParam = /:\w+/g; | |
var splatParam = /\*\w+/g; | |
var escapeRegExp = /[-[\]{}()+?.,\\^$|#\s]/g; | |
// Set up all inheritable **Backbone.Router** properties and methods. | |
_.extend(Router.prototype, Events, { | |
// Initialize is an empty function by default. Override it with your own | |
// initialization logic. | |
initialize: function(){}, | |
// Manually bind a single named route to a callback. For example: | |
// | |
// this.route('search/:query/p:num', 'search', function(query, num) { | |
// ... | |
// }); | |
// | |
route: function(route, name, callback) { | |
Backbone.history || (Backbone.history = new History); | |
if (!_.isRegExp(route)) route = this._routeToRegExp(route); | |
if (!callback) callback = this[name]; | |
Backbone.history.route(route, _.bind(function(fragment) { | |
var args = this._extractParameters(route, fragment); | |
callback && callback.apply(this, args); | |
this.trigger.apply(this, ['route:' + name].concat(args)); | |
Backbone.history.trigger('route', this, name, args); | |
}, this)); | |
return this; | |
}, | |
// Simple proxy to `Backbone.history` to save a fragment into the history. | |
navigate: function(fragment, options) { | |
Backbone.history.navigate(fragment, options); | |
}, | |
// Bind all defined routes to `Backbone.history`. We have to reverse the | |
// order of the routes here to support behavior where the most general | |
// routes can be defined at the bottom of the route map. | |
_bindRoutes: function() { | |
if (!this.routes) return; | |
var routes = []; | |
for (var route in this.routes) { | |
routes.unshift([route, this.routes[route]]); | |
} | |
for (var i = 0, l = routes.length; i < l; i++) { | |
this.route(routes[i][0], routes[i][1], this[routes[i][1]]); | |
} | |
}, | |
// Convert a route string into a regular expression, suitable for matching | |
// against the current location hash. | |
_routeToRegExp: function(route) { | |
route = route.replace(escapeRegExp, '\\$&') | |
.replace(namedParam, '([^\/]+)') | |
.replace(splatParam, '(.*?)'); | |
return new RegExp('^' + route + '$'); | |
}, | |
// Given a route, and a URL fragment that it matches, return the array of | |
// extracted parameters. | |
_extractParameters: function(route, fragment) { | |
return route.exec(fragment).slice(1); | |
} | |
}); | |
// Backbone.History | |
// ---------------- | |
// Handles cross-browser history management, based on URL fragments. If the | |
// browser does not support `onhashchange`, falls back to polling. | |
var History = Backbone.History = function() { | |
this.handlers = []; | |
_.bindAll(this, 'checkUrl'); | |
}; | |
// Cached regex for cleaning leading hashes and slashes . | |
var routeStripper = /^[#\/]/; | |
// Cached regex for detecting MSIE. | |
var isExplorer = /msie [\w.]+/; | |
// Has the history handling already been started? | |
History.started = false; | |
// Set up all inheritable **Backbone.History** properties and methods. | |
_.extend(History.prototype, Events, { | |
// The default interval to poll for hash changes, if necessary, is | |
// twenty times a second. | |
interval: 50, | |
// Gets the true hash value. Cannot use location.hash directly due to bug | |
// in Firefox where location.hash will always be decoded. | |
getHash: function(windowOverride) { | |
var loc = windowOverride ? windowOverride.location : window.location; | |
var match = loc.href.match(/#(.*)$/); | |
return match ? match[1] : ''; | |
}, | |
// Get the cross-browser normalized URL fragment, either from the URL, | |
// the hash, or the override. | |
getFragment: function(fragment, forcePushState) { | |
if (fragment == null) { | |
if (this._hasPushState || forcePushState) { | |
fragment = window.location.pathname; | |
var search = window.location.search; | |
if (search) fragment += search; | |
} else { | |
fragment = this.getHash(); | |
} | |
} | |
if (!fragment.indexOf(this.options.root)) fragment = fragment.substr(this.options.root.length); | |
return fragment.replace(routeStripper, ''); | |
}, | |
// Start the hash change handling, returning `true` if the current URL matches | |
// an existing route, and `false` otherwise. | |
start: function(options) { | |
if (History.started) throw new Error("Backbone.history has already been started"); | |
History.started = true; | |
// Figure out the initial configuration. Do we need an iframe? | |
// Is pushState desired ... is it available? | |
this.options = _.extend({}, {root: '/'}, this.options, options); | |
this._wantsHashChange = this.options.hashChange !== false; | |
this._wantsPushState = !!this.options.pushState; | |
this._hasPushState = !!(this.options.pushState && window.history && window.history.pushState); | |
var fragment = this.getFragment(); | |
var docMode = document.documentMode; | |
var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7)); | |
if (oldIE) { | |
this.iframe = $('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow; | |
this.navigate(fragment); | |
} | |
// Depending on whether we're using pushState or hashes, and whether | |
// 'onhashchange' is supported, determine how we check the URL state. | |
if (this._hasPushState) { | |
$(window).bind('popstate', this.checkUrl); | |
} else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) { | |
$(window).bind('hashchange', this.checkUrl); | |
} else if (this._wantsHashChange) { | |
this._checkUrlInterval = setInterval(this.checkUrl, this.interval); | |
} | |
// Determine if we need to change the base url, for a pushState link | |
// opened by a non-pushState browser. | |
this.fragment = fragment; | |
var loc = window.location; | |
var atRoot = loc.pathname == this.options.root; | |
// If we've started off with a route from a `pushState`-enabled browser, | |
// but we're currently in a browser that doesn't support it... | |
if (this._wantsHashChange && this._wantsPushState && !this._hasPushState && !atRoot) { | |
this.fragment = this.getFragment(null, true); | |
window.location.replace(this.options.root + '#' + this.fragment); | |
// Return immediately as browser will do redirect to new url | |
return true; | |
// Or if we've started out with a hash-based route, but we're currently | |
// in a browser where it could be `pushState`-based instead... | |
} else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) { | |
this.fragment = this.getHash().replace(routeStripper, ''); | |
window.history.replaceState({}, document.title, loc.protocol + '//' + loc.host + this.options.root + this.fragment); | |
} | |
if (!this.options.silent) { | |
return this.loadUrl(); | |
} | |
}, | |
// Disable Backbone.history, perhaps temporarily. Not useful in a real app, | |
// but possibly useful for unit testing Routers. | |
stop: function() { | |
$(window).unbind('popstate', this.checkUrl).unbind('hashchange', this.checkUrl); | |
clearInterval(this._checkUrlInterval); | |
History.started = false; | |
}, | |
// Add a route to be tested when the fragment changes. Routes added later | |
// may override previous routes. | |
route: function(route, callback) { | |
this.handlers.unshift({route: route, callback: callback}); | |
}, | |
// Checks the current URL to see if it has changed, and if it has, | |
// calls `loadUrl`, normalizing across the hidden iframe. | |
checkUrl: function(e) { | |
var current = this.getFragment(); | |
if (current == this.fragment && this.iframe) current = this.getFragment(this.getHash(this.iframe)); | |
if (current == this.fragment) return false; | |
if (this.iframe) this.navigate(current); | |
this.loadUrl() || this.loadUrl(this.getHash()); | |
}, | |
// Attempt to load the current URL fragment. If a route succeeds with a | |
// match, returns `true`. If no defined routes matches the fragment, | |
// returns `false`. | |
loadUrl: function(fragmentOverride) { | |
var fragment = this.fragment = this.getFragment(fragmentOverride); | |
var matched = _.any(this.handlers, function(handler) { | |
if (handler.route.test(fragment)) { | |
handler.callback(fragment); | |
return true; | |
} | |
}); | |
return matched; | |
}, | |
// Save a fragment into the hash history, or replace the URL state if the | |
// 'replace' option is passed. You are responsible for properly URL-encoding | |
// the fragment in advance. | |
// | |
// The options object can contain `trigger: true` if you wish to have the | |
// route callback be fired (not usually desirable), or `replace: true`, if | |
// you wish to modify the current URL without adding an entry to the history. | |
navigate: function(fragment, options) { | |
if (!History.started) return false; | |
if (!options || options === true) options = {trigger: options}; | |
var frag = (fragment || '').replace(routeStripper, ''); | |
if (this.fragment == frag) return; | |
// If pushState is available, we use it to set the fragment as a real URL. | |
if (this._hasPushState) { | |
if (frag.indexOf(this.options.root) != 0) frag = this.options.root + frag; | |
this.fragment = frag; | |
window.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, frag); | |
// If hash changes haven't been explicitly disabled, update the hash | |
// fragment to store history. | |
} else if (this._wantsHashChange) { | |
this.fragment = frag; | |
this._updateHash(window.location, frag, options.replace); | |
if (this.iframe && (frag != this.getFragment(this.getHash(this.iframe)))) { | |
// Opening and closing the iframe tricks IE7 and earlier to push a history entry on hash-tag change. | |
// When replace is true, we don't want this. | |
if(!options.replace) this.iframe.document.open().close(); | |
this._updateHash(this.iframe.location, frag, options.replace); | |
} | |
// If you've told us that you explicitly don't want fallback hashchange- | |
// based history, then `navigate` becomes a page refresh. | |
} else { | |
window.location.assign(this.options.root + fragment); | |
} | |
if (options.trigger) this.loadUrl(fragment); | |
}, | |
// Update the hash location, either replacing the current entry, or adding | |
// a new one to the browser history. | |
_updateHash: function(location, fragment, replace) { | |
if (replace) { | |
location.replace(location.toString().replace(/(javascript:|#).*$/, '') + '#' + fragment); | |
} else { | |
location.hash = fragment; | |
} | |
} | |
}); | |
// Backbone.View | |
// ------------- | |
// Creating a Backbone.View creates its initial element outside of the DOM, | |
// if an existing element is not provided... | |
var View = Backbone.View = function(options) { | |
this.cid = _.uniqueId('view'); | |
this._configure(options || {}); | |
this._ensureElement(); | |
this.initialize.apply(this, arguments); | |
this.delegateEvents(); | |
}; | |
// Cached regex to split keys for `delegate`. | |
var delegateEventSplitter = /^(\S+)\s*(.*)$/; | |
// List of view options to be merged as properties. | |
var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName']; | |
// Set up all inheritable **Backbone.View** properties and methods. | |
_.extend(View.prototype, Events, { | |
// The default `tagName` of a View's element is `"div"`. | |
tagName: 'div', | |
// jQuery delegate for element lookup, scoped to DOM elements within the | |
// current view. This should be prefered to global lookups where possible. | |
$: function(selector) { | |
return this.$el.find(selector); | |
}, | |
// Initialize is an empty function by default. Override it with your own | |
// initialization logic. | |
initialize: function(){}, | |
// **render** is the core function that your view should override, in order | |
// to populate its element (`this.el`), with the appropriate HTML. The | |
// convention is for **render** to always return `this`. | |
render: function() { | |
return this; | |
}, | |
// Remove this view from the DOM. Note that the view isn't present in the | |
// DOM by default, so calling this method may be a no-op. | |
remove: function() { | |
this.$el.remove(); | |
return this; | |
}, | |
// For small amounts of DOM Elements, where a full-blown template isn't | |
// needed, use **make** to manufacture elements, one at a time. | |
// | |
// var el = this.make('li', {'class': 'row'}, this.model.escape('title')); | |
// | |
make: function(tagName, attributes, content) { | |
var el = document.createElement(tagName); | |
if (attributes) $(el).attr(attributes); | |
if (content) $(el).html(content); | |
return el; | |
}, | |
// Change the view's element (`this.el` property), including event | |
// re-delegation. | |
setElement: function(element, delegate) { | |
if (this.$el) this.undelegateEvents(); | |
this.$el = (element instanceof $) ? element : $(element); | |
this.el = this.$el[0]; | |
if (delegate !== false) this.delegateEvents(); | |
return this; | |
}, | |
// Set callbacks, where `this.events` is a hash of | |
// | |
// *{"event selector": "callback"}* | |
// | |
// { | |
// 'mousedown .title': 'edit', | |
// 'click .button': 'save' | |
// 'click .open': function(e) { ... } | |
// } | |
// | |
// pairs. Callbacks will be bound to the view, with `this` set properly. | |
// Uses event delegation for efficiency. | |
// Omitting the selector binds the event to `this.el`. | |
// This only works for delegate-able events: not `focus`, `blur`, and | |
// not `change`, `submit`, and `reset` in Internet Explorer. | |
delegateEvents: function(events) { | |
if (!(events || (events = getValue(this, 'events')))) return; | |
this.undelegateEvents(); | |
for (var key in events) { | |
var method = events[key]; | |
if (!_.isFunction(method)) method = this[events[key]]; | |
if (!method) throw new Error('Method "' + events[key] + '" does not exist'); | |
var match = key.match(delegateEventSplitter); | |
var eventName = match[1], selector = match[2]; | |
method = _.bind(method, this); | |
eventName += '.delegateEvents' + this.cid; | |
if (selector === '') { | |
this.$el.bind(eventName, method); | |
} else { | |
this.$el.delegate(selector, eventName, method); | |
} | |
} | |
}, | |
// Clears all callbacks previously bound to the view with `delegateEvents`. | |
// You usually don't need to use this, but may wish to if you have multiple | |
// Backbone views attached to the same DOM element. | |
undelegateEvents: function() { | |
this.$el.unbind('.delegateEvents' + this.cid); | |
}, | |
// Performs the initial configuration of a View with a set of options. | |
// Keys with special meaning *(model, collection, id, className)*, are | |
// attached directly to the view. | |
_configure: function(options) { | |
if (this.options) options = _.extend({}, this.options, options); | |
for (var i = 0, l = viewOptions.length; i < l; i++) { | |
var attr = viewOptions[i]; | |
if (options[attr]) this[attr] = options[attr]; | |
} | |
this.options = options; | |
}, | |
// Ensure that the View has a DOM element to render into. | |
// If `this.el` is a string, pass it through `$()`, take the first | |
// matching element, and re-assign it to `el`. Otherwise, create | |
// an element from the `id`, `className` and `tagName` properties. | |
_ensureElement: function() { | |
if (!this.el) { | |
var attrs = getValue(this, 'attributes') || {}; | |
if (this.id) attrs.id = this.id; | |
if (this.className) attrs['class'] = this.className; | |
this.setElement(this.make(this.tagName, attrs), false); | |
} else { | |
this.setElement(this.el, false); | |
} | |
} | |
}); | |
// The self-propagating extend function that Backbone classes use. | |
var extend = function (protoProps, classProps) { | |
var child = inherits(this, protoProps, classProps); | |
child.extend = this.extend; | |
return child; | |
}; | |
// Set up inheritance for the model, collection, and view. | |
Model.extend = Collection.extend = Router.extend = View.extend = extend; | |
// Backbone.sync | |
// ------------- | |
// Map from CRUD to HTTP for our default `Backbone.sync` implementation. | |
var methodMap = { | |
'create': 'POST', | |
'update': 'PUT', | |
'delete': 'DELETE', | |
'read': 'GET' | |
}; | |
// Override this function to change the manner in which Backbone persists | |
// models to the server. You will be passed the type of request, and the | |
// model in question. By default, makes a RESTful Ajax request | |
// to the model's `url()`. Some possible customizations could be: | |
// | |
// * Use `setTimeout` to batch rapid-fire updates into a single request. | |
// * Send up the models as XML instead of JSON. | |
// * Persist models via WebSockets instead of Ajax. | |
// | |
// Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests | |
// as `POST`, with a `_method` parameter containing the true HTTP method, | |
// as well as all requests with the body as `application/x-www-form-urlencoded` | |
// instead of `application/json` with the model in a param named `model`. | |
// Useful when interfacing with server-side languages like **PHP** that make | |
// it difficult to read the body of `PUT` requests. | |
Backbone.sync = function(method, model, options) { | |
var type = methodMap[method]; | |
// Default options, unless specified. | |
options || (options = {}); | |
// Default JSON-request options. | |
var params = {type: type, dataType: 'json'}; | |
// Ensure that we have a URL. | |
if (!options.url) { | |
params.url = getValue(model, 'url') || urlError(); | |
} | |
// Ensure that we have the appropriate request data. | |
if (!options.data && model && (method == 'create' || method == 'update')) { | |
params.contentType = 'application/json'; | |
params.data = JSON.stringify(model.toJSON()); | |
} | |
// For older servers, emulate JSON by encoding the request into an HTML-form. | |
if (Backbone.emulateJSON) { | |
params.contentType = 'application/x-www-form-urlencoded'; | |
params.data = params.data ? {model: params.data} : {}; | |
} | |
// For older servers, emulate HTTP by mimicking the HTTP method with `_method` | |
// And an `X-HTTP-Method-Override` header. | |
if (Backbone.emulateHTTP) { | |
if (type === 'PUT' || type === 'DELETE') { | |
if (Backbone.emulateJSON) params.data._method = type; | |
params.type = 'POST'; | |
params.beforeSend = function(xhr) { | |
xhr.setRequestHeader('X-HTTP-Method-Override', type); | |
}; | |
} | |
} | |
// Don't process data on a non-GET request. | |
if (params.type !== 'GET' && !Backbone.emulateJSON) { | |
params.processData = false; | |
} | |
// Make the request, allowing the user to override any Ajax options. | |
return $.ajax(_.extend(params, options)); | |
}; | |
// Wrap an optional error callback with a fallback error event. | |
Backbone.wrapError = function(onError, originalModel, options) { | |
return function(model, resp) { | |
resp = model === originalModel ? resp : model; | |
if (onError) { | |
onError(originalModel, resp, options); | |
} else { | |
originalModel.trigger('error', originalModel, resp, options); | |
} | |
}; | |
}; | |
// Helpers | |
// ------- | |
// Shared empty constructor function to aid in prototype-chain creation. | |
var ctor = function(){}; | |
// Helper function to correctly set up the prototype chain, for subclasses. | |
// Similar to `goog.inherits`, but uses a hash of prototype properties and | |
// class properties to be extended. | |
var inherits = function(parent, protoProps, staticProps) { | |
var child; | |
// The constructor function for the new subclass is either defined by you | |
// (the "constructor" property in your `extend` definition), or defaulted | |
// by us to simply call the parent's constructor. | |
if (protoProps && protoProps.hasOwnProperty('constructor')) { | |
child = protoProps.constructor; | |
} else { | |
child = function(){ parent.apply(this, arguments); }; | |
} | |
// Inherit class (static) properties from parent. | |
_.extend(child, parent); | |
// Set the prototype chain to inherit from `parent`, without calling | |
// `parent`'s constructor function. | |
ctor.prototype = parent.prototype; | |
child.prototype = new ctor(); | |
// Add prototype properties (instance properties) to the subclass, | |
// if supplied. | |
if (protoProps) _.extend(child.prototype, protoProps); | |
// Add static properties to the constructor function, if supplied. | |
if (staticProps) _.extend(child, staticProps); | |
// Correctly set child's `prototype.constructor`. | |
child.prototype.constructor = child; | |
// Set a convenience property in case the parent's prototype is needed later. | |
child.__super__ = parent.prototype; | |
return child; | |
}; | |
// Helper function to get a value from a Backbone object as a property | |
// or as a function. | |
var getValue = function(object, prop) { | |
if (!(object && object[prop])) return null; | |
return _.isFunction(object[prop]) ? object[prop]() : object[prop]; | |
}; | |
// Throw an error when a URL is needed, and none is supplied. | |
var urlError = function() { | |
throw new Error('A "url" property or function must be specified'); | |
}; | |
}).call(this); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com | |
* | |
* This software is provided 'as-is', without any express or implied | |
* warranty. In no event will the authors be held liable for any damages | |
* arising from the use of this software. | |
* Permission is granted to anyone to use this software for any purpose, | |
* including commercial applications, and to alter it and redistribute it | |
* freely, subject to the following restrictions: | |
* 1. The origin of this software must not be misrepresented; you must not | |
* claim that you wrote the original software. If you use this software | |
* in a product, an acknowledgment in the product documentation would be | |
* appreciated but is not required. | |
* 2. Altered source versions must be plainly marked as such, and must not be | |
* misrepresented as being the original software. | |
* 3. This notice may not be removed or altered from any source distribution. | |
*/ | |
var Box2D = {}; | |
(function (a2j, undefined) { | |
if(!(Object.prototype.defineProperty instanceof Function) | |
&& Object.prototype.__defineGetter__ instanceof Function | |
&& Object.prototype.__defineSetter__ instanceof Function) | |
{ | |
Object.defineProperty = function(obj, p, cfg) { | |
if(cfg.get instanceof Function) | |
obj.__defineGetter__(p, cfg.get); | |
if(cfg.set instanceof Function) | |
obj.__defineSetter__(p, cfg.set); | |
} | |
} | |
function emptyFn() {}; | |
a2j.inherit = function(cls, base) { | |
var tmpCtr = cls; | |
emptyFn.prototype = base.prototype; | |
cls.prototype = new emptyFn; | |
cls.prototype.constructor = tmpCtr; | |
}; | |
a2j.generateCallback = function generateCallback(context, cb) { | |
return function () { | |
cb.apply(context, arguments); | |
}; | |
}; | |
a2j.NVector = function NVector(length) { | |
if (length === undefined) length = 0; | |
var tmp = new Array(length || 0); | |
for (var i = 0; i < length; ++i) | |
tmp[i] = 0; | |
return tmp; | |
}; | |
a2j.is = function is(o1, o2) { | |
if (o1 === null) return false; | |
if ((o2 instanceof Function) && (o1 instanceof o2)) return true; | |
if ((o1.constructor.__implements != undefined) && (o1.constructor.__implements[o2])) return true; | |
return false; | |
}; | |
a2j.parseUInt = function(v) { | |
return Math.abs(parseInt(v)); | |
} | |
})(Box2D); | |
//#TODO remove assignments from global namespace | |
var Vector = Array; | |
var Vector_a2j_Number = Box2D.NVector; | |
//package structure | |
if (typeof(Box2D) === "undefined") Box2D = {}; | |
if (typeof(Box2D.Collision) === "undefined") Box2D.Collision = {}; | |
if (typeof(Box2D.Collision.Shapes) === "undefined") Box2D.Collision.Shapes = {}; | |
if (typeof(Box2D.Common) === "undefined") Box2D.Common = {}; | |
if (typeof(Box2D.Common.Math) === "undefined") Box2D.Common.Math = {}; | |
if (typeof(Box2D.Dynamics) === "undefined") Box2D.Dynamics = {}; | |
if (typeof(Box2D.Dynamics.Contacts) === "undefined") Box2D.Dynamics.Contacts = {}; | |
if (typeof(Box2D.Dynamics.Controllers) === "undefined") Box2D.Dynamics.Controllers = {}; | |
if (typeof(Box2D.Dynamics.Joints) === "undefined") Box2D.Dynamics.Joints = {}; | |
//pre-definitions | |
(function () { | |
Box2D.Collision.IBroadPhase = 'Box2D.Collision.IBroadPhase'; | |
function b2AABB() { | |
b2AABB.b2AABB.apply(this, arguments); | |
}; | |
Box2D.Collision.b2AABB = b2AABB; | |
function b2Bound() { | |
b2Bound.b2Bound.apply(this, arguments); | |
}; | |
Box2D.Collision.b2Bound = b2Bound; | |
function b2BoundValues() { | |
b2BoundValues.b2BoundValues.apply(this, arguments); | |
if (this.constructor === b2BoundValues) this.b2BoundValues.apply(this, arguments); | |
}; | |
Box2D.Collision.b2BoundValues = b2BoundValues; | |
function b2Collision() { | |
b2Collision.b2Collision.apply(this, arguments); | |
}; | |
Box2D.Collision.b2Collision = b2Collision; | |
function b2ContactID() { | |
b2ContactID.b2ContactID.apply(this, arguments); | |
if (this.constructor === b2ContactID) this.b2ContactID.apply(this, arguments); | |
}; | |
Box2D.Collision.b2ContactID = b2ContactID; | |
function b2ContactPoint() { | |
b2ContactPoint.b2ContactPoint.apply(this, arguments); | |
}; | |
Box2D.Collision.b2ContactPoint = b2ContactPoint; | |
function b2Distance() { | |
b2Distance.b2Distance.apply(this, arguments); | |
}; | |
Box2D.Collision.b2Distance = b2Distance; | |
function b2DistanceInput() { | |
b2DistanceInput.b2DistanceInput.apply(this, arguments); | |
}; | |
Box2D.Collision.b2DistanceInput = b2DistanceInput; | |
function b2DistanceOutput() { | |
b2DistanceOutput.b2DistanceOutput.apply(this, arguments); | |
}; | |
Box2D.Collision.b2DistanceOutput = b2DistanceOutput; | |
function b2DistanceProxy() { | |
b2DistanceProxy.b2DistanceProxy.apply(this, arguments); | |
}; | |
Box2D.Collision.b2DistanceProxy = b2DistanceProxy; | |
function b2DynamicTree() { | |
b2DynamicTree.b2DynamicTree.apply(this, arguments); | |
if (this.constructor === b2DynamicTree) this.b2DynamicTree.apply(this, arguments); | |
}; | |
Box2D.Collision.b2DynamicTree = b2DynamicTree; | |
function b2DynamicTreeBroadPhase() { | |
b2DynamicTreeBroadPhase.b2DynamicTreeBroadPhase.apply(this, arguments); | |
}; | |
Box2D.Collision.b2DynamicTreeBroadPhase = b2DynamicTreeBroadPhase; | |
function b2DynamicTreeNode() { | |
b2DynamicTreeNode.b2DynamicTreeNode.apply(this, arguments); | |
}; | |
Box2D.Collision.b2DynamicTreeNode = b2DynamicTreeNode; | |
function b2DynamicTreePair() { | |
b2DynamicTreePair.b2DynamicTreePair.apply(this, arguments); | |
}; | |
Box2D.Collision.b2DynamicTreePair = b2DynamicTreePair; | |
function b2Manifold() { | |
b2Manifold.b2Manifold.apply(this, arguments); | |
if (this.constructor === b2Manifold) this.b2Manifold.apply(this, arguments); | |
}; | |
Box2D.Collision.b2Manifold = b2Manifold; | |
function b2ManifoldPoint() { | |
b2ManifoldPoint.b2ManifoldPoint.apply(this, arguments); | |
if (this.constructor === b2ManifoldPoint) this.b2ManifoldPoint.apply(this, arguments); | |
}; | |
Box2D.Collision.b2ManifoldPoint = b2ManifoldPoint; | |
function b2Point() { | |
b2Point.b2Point.apply(this, arguments); | |
}; | |
Box2D.Collision.b2Point = b2Point; | |
function b2RayCastInput() { | |
b2RayCastInput.b2RayCastInput.apply(this, arguments); | |
if (this.constructor === b2RayCastInput) this.b2RayCastInput.apply(this, arguments); | |
}; | |
Box2D.Collision.b2RayCastInput = b2RayCastInput; | |
function b2RayCastOutput() { | |
b2RayCastOutput.b2RayCastOutput.apply(this, arguments); | |
}; | |
Box2D.Collision.b2RayCastOutput = b2RayCastOutput; | |
function b2Segment() { | |
b2Segment.b2Segment.apply(this, arguments); | |
}; | |
Box2D.Collision.b2Segment = b2Segment; | |
function b2SeparationFunction() { | |
b2SeparationFunction.b2SeparationFunction.apply(this, arguments); | |
}; | |
Box2D.Collision.b2SeparationFunction = b2SeparationFunction; | |
function b2Simplex() { | |
b2Simplex.b2Simplex.apply(this, arguments); | |
if (this.constructor === b2Simplex) this.b2Simplex.apply(this, arguments); | |
}; | |
Box2D.Collision.b2Simplex = b2Simplex; | |
function b2SimplexCache() { | |
b2SimplexCache.b2SimplexCache.apply(this, arguments); | |
}; | |
Box2D.Collision.b2SimplexCache = b2SimplexCache; | |
function b2SimplexVertex() { | |
b2SimplexVertex.b2SimplexVertex.apply(this, arguments); | |
}; | |
Box2D.Collision.b2SimplexVertex = b2SimplexVertex; | |
function b2TimeOfImpact() { | |
b2TimeOfImpact.b2TimeOfImpact.apply(this, arguments); | |
}; | |
Box2D.Collision.b2TimeOfImpact = b2TimeOfImpact; | |
function b2TOIInput() { | |
b2TOIInput.b2TOIInput.apply(this, arguments); | |
}; | |
Box2D.Collision.b2TOIInput = b2TOIInput; | |
function b2WorldManifold() { | |
b2WorldManifold.b2WorldManifold.apply(this, arguments); | |
if (this.constructor === b2WorldManifold) this.b2WorldManifold.apply(this, arguments); | |
}; | |
Box2D.Collision.b2WorldManifold = b2WorldManifold; | |
function ClipVertex() { | |
ClipVertex.ClipVertex.apply(this, arguments); | |
}; | |
Box2D.Collision.ClipVertex = ClipVertex; | |
function Features() { | |
Features.Features.apply(this, arguments); | |
}; | |
Box2D.Collision.Features = Features; | |
function b2CircleShape() { | |
b2CircleShape.b2CircleShape.apply(this, arguments); | |
if (this.constructor === b2CircleShape) this.b2CircleShape.apply(this, arguments); | |
}; | |
Box2D.Collision.Shapes.b2CircleShape = b2CircleShape; | |
function b2EdgeChainDef() { | |
b2EdgeChainDef.b2EdgeChainDef.apply(this, arguments); | |
if (this.constructor === b2EdgeChainDef) this.b2EdgeChainDef.apply(this, arguments); | |
}; | |
Box2D.Collision.Shapes.b2EdgeChainDef = b2EdgeChainDef; | |
function b2EdgeShape() { | |
b2EdgeShape.b2EdgeShape.apply(this, arguments); | |
if (this.constructor === b2EdgeShape) this.b2EdgeShape.apply(this, arguments); | |
}; | |
Box2D.Collision.Shapes.b2EdgeShape = b2EdgeShape; | |
function b2MassData() { | |
b2MassData.b2MassData.apply(this, arguments); | |
}; | |
Box2D.Collision.Shapes.b2MassData = b2MassData; | |
function b2PolygonShape() { | |
b2PolygonShape.b2PolygonShape.apply(this, arguments); | |
if (this.constructor === b2PolygonShape) this.b2PolygonShape.apply(this, arguments); | |
}; | |
Box2D.Collision.Shapes.b2PolygonShape = b2PolygonShape; | |
function b2Shape() { | |
b2Shape.b2Shape.apply(this, arguments); | |
if (this.constructor === b2Shape) this.b2Shape.apply(this, arguments); | |
}; | |
Box2D.Collision.Shapes.b2Shape = b2Shape; | |
Box2D.Common.b2internal = 'Box2D.Common.b2internal'; | |
function b2Color() { | |
b2Color.b2Color.apply(this, arguments); | |
if (this.constructor === b2Color) this.b2Color.apply(this, arguments); | |
}; | |
Box2D.Common.b2Color = b2Color; | |
function b2Settings() { | |
b2Settings.b2Settings.apply(this, arguments); | |
}; | |
Box2D.Common.b2Settings = b2Settings; | |
function b2Mat22() { | |
b2Mat22.b2Mat22.apply(this, arguments); | |
if (this.constructor === b2Mat22) this.b2Mat22.apply(this, arguments); | |
}; | |
Box2D.Common.Math.b2Mat22 = b2Mat22; | |
function b2Mat33() { | |
b2Mat33.b2Mat33.apply(this, arguments); | |
if (this.constructor === b2Mat33) this.b2Mat33.apply(this, arguments); | |
}; | |
Box2D.Common.Math.b2Mat33 = b2Mat33; | |
function b2Math() { | |
b2Math.b2Math.apply(this, arguments); | |
}; | |
Box2D.Common.Math.b2Math = b2Math; | |
function b2Sweep() { | |
b2Sweep.b2Sweep.apply(this, arguments); | |
}; | |
Box2D.Common.Math.b2Sweep = b2Sweep; | |
function b2Transform() { | |
b2Transform.b2Transform.apply(this, arguments); | |
if (this.constructor === b2Transform) this.b2Transform.apply(this, arguments); | |
}; | |
Box2D.Common.Math.b2Transform = b2Transform; | |
function b2Vec2() { | |
b2Vec2.b2Vec2.apply(this, arguments); | |
if (this.constructor === b2Vec2) this.b2Vec2.apply(this, arguments); | |
}; | |
Box2D.Common.Math.b2Vec2 = b2Vec2; | |
function b2Vec3() { | |
b2Vec3.b2Vec3.apply(this, arguments); | |
if (this.constructor === b2Vec3) this.b2Vec3.apply(this, arguments); | |
}; | |
Box2D.Common.Math.b2Vec3 = b2Vec3; | |
function b2Body() { | |
b2Body.b2Body.apply(this, arguments); | |
if (this.constructor === b2Body) this.b2Body.apply(this, arguments); | |
}; | |
Box2D.Dynamics.b2Body = b2Body; | |
function b2BodyDef() { | |
b2BodyDef.b2BodyDef.apply(this, arguments); | |
if (this.constructor === b2BodyDef) this.b2BodyDef.apply(this, arguments); | |
}; | |
Box2D.Dynamics.b2BodyDef = b2BodyDef; | |
function b2ContactFilter() { | |
b2ContactFilter.b2ContactFilter.apply(this, arguments); | |
}; | |
Box2D.Dynamics.b2ContactFilter = b2ContactFilter; | |
function b2ContactImpulse() { | |
b2ContactImpulse.b2ContactImpulse.apply(this, arguments); | |
}; | |
Box2D.Dynamics.b2ContactImpulse = b2ContactImpulse; | |
function b2ContactListener() { | |
b2ContactListener.b2ContactListener.apply(this, arguments); | |
}; | |
Box2D.Dynamics.b2ContactListener = b2ContactListener; | |
function b2ContactManager() { | |
b2ContactManager.b2ContactManager.apply(this, arguments); | |
if (this.constructor === b2ContactManager) this.b2ContactManager.apply(this, arguments); | |
}; | |
Box2D.Dynamics.b2ContactManager = b2ContactManager; | |
function b2DebugDraw() { | |
b2DebugDraw.b2DebugDraw.apply(this, arguments); | |
if (this.constructor === b2DebugDraw) this.b2DebugDraw.apply(this, arguments); | |
}; | |
Box2D.Dynamics.b2DebugDraw = b2DebugDraw; | |
function b2DestructionListener() { | |
b2DestructionListener.b2DestructionListener.apply(this, arguments); | |
}; | |
Box2D.Dynamics.b2DestructionListener = b2DestructionListener; | |
function b2FilterData() { | |
b2FilterData.b2FilterData.apply(this, arguments); | |
}; | |
Box2D.Dynamics.b2FilterData = b2FilterData; | |
function b2Fixture() { | |
b2Fixture.b2Fixture.apply(this, arguments); | |
if (this.constructor === b2Fixture) this.b2Fixture.apply(this, arguments); | |
}; | |
Box2D.Dynamics.b2Fixture = b2Fixture; | |
function b2FixtureDef() { | |
b2FixtureDef.b2FixtureDef.apply(this, arguments); | |
if (this.constructor === b2FixtureDef) this.b2FixtureDef.apply(this, arguments); | |
}; | |
Box2D.Dynamics.b2FixtureDef = b2FixtureDef; | |
function b2Island() { | |
b2Island.b2Island.apply(this, arguments); | |
if (this.constructor === b2Island) this.b2Island.apply(this, arguments); | |
}; | |
Box2D.Dynamics.b2Island = b2Island; | |
function b2TimeStep() { | |
b2TimeStep.b2TimeStep.apply(this, arguments); | |
}; | |
Box2D.Dynamics.b2TimeStep = b2TimeStep; | |
function b2World() { | |
b2World.b2World.apply(this, arguments); | |
if (this.constructor === b2World) this.b2World.apply(this, arguments); | |
}; | |
Box2D.Dynamics.b2World = b2World; | |
function b2CircleContact() { | |
b2CircleContact.b2CircleContact.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Contacts.b2CircleContact = b2CircleContact; | |
function b2Contact() { | |
b2Contact.b2Contact.apply(this, arguments); | |
if (this.constructor === b2Contact) this.b2Contact.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Contacts.b2Contact = b2Contact; | |
function b2ContactConstraint() { | |
b2ContactConstraint.b2ContactConstraint.apply(this, arguments); | |
if (this.constructor === b2ContactConstraint) this.b2ContactConstraint.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Contacts.b2ContactConstraint = b2ContactConstraint; | |
function b2ContactConstraintPoint() { | |
b2ContactConstraintPoint.b2ContactConstraintPoint.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Contacts.b2ContactConstraintPoint = b2ContactConstraintPoint; | |
function b2ContactEdge() { | |
b2ContactEdge.b2ContactEdge.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Contacts.b2ContactEdge = b2ContactEdge; | |
function b2ContactFactory() { | |
b2ContactFactory.b2ContactFactory.apply(this, arguments); | |
if (this.constructor === b2ContactFactory) this.b2ContactFactory.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Contacts.b2ContactFactory = b2ContactFactory; | |
function b2ContactRegister() { | |
b2ContactRegister.b2ContactRegister.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Contacts.b2ContactRegister = b2ContactRegister; | |
function b2ContactResult() { | |
b2ContactResult.b2ContactResult.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Contacts.b2ContactResult = b2ContactResult; | |
function b2ContactSolver() { | |
b2ContactSolver.b2ContactSolver.apply(this, arguments); | |
if (this.constructor === b2ContactSolver) this.b2ContactSolver.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Contacts.b2ContactSolver = b2ContactSolver; | |
function b2EdgeAndCircleContact() { | |
b2EdgeAndCircleContact.b2EdgeAndCircleContact.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Contacts.b2EdgeAndCircleContact = b2EdgeAndCircleContact; | |
function b2NullContact() { | |
b2NullContact.b2NullContact.apply(this, arguments); | |
if (this.constructor === b2NullContact) this.b2NullContact.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Contacts.b2NullContact = b2NullContact; | |
function b2PolyAndCircleContact() { | |
b2PolyAndCircleContact.b2PolyAndCircleContact.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Contacts.b2PolyAndCircleContact = b2PolyAndCircleContact; | |
function b2PolyAndEdgeContact() { | |
b2PolyAndEdgeContact.b2PolyAndEdgeContact.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Contacts.b2PolyAndEdgeContact = b2PolyAndEdgeContact; | |
function b2PolygonContact() { | |
b2PolygonContact.b2PolygonContact.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Contacts.b2PolygonContact = b2PolygonContact; | |
function b2PositionSolverManifold() { | |
b2PositionSolverManifold.b2PositionSolverManifold.apply(this, arguments); | |
if (this.constructor === b2PositionSolverManifold) this.b2PositionSolverManifold.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Contacts.b2PositionSolverManifold = b2PositionSolverManifold; | |
function b2BuoyancyController() { | |
b2BuoyancyController.b2BuoyancyController.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Controllers.b2BuoyancyController = b2BuoyancyController; | |
function b2ConstantAccelController() { | |
b2ConstantAccelController.b2ConstantAccelController.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Controllers.b2ConstantAccelController = b2ConstantAccelController; | |
function b2ConstantForceController() { | |
b2ConstantForceController.b2ConstantForceController.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Controllers.b2ConstantForceController = b2ConstantForceController; | |
function b2Controller() { | |
b2Controller.b2Controller.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Controllers.b2Controller = b2Controller; | |
function b2ControllerEdge() { | |
b2ControllerEdge.b2ControllerEdge.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Controllers.b2ControllerEdge = b2ControllerEdge; | |
function b2GravityController() { | |
b2GravityController.b2GravityController.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Controllers.b2GravityController = b2GravityController; | |
function b2TensorDampingController() { | |
b2TensorDampingController.b2TensorDampingController.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Controllers.b2TensorDampingController = b2TensorDampingController; | |
function b2DistanceJoint() { | |
b2DistanceJoint.b2DistanceJoint.apply(this, arguments); | |
if (this.constructor === b2DistanceJoint) this.b2DistanceJoint.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2DistanceJoint = b2DistanceJoint; | |
function b2DistanceJointDef() { | |
b2DistanceJointDef.b2DistanceJointDef.apply(this, arguments); | |
if (this.constructor === b2DistanceJointDef) this.b2DistanceJointDef.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2DistanceJointDef = b2DistanceJointDef; | |
function b2FrictionJoint() { | |
b2FrictionJoint.b2FrictionJoint.apply(this, arguments); | |
if (this.constructor === b2FrictionJoint) this.b2FrictionJoint.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2FrictionJoint = b2FrictionJoint; | |
function b2FrictionJointDef() { | |
b2FrictionJointDef.b2FrictionJointDef.apply(this, arguments); | |
if (this.constructor === b2FrictionJointDef) this.b2FrictionJointDef.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2FrictionJointDef = b2FrictionJointDef; | |
function b2GearJoint() { | |
b2GearJoint.b2GearJoint.apply(this, arguments); | |
if (this.constructor === b2GearJoint) this.b2GearJoint.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2GearJoint = b2GearJoint; | |
function b2GearJointDef() { | |
b2GearJointDef.b2GearJointDef.apply(this, arguments); | |
if (this.constructor === b2GearJointDef) this.b2GearJointDef.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2GearJointDef = b2GearJointDef; | |
function b2Jacobian() { | |
b2Jacobian.b2Jacobian.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2Jacobian = b2Jacobian; | |
function b2Joint() { | |
b2Joint.b2Joint.apply(this, arguments); | |
if (this.constructor === b2Joint) this.b2Joint.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2Joint = b2Joint; | |
function b2JointDef() { | |
b2JointDef.b2JointDef.apply(this, arguments); | |
if (this.constructor === b2JointDef) this.b2JointDef.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2JointDef = b2JointDef; | |
function b2JointEdge() { | |
b2JointEdge.b2JointEdge.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2JointEdge = b2JointEdge; | |
function b2LineJoint() { | |
b2LineJoint.b2LineJoint.apply(this, arguments); | |
if (this.constructor === b2LineJoint) this.b2LineJoint.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2LineJoint = b2LineJoint; | |
function b2LineJointDef() { | |
b2LineJointDef.b2LineJointDef.apply(this, arguments); | |
if (this.constructor === b2LineJointDef) this.b2LineJointDef.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2LineJointDef = b2LineJointDef; | |
function b2MouseJoint() { | |
b2MouseJoint.b2MouseJoint.apply(this, arguments); | |
if (this.constructor === b2MouseJoint) this.b2MouseJoint.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2MouseJoint = b2MouseJoint; | |
function b2MouseJointDef() { | |
b2MouseJointDef.b2MouseJointDef.apply(this, arguments); | |
if (this.constructor === b2MouseJointDef) this.b2MouseJointDef.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2MouseJointDef = b2MouseJointDef; | |
function b2PrismaticJoint() { | |
b2PrismaticJoint.b2PrismaticJoint.apply(this, arguments); | |
if (this.constructor === b2PrismaticJoint) this.b2PrismaticJoint.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2PrismaticJoint = b2PrismaticJoint; | |
function b2PrismaticJointDef() { | |
b2PrismaticJointDef.b2PrismaticJointDef.apply(this, arguments); | |
if (this.constructor === b2PrismaticJointDef) this.b2PrismaticJointDef.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2PrismaticJointDef = b2PrismaticJointDef; | |
function b2PulleyJoint() { | |
b2PulleyJoint.b2PulleyJoint.apply(this, arguments); | |
if (this.constructor === b2PulleyJoint) this.b2PulleyJoint.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2PulleyJoint = b2PulleyJoint; | |
function b2PulleyJointDef() { | |
b2PulleyJointDef.b2PulleyJointDef.apply(this, arguments); | |
if (this.constructor === b2PulleyJointDef) this.b2PulleyJointDef.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2PulleyJointDef = b2PulleyJointDef; | |
function b2RevoluteJoint() { | |
b2RevoluteJoint.b2RevoluteJoint.apply(this, arguments); | |
if (this.constructor === b2RevoluteJoint) this.b2RevoluteJoint.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2RevoluteJoint = b2RevoluteJoint; | |
function b2RevoluteJointDef() { | |
b2RevoluteJointDef.b2RevoluteJointDef.apply(this, arguments); | |
if (this.constructor === b2RevoluteJointDef) this.b2RevoluteJointDef.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2RevoluteJointDef = b2RevoluteJointDef; | |
function b2WeldJoint() { | |
b2WeldJoint.b2WeldJoint.apply(this, arguments); | |
if (this.constructor === b2WeldJoint) this.b2WeldJoint.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2WeldJoint = b2WeldJoint; | |
function b2WeldJointDef() { | |
b2WeldJointDef.b2WeldJointDef.apply(this, arguments); | |
if (this.constructor === b2WeldJointDef) this.b2WeldJointDef.apply(this, arguments); | |
}; | |
Box2D.Dynamics.Joints.b2WeldJointDef = b2WeldJointDef; | |
})(); //definitions | |
Box2D.postDefs = []; | |
(function () { | |
var b2CircleShape = Box2D.Collision.Shapes.b2CircleShape, | |
b2EdgeChainDef = Box2D.Collision.Shapes.b2EdgeChainDef, | |
b2EdgeShape = Box2D.Collision.Shapes.b2EdgeShape, | |
b2MassData = Box2D.Collision.Shapes.b2MassData, | |
b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape, | |
b2Shape = Box2D.Collision.Shapes.b2Shape, | |
b2Color = Box2D.Common.b2Color, | |
b2internal = Box2D.Common.b2internal, | |
b2Settings = Box2D.Common.b2Settings, | |
b2Mat22 = Box2D.Common.Math.b2Mat22, | |
b2Mat33 = Box2D.Common.Math.b2Mat33, | |
b2Math = Box2D.Common.Math.b2Math, | |
b2Sweep = Box2D.Common.Math.b2Sweep, | |
b2Transform = Box2D.Common.Math.b2Transform, | |
b2Vec2 = Box2D.Common.Math.b2Vec2, | |
b2Vec3 = Box2D.Common.Math.b2Vec3, | |
b2AABB = Box2D.Collision.b2AABB, | |
b2Bound = Box2D.Collision.b2Bound, | |
b2BoundValues = Box2D.Collision.b2BoundValues, | |
b2Collision = Box2D.Collision.b2Collision, | |
b2ContactID = Box2D.Collision.b2ContactID, | |
b2ContactPoint = Box2D.Collision.b2ContactPoint, | |
b2Distance = Box2D.Collision.b2Distance, | |
b2DistanceInput = Box2D.Collision.b2DistanceInput, | |
b2DistanceOutput = Box2D.Collision.b2DistanceOutput, | |
b2DistanceProxy = Box2D.Collision.b2DistanceProxy, | |
b2DynamicTree = Box2D.Collision.b2DynamicTree, | |
b2DynamicTreeBroadPhase = Box2D.Collision.b2DynamicTreeBroadPhase, | |
b2DynamicTreeNode = Box2D.Collision.b2DynamicTreeNode, | |
b2DynamicTreePair = Box2D.Collision.b2DynamicTreePair, | |
b2Manifold = Box2D.Collision.b2Manifold, | |
b2ManifoldPoint = Box2D.Collision.b2ManifoldPoint, | |
b2Point = Box2D.Collision.b2Point, | |
b2RayCastInput = Box2D.Collision.b2RayCastInput, | |
b2RayCastOutput = Box2D.Collision.b2RayCastOutput, | |
b2Segment = Box2D.Collision.b2Segment, | |
b2SeparationFunction = Box2D.Collision.b2SeparationFunction, | |
b2Simplex = Box2D.Collision.b2Simplex, | |
b2SimplexCache = Box2D.Collision.b2SimplexCache, | |
b2SimplexVertex = Box2D.Collision.b2SimplexVertex, | |
b2TimeOfImpact = Box2D.Collision.b2TimeOfImpact, | |
b2TOIInput = Box2D.Collision.b2TOIInput, | |
b2WorldManifold = Box2D.Collision.b2WorldManifold, | |
ClipVertex = Box2D.Collision.ClipVertex, | |
Features = Box2D.Collision.Features, | |
IBroadPhase = Box2D.Collision.IBroadPhase; | |
b2AABB.b2AABB = function () { | |
this.lowerBound = new b2Vec2(); | |
this.upperBound = new b2Vec2(); | |
}; | |
b2AABB.prototype.IsValid = function () { | |
var dX = this.upperBound.x - this.lowerBound.x; | |
var dY = this.upperBound.y - this.lowerBound.y; | |
var valid = dX >= 0.0 && dY >= 0.0; | |
valid = valid && this.lowerBound.IsValid() && this.upperBound.IsValid(); | |
return valid; | |
} | |
b2AABB.prototype.GetCenter = function () { | |
return new b2Vec2((this.lowerBound.x + this.upperBound.x) / 2, (this.lowerBound.y + this.upperBound.y) / 2); | |
} | |
b2AABB.prototype.GetExtents = function () { | |
return new b2Vec2((this.upperBound.x - this.lowerBound.x) / 2, (this.upperBound.y - this.lowerBound.y) / 2); | |
} | |
b2AABB.prototype.Contains = function (aabb) { | |
var result = true; | |
result = result && this.lowerBound.x <= aabb.lowerBound.x; | |
result = result && this.lowerBound.y <= aabb.lowerBound.y; | |
result = result && aabb.upperBound.x <= this.upperBound.x; | |
result = result && aabb.upperBound.y <= this.upperBound.y; | |
return result; | |
} | |
b2AABB.prototype.RayCast = function (output, input) { | |
var tmin = (-Number.MAX_VALUE); | |
var tmax = Number.MAX_VALUE; | |
var pX = input.p1.x; | |
var pY = input.p1.y; | |
var dX = input.p2.x - input.p1.x; | |
var dY = input.p2.y - input.p1.y; | |
var absDX = Math.abs(dX); | |
var absDY = Math.abs(dY); | |
var normal = output.normal; | |
var inv_d = 0; | |
var t1 = 0; | |
var t2 = 0; | |
var t3 = 0; | |
var s = 0; { | |
if (absDX < Number.MIN_VALUE) { | |
if (pX < this.lowerBound.x || this.upperBound.x < pX) return false; | |
} | |
else { | |
inv_d = 1.0 / dX; | |
t1 = (this.lowerBound.x - pX) * inv_d; | |
t2 = (this.upperBound.x - pX) * inv_d; | |
s = (-1.0); | |
if (t1 > t2) { | |
t3 = t1; | |
t1 = t2; | |
t2 = t3; | |
s = 1.0; | |
} | |
if (t1 > tmin) { | |
normal.x = s; | |
normal.y = 0; | |
tmin = t1; | |
} | |
tmax = Math.min(tmax, t2); | |
if (tmin > tmax) return false; | |
} | |
} { | |
if (absDY < Number.MIN_VALUE) { | |
if (pY < this.lowerBound.y || this.upperBound.y < pY) return false; | |
} | |
else { | |
inv_d = 1.0 / dY; | |
t1 = (this.lowerBound.y - pY) * inv_d; | |
t2 = (this.upperBound.y - pY) * inv_d; | |
s = (-1.0); | |
if (t1 > t2) { | |
t3 = t1; | |
t1 = t2; | |
t2 = t3; | |
s = 1.0; | |
} | |
if (t1 > tmin) { | |
normal.y = s; | |
normal.x = 0; | |
tmin = t1; | |
} | |
tmax = Math.min(tmax, t2); | |
if (tmin > tmax) return false; | |
} | |
} | |
output.fraction = tmin; | |
return true; | |
} | |
b2AABB.prototype.TestOverlap = function (other) { | |
var d1X = other.lowerBound.x - this.upperBound.x; | |
var d1Y = other.lowerBound.y - this.upperBound.y; | |
var d2X = this.lowerBound.x - other.upperBound.x; | |
var d2Y = this.lowerBound.y - other.upperBound.y; | |
if (d1X > 0.0 || d1Y > 0.0) return false; | |
if (d2X > 0.0 || d2Y > 0.0) return false; | |
return true; | |
} | |
b2AABB.Combine = function (aabb1, aabb2) { | |
var aabb = new b2AABB(); | |
aabb.Combine(aabb1, aabb2); | |
return aabb; | |
} | |
b2AABB.prototype.Combine = function (aabb1, aabb2) { | |
this.lowerBound.x = Math.min(aabb1.lowerBound.x, aabb2.lowerBound.x); | |
this.lowerBound.y = Math.min(aabb1.lowerBound.y, aabb2.lowerBound.y); | |
this.upperBound.x = Math.max(aabb1.upperBound.x, aabb2.upperBound.x); | |
this.upperBound.y = Math.max(aabb1.upperBound.y, aabb2.upperBound.y); | |
} | |
b2Bound.b2Bound = function () {}; | |
b2Bound.prototype.IsLower = function () { | |
return (this.value & 1) == 0; | |
} | |
b2Bound.prototype.IsUpper = function () { | |
return (this.value & 1) == 1; | |
} | |
b2Bound.prototype.Swap = function (b) { | |
var tempValue = this.value; | |
var tempProxy = this.proxy; | |
var tempStabbingCount = this.stabbingCount; | |
this.value = b.value; | |
this.proxy = b.proxy; | |
this.stabbingCount = b.stabbingCount; | |
b.value = tempValue; | |
b.proxy = tempProxy; | |
b.stabbingCount = tempStabbingCount; | |
} | |
b2BoundValues.b2BoundValues = function () {}; | |
b2BoundValues.prototype.b2BoundValues = function () { | |
this.lowerValues = new Vector_a2j_Number(); | |
this.lowerValues[0] = 0.0; | |
this.lowerValues[1] = 0.0; | |
this.upperValues = new Vector_a2j_Number(); | |
this.upperValues[0] = 0.0; | |
this.upperValues[1] = 0.0; | |
} | |
b2Collision.b2Collision = function () {}; | |
b2Collision.ClipSegmentToLine = function (vOut, vIn, normal, offset) { | |
if (offset === undefined) offset = 0; | |
var cv; | |
var numOut = 0; | |
cv = vIn[0]; | |
var vIn0 = cv.v; | |
cv = vIn[1]; | |
var vIn1 = cv.v; | |
var distance0 = normal.x * vIn0.x + normal.y * vIn0.y - offset; | |
var distance1 = normal.x * vIn1.x + normal.y * vIn1.y - offset; | |
if (distance0 <= 0.0) vOut[numOut++].Set(vIn[0]); | |
if (distance1 <= 0.0) vOut[numOut++].Set(vIn[1]); | |
if (distance0 * distance1 < 0.0) { | |
var interp = distance0 / (distance0 - distance1); | |
cv = vOut[numOut]; | |
var tVec = cv.v; | |
tVec.x = vIn0.x + interp * (vIn1.x - vIn0.x); | |
tVec.y = vIn0.y + interp * (vIn1.y - vIn0.y); | |
cv = vOut[numOut]; | |
var cv2; | |
if (distance0 > 0.0) { | |
cv2 = vIn[0]; | |
cv.id = cv2.id; | |
} | |
else { | |
cv2 = vIn[1]; | |
cv.id = cv2.id; | |
}++numOut; | |
} | |
return numOut; | |
} | |
b2Collision.EdgeSeparation = function (poly1, xf1, edge1, poly2, xf2) { | |
if (edge1 === undefined) edge1 = 0; | |
var count1 = parseInt(poly1.m_vertexCount); | |
var vertices1 = poly1.m_vertices; | |
var normals1 = poly1.m_normals; | |
var count2 = parseInt(poly2.m_vertexCount); | |
var vertices2 = poly2.m_vertices; | |
var tMat; | |
var tVec; | |
tMat = xf1.R; | |
tVec = normals1[edge1]; | |
var normal1WorldX = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
var normal1WorldY = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
tMat = xf2.R; | |
var normal1X = (tMat.col1.x * normal1WorldX + tMat.col1.y * normal1WorldY); | |
var normal1Y = (tMat.col2.x * normal1WorldX + tMat.col2.y * normal1WorldY); | |
var index = 0; | |
var minDot = Number.MAX_VALUE; | |
for (var i = 0; i < count2; ++i) { | |
tVec = vertices2[i]; | |
var dot = tVec.x * normal1X + tVec.y * normal1Y; | |
if (dot < minDot) { | |
minDot = dot; | |
index = i; | |
} | |
} | |
tVec = vertices1[edge1]; | |
tMat = xf1.R; | |
var v1X = xf1.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
var v1Y = xf1.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
tVec = vertices2[index]; | |
tMat = xf2.R; | |
var v2X = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
var v2Y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
v2X -= v1X; | |
v2Y -= v1Y; | |
var separation = v2X * normal1WorldX + v2Y * normal1WorldY; | |
return separation; | |
} | |
b2Collision.FindMaxSeparation = function (edgeIndex, poly1, xf1, poly2, xf2) { | |
var count1 = parseInt(poly1.m_vertexCount); | |
var normals1 = poly1.m_normals; | |
var tVec; | |
var tMat; | |
tMat = xf2.R; | |
tVec = poly2.m_centroid; | |
var dX = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
var dY = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
tMat = xf1.R; | |
tVec = poly1.m_centroid; | |
dX -= xf1.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
dY -= xf1.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
var dLocal1X = (dX * xf1.R.col1.x + dY * xf1.R.col1.y); | |
var dLocal1Y = (dX * xf1.R.col2.x + dY * xf1.R.col2.y); | |
var edge = 0; | |
var maxDot = (-Number.MAX_VALUE); | |
for (var i = 0; i < count1; ++i) { | |
tVec = normals1[i]; | |
var dot = (tVec.x * dLocal1X + tVec.y * dLocal1Y); | |
if (dot > maxDot) { | |
maxDot = dot; | |
edge = i; | |
} | |
} | |
var s = b2Collision.EdgeSeparation(poly1, xf1, edge, poly2, xf2); | |
var prevEdge = parseInt(edge - 1 >= 0 ? edge - 1 : count1 - 1); | |
var sPrev = b2Collision.EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2); | |
var nextEdge = parseInt(edge + 1 < count1 ? edge + 1 : 0); | |
var sNext = b2Collision.EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2); | |
var bestEdge = 0; | |
var bestSeparation = 0; | |
var increment = 0; | |
if (sPrev > s && sPrev > sNext) { | |
increment = (-1); | |
bestEdge = prevEdge; | |
bestSeparation = sPrev; | |
} | |
else if (sNext > s) { | |
increment = 1; | |
bestEdge = nextEdge; | |
bestSeparation = sNext; | |
} | |
else { | |
edgeIndex[0] = edge; | |
return s; | |
} | |
while (true) { | |
if (increment == (-1)) edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1; | |
else edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0;s = b2Collision.EdgeSeparation(poly1, xf1, edge, poly2, xf2); | |
if (s > bestSeparation) { | |
bestEdge = edge; | |
bestSeparation = s; | |
} | |
else { | |
break; | |
} | |
} | |
edgeIndex[0] = bestEdge; | |
return bestSeparation; | |
} | |
b2Collision.FindIncidentEdge = function (c, poly1, xf1, edge1, poly2, xf2) { | |
if (edge1 === undefined) edge1 = 0; | |
var count1 = parseInt(poly1.m_vertexCount); | |
var normals1 = poly1.m_normals; | |
var count2 = parseInt(poly2.m_vertexCount); | |
var vertices2 = poly2.m_vertices; | |
var normals2 = poly2.m_normals; | |
var tMat; | |
var tVec; | |
tMat = xf1.R; | |
tVec = normals1[edge1]; | |
var normal1X = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
var normal1Y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
tMat = xf2.R; | |
var tX = (tMat.col1.x * normal1X + tMat.col1.y * normal1Y); | |
normal1Y = (tMat.col2.x * normal1X + tMat.col2.y * normal1Y); | |
normal1X = tX; | |
var index = 0; | |
var minDot = Number.MAX_VALUE; | |
for (var i = 0; i < count2; ++i) { | |
tVec = normals2[i]; | |
var dot = (normal1X * tVec.x + normal1Y * tVec.y); | |
if (dot < minDot) { | |
minDot = dot; | |
index = i; | |
} | |
} | |
var tClip; | |
var i1 = parseInt(index); | |
var i2 = parseInt(i1 + 1 < count2 ? i1 + 1 : 0); | |
tClip = c[0]; | |
tVec = vertices2[i1]; | |
tMat = xf2.R; | |
tClip.v.x = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
tClip.v.y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
tClip.id.features.referenceEdge = edge1; | |
tClip.id.features.incidentEdge = i1; | |
tClip.id.features.incidentVertex = 0; | |
tClip = c[1]; | |
tVec = vertices2[i2]; | |
tMat = xf2.R; | |
tClip.v.x = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
tClip.v.y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
tClip.id.features.referenceEdge = edge1; | |
tClip.id.features.incidentEdge = i2; | |
tClip.id.features.incidentVertex = 1; | |
} | |
b2Collision.MakeClipPointVector = function () { | |
var r = new Vector(2); | |
r[0] = new ClipVertex(); | |
r[1] = new ClipVertex(); | |
return r; | |
} | |
b2Collision.CollidePolygons = function (manifold, polyA, xfA, polyB, xfB) { | |
var cv; | |
manifold.m_pointCount = 0; | |
var totalRadius = polyA.m_radius + polyB.m_radius; | |
var edgeA = 0; | |
b2Collision.s_edgeAO[0] = edgeA; | |
var separationA = b2Collision.FindMaxSeparation(b2Collision.s_edgeAO, polyA, xfA, polyB, xfB); | |
edgeA = b2Collision.s_edgeAO[0]; | |
if (separationA > totalRadius) return; | |
var edgeB = 0; | |
b2Collision.s_edgeBO[0] = edgeB; | |
var separationB = b2Collision.FindMaxSeparation(b2Collision.s_edgeBO, polyB, xfB, polyA, xfA); | |
edgeB = b2Collision.s_edgeBO[0]; | |
if (separationB > totalRadius) return; | |
var poly1; | |
var poly2; | |
var xf1; | |
var xf2; | |
var edge1 = 0; | |
var flip = 0; | |
var k_relativeTol = 0.98; | |
var k_absoluteTol = 0.001; | |
var tMat; | |
if (separationB > k_relativeTol * separationA + k_absoluteTol) { | |
poly1 = polyB; | |
poly2 = polyA; | |
xf1 = xfB; | |
xf2 = xfA; | |
edge1 = edgeB; | |
manifold.m_type = b2Manifold.e_faceB; | |
flip = 1; | |
} | |
else { | |
poly1 = polyA; | |
poly2 = polyB; | |
xf1 = xfA; | |
xf2 = xfB; | |
edge1 = edgeA; | |
manifold.m_type = b2Manifold.e_faceA; | |
flip = 0; | |
} | |
var incidentEdge = b2Collision.s_incidentEdge; | |
b2Collision.FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2); | |
var count1 = parseInt(poly1.m_vertexCount); | |
var vertices1 = poly1.m_vertices; | |
var local_v11 = vertices1[edge1]; | |
var local_v12; | |
if (edge1 + 1 < count1) { | |
local_v12 = vertices1[parseInt(edge1 + 1)]; | |
} | |
else { | |
local_v12 = vertices1[0]; | |
} | |
var localTangent = b2Collision.s_localTangent; | |
localTangent.Set(local_v12.x - local_v11.x, local_v12.y - local_v11.y); | |
localTangent.Normalize(); | |
var localNormal = b2Collision.s_localNormal; | |
localNormal.x = localTangent.y; | |
localNormal.y = (-localTangent.x); | |
var planePoint = b2Collision.s_planePoint; | |
planePoint.Set(0.5 * (local_v11.x + local_v12.x), 0.5 * (local_v11.y + local_v12.y)); | |
var tangent = b2Collision.s_tangent; | |
tMat = xf1.R; | |
tangent.x = (tMat.col1.x * localTangent.x + tMat.col2.x * localTangent.y); | |
tangent.y = (tMat.col1.y * localTangent.x + tMat.col2.y * localTangent.y); | |
var tangent2 = b2Collision.s_tangent2; | |
tangent2.x = (-tangent.x); | |
tangent2.y = (-tangent.y); | |
var normal = b2Collision.s_normal; | |
normal.x = tangent.y; | |
normal.y = (-tangent.x); | |
var v11 = b2Collision.s_v11; | |
var v12 = b2Collision.s_v12; | |
v11.x = xf1.position.x + (tMat.col1.x * local_v11.x + tMat.col2.x * local_v11.y); | |
v11.y = xf1.position.y + (tMat.col1.y * local_v11.x + tMat.col2.y * local_v11.y); | |
v12.x = xf1.position.x + (tMat.col1.x * local_v12.x + tMat.col2.x * local_v12.y); | |
v12.y = xf1.position.y + (tMat.col1.y * local_v12.x + tMat.col2.y * local_v12.y); | |
var frontOffset = normal.x * v11.x + normal.y * v11.y; | |
var sideOffset1 = (-tangent.x * v11.x) - tangent.y * v11.y + totalRadius; | |
var sideOffset2 = tangent.x * v12.x + tangent.y * v12.y + totalRadius; | |
var clipPoints1 = b2Collision.s_clipPoints1; | |
var clipPoints2 = b2Collision.s_clipPoints2; | |
var np = 0; | |
np = b2Collision.ClipSegmentToLine(clipPoints1, incidentEdge, tangent2, sideOffset1); | |
if (np < 2) return; | |
np = b2Collision.ClipSegmentToLine(clipPoints2, clipPoints1, tangent, sideOffset2); | |
if (np < 2) return; | |
manifold.m_localPlaneNormal.SetV(localNormal); | |
manifold.m_localPoint.SetV(planePoint); | |
var pointCount = 0; | |
for (var i = 0; i < b2Settings.b2_maxManifoldPoints; ++i) { | |
cv = clipPoints2[i]; | |
var separation = normal.x * cv.v.x + normal.y * cv.v.y - frontOffset; | |
if (separation <= totalRadius) { | |
var cp = manifold.m_points[pointCount]; | |
tMat = xf2.R; | |
var tX = cv.v.x - xf2.position.x; | |
var tY = cv.v.y - xf2.position.y; | |
cp.m_localPoint.x = (tX * tMat.col1.x + tY * tMat.col1.y); | |
cp.m_localPoint.y = (tX * tMat.col2.x + tY * tMat.col2.y); | |
cp.m_id.Set(cv.id); | |
cp.m_id.features.flip = flip; | |
++pointCount; | |
} | |
} | |
manifold.m_pointCount = pointCount; | |
} | |
b2Collision.CollideCircles = function (manifold, circle1, xf1, circle2, xf2) { | |
manifold.m_pointCount = 0; | |
var tMat; | |
var tVec; | |
tMat = xf1.R; | |
tVec = circle1.m_p; | |
var p1X = xf1.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
var p1Y = xf1.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
tMat = xf2.R; | |
tVec = circle2.m_p; | |
var p2X = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
var p2Y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
var dX = p2X - p1X; | |
var dY = p2Y - p1Y; | |
var distSqr = dX * dX + dY * dY; | |
var radius = circle1.m_radius + circle2.m_radius; | |
if (distSqr > radius * radius) { | |
return; | |
} | |
manifold.m_type = b2Manifold.e_circles; | |
manifold.m_localPoint.SetV(circle1.m_p); | |
manifold.m_localPlaneNormal.SetZero(); | |
manifold.m_pointCount = 1; | |
manifold.m_points[0].m_localPoint.SetV(circle2.m_p); | |
manifold.m_points[0].m_id.key = 0; | |
} | |
b2Collision.CollidePolygonAndCircle = function (manifold, polygon, xf1, circle, xf2) { | |
manifold.m_pointCount = 0; | |
var tPoint; | |
var dX = 0; | |
var dY = 0; | |
var positionX = 0; | |
var positionY = 0; | |
var tVec; | |
var tMat; | |
tMat = xf2.R; | |
tVec = circle.m_p; | |
var cX = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
var cY = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
dX = cX - xf1.position.x; | |
dY = cY - xf1.position.y; | |
tMat = xf1.R; | |
var cLocalX = (dX * tMat.col1.x + dY * tMat.col1.y); | |
var cLocalY = (dX * tMat.col2.x + dY * tMat.col2.y); | |
var dist = 0; | |
var normalIndex = 0; | |
var separation = (-Number.MAX_VALUE); | |
var radius = polygon.m_radius + circle.m_radius; | |
var vertexCount = parseInt(polygon.m_vertexCount); | |
var vertices = polygon.m_vertices; | |
var normals = polygon.m_normals; | |
for (var i = 0; i < vertexCount; ++i) { | |
tVec = vertices[i]; | |
dX = cLocalX - tVec.x; | |
dY = cLocalY - tVec.y; | |
tVec = normals[i]; | |
var s = tVec.x * dX + tVec.y * dY; | |
if (s > radius) { | |
return; | |
} | |
if (s > separation) { | |
separation = s; | |
normalIndex = i; | |
} | |
} | |
var vertIndex1 = parseInt(normalIndex); | |
var vertIndex2 = parseInt(vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0); | |
var v1 = vertices[vertIndex1]; | |
var v2 = vertices[vertIndex2]; | |
if (separation < Number.MIN_VALUE) { | |
manifold.m_pointCount = 1; | |
manifold.m_type = b2Manifold.e_faceA; | |
manifold.m_localPlaneNormal.SetV(normals[normalIndex]); | |
manifold.m_localPoint.x = 0.5 * (v1.x + v2.x); | |
manifold.m_localPoint.y = 0.5 * (v1.y + v2.y); | |
manifold.m_points[0].m_localPoint.SetV(circle.m_p); | |
manifold.m_points[0].m_id.key = 0; | |
return; | |
} | |
var u1 = (cLocalX - v1.x) * (v2.x - v1.x) + (cLocalY - v1.y) * (v2.y - v1.y); | |
var u2 = (cLocalX - v2.x) * (v1.x - v2.x) + (cLocalY - v2.y) * (v1.y - v2.y); | |
if (u1 <= 0.0) { | |
if ((cLocalX - v1.x) * (cLocalX - v1.x) + (cLocalY - v1.y) * (cLocalY - v1.y) > radius * radius) return; | |
manifold.m_pointCount = 1; | |
manifold.m_type = b2Manifold.e_faceA; | |
manifold.m_localPlaneNormal.x = cLocalX - v1.x; | |
manifold.m_localPlaneNormal.y = cLocalY - v1.y; | |
manifold.m_localPlaneNormal.Normalize(); | |
manifold.m_localPoint.SetV(v1); | |
manifold.m_points[0].m_localPoint.SetV(circle.m_p); | |
manifold.m_points[0].m_id.key = 0; | |
} | |
else if (u2 <= 0) { | |
if ((cLocalX - v2.x) * (cLocalX - v2.x) + (cLocalY - v2.y) * (cLocalY - v2.y) > radius * radius) return; | |
manifold.m_pointCount = 1; | |
manifold.m_type = b2Manifold.e_faceA; | |
manifold.m_localPlaneNormal.x = cLocalX - v2.x; | |
manifold.m_localPlaneNormal.y = cLocalY - v2.y; | |
manifold.m_localPlaneNormal.Normalize(); | |
manifold.m_localPoint.SetV(v2); | |
manifold.m_points[0].m_localPoint.SetV(circle.m_p); | |
manifold.m_points[0].m_id.key = 0; | |
} | |
else { | |
var faceCenterX = 0.5 * (v1.x + v2.x); | |
var faceCenterY = 0.5 * (v1.y + v2.y); | |
separation = (cLocalX - faceCenterX) * normals[vertIndex1].x + (cLocalY - faceCenterY) * normals[vertIndex1].y; | |
if (separation > radius) return; | |
manifold.m_pointCount = 1; | |
manifold.m_type = b2Manifold.e_faceA; | |
manifold.m_localPlaneNormal.x = normals[vertIndex1].x; | |
manifold.m_localPlaneNormal.y = normals[vertIndex1].y; | |
manifold.m_localPlaneNormal.Normalize(); | |
manifold.m_localPoint.Set(faceCenterX, faceCenterY); | |
manifold.m_points[0].m_localPoint.SetV(circle.m_p); | |
manifold.m_points[0].m_id.key = 0; | |
} | |
} | |
b2Collision.TestOverlap = function (a, b) { | |
var t1 = b.lowerBound; | |
var t2 = a.upperBound; | |
var d1X = t1.x - t2.x; | |
var d1Y = t1.y - t2.y; | |
t1 = a.lowerBound; | |
t2 = b.upperBound; | |
var d2X = t1.x - t2.x; | |
var d2Y = t1.y - t2.y; | |
if (d1X > 0.0 || d1Y > 0.0) return false; | |
if (d2X > 0.0 || d2Y > 0.0) return false; | |
return true; | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Collision.b2Collision.s_incidentEdge = b2Collision.MakeClipPointVector(); | |
Box2D.Collision.b2Collision.s_clipPoints1 = b2Collision.MakeClipPointVector(); | |
Box2D.Collision.b2Collision.s_clipPoints2 = b2Collision.MakeClipPointVector(); | |
Box2D.Collision.b2Collision.s_edgeAO = new Vector_a2j_Number(1); | |
Box2D.Collision.b2Collision.s_edgeBO = new Vector_a2j_Number(1); | |
Box2D.Collision.b2Collision.s_localTangent = new b2Vec2(); | |
Box2D.Collision.b2Collision.s_localNormal = new b2Vec2(); | |
Box2D.Collision.b2Collision.s_planePoint = new b2Vec2(); | |
Box2D.Collision.b2Collision.s_normal = new b2Vec2(); | |
Box2D.Collision.b2Collision.s_tangent = new b2Vec2(); | |
Box2D.Collision.b2Collision.s_tangent2 = new b2Vec2(); | |
Box2D.Collision.b2Collision.s_v11 = new b2Vec2(); | |
Box2D.Collision.b2Collision.s_v12 = new b2Vec2(); | |
Box2D.Collision.b2Collision.b2CollidePolyTempVec = new b2Vec2(); | |
Box2D.Collision.b2Collision.b2_nullFeature = 0x000000ff; | |
}); | |
b2ContactID.b2ContactID = function () { | |
this.features = new Features(); | |
}; | |
b2ContactID.prototype.b2ContactID = function () { | |
this.features._m_id = this; | |
} | |
b2ContactID.prototype.Set = function (id) { | |
this.key = id._key; | |
} | |
b2ContactID.prototype.Copy = function () { | |
var id = new b2ContactID(); | |
id.key = this.key; | |
return id; | |
} | |
Object.defineProperty(b2ContactID.prototype, 'key', { | |
enumerable: false, | |
configurable: true, | |
get: function () { | |
return this._key; | |
} | |
}); | |
Object.defineProperty(b2ContactID.prototype, 'key', { | |
enumerable: false, | |
configurable: true, | |
set: function (value) { | |
if (value === undefined) value = 0; | |
this._key = value; | |
this.features._referenceEdge = this._key & 0x000000ff; | |
this.features._incidentEdge = ((this._key & 0x0000ff00) >> 8) & 0x000000ff; | |
this.features._incidentVertex = ((this._key & 0x00ff0000) >> 16) & 0x000000ff; | |
this.features._flip = ((this._key & 0xff000000) >> 24) & 0x000000ff; | |
} | |
}); | |
b2ContactPoint.b2ContactPoint = function () { | |
this.position = new b2Vec2(); | |
this.velocity = new b2Vec2(); | |
this.normal = new b2Vec2(); | |
this.id = new b2ContactID(); | |
}; | |
b2Distance.b2Distance = function () {}; | |
b2Distance.Distance = function (output, cache, input) { | |
++b2Distance.b2_gjkCalls; | |
var proxyA = input.proxyA; | |
var proxyB = input.proxyB; | |
var transformA = input.transformA; | |
var transformB = input.transformB; | |
var simplex = b2Distance.s_simplex; | |
simplex.ReadCache(cache, proxyA, transformA, proxyB, transformB); | |
var vertices = simplex.m_vertices; | |
var k_maxIters = 20; | |
var saveA = b2Distance.s_saveA; | |
var saveB = b2Distance.s_saveB; | |
var saveCount = 0; | |
var closestPoint = simplex.GetClosestPoint(); | |
var distanceSqr1 = closestPoint.LengthSquared(); | |
var distanceSqr2 = distanceSqr1; | |
var i = 0; | |
var p; | |
var iter = 0; | |
while (iter < k_maxIters) { | |
saveCount = simplex.m_count; | |
for (i = 0; | |
i < saveCount; i++) { | |
saveA[i] = vertices[i].indexA; | |
saveB[i] = vertices[i].indexB; | |
} | |
switch (simplex.m_count) { | |
case 1: | |
break; | |
case 2: | |
simplex.Solve2(); | |
break; | |
case 3: | |
simplex.Solve3(); | |
break; | |
default: | |
b2Settings.b2Assert(false); | |
} | |
if (simplex.m_count == 3) { | |
break; | |
} | |
p = simplex.GetClosestPoint(); | |
distanceSqr2 = p.LengthSquared(); | |
if (distanceSqr2 > distanceSqr1) {} | |
distanceSqr1 = distanceSqr2; | |
var d = simplex.GetSearchDirection(); | |
if (d.LengthSquared() < Number.MIN_VALUE * Number.MIN_VALUE) { | |
break; | |
} | |
var vertex = vertices[simplex.m_count]; | |
vertex.indexA = proxyA.GetSupport(b2Math.MulTMV(transformA.R, d.GetNegative())); | |
vertex.wA = b2Math.MulX(transformA, proxyA.GetVertex(vertex.indexA)); | |
vertex.indexB = proxyB.GetSupport(b2Math.MulTMV(transformB.R, d)); | |
vertex.wB = b2Math.MulX(transformB, proxyB.GetVertex(vertex.indexB)); | |
vertex.w = b2Math.SubtractVV(vertex.wB, vertex.wA); | |
++iter; | |
++b2Distance.b2_gjkIters; | |
var duplicate = false; | |
for (i = 0; | |
i < saveCount; i++) { | |
if (vertex.indexA == saveA[i] && vertex.indexB == saveB[i]) { | |
duplicate = true; | |
break; | |
} | |
} | |
if (duplicate) { | |
break; | |
}++simplex.m_count; | |
} | |
b2Distance.b2_gjkMaxIters = b2Math.Max(b2Distance.b2_gjkMaxIters, iter); | |
simplex.GetWitnessPoints(output.pointA, output.pointB); | |
output.distance = b2Math.SubtractVV(output.pointA, output.pointB).Length(); | |
output.iterations = iter; | |
simplex.WriteCache(cache); | |
if (input.useRadii) { | |
var rA = proxyA.m_radius; | |
var rB = proxyB.m_radius; | |
if (output.distance > rA + rB && output.distance > Number.MIN_VALUE) { | |
output.distance -= rA + rB; | |
var normal = b2Math.SubtractVV(output.pointB, output.pointA); | |
normal.Normalize(); | |
output.pointA.x += rA * normal.x; | |
output.pointA.y += rA * normal.y; | |
output.pointB.x -= rB * normal.x; | |
output.pointB.y -= rB * normal.y; | |
} | |
else { | |
p = new b2Vec2(); | |
p.x = .5 * (output.pointA.x + output.pointB.x); | |
p.y = .5 * (output.pointA.y + output.pointB.y); | |
output.pointA.x = output.pointB.x = p.x; | |
output.pointA.y = output.pointB.y = p.y; | |
output.distance = 0.0; | |
} | |
} | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Collision.b2Distance.s_simplex = new b2Simplex(); | |
Box2D.Collision.b2Distance.s_saveA = new Vector_a2j_Number(3); | |
Box2D.Collision.b2Distance.s_saveB = new Vector_a2j_Number(3); | |
}); | |
b2DistanceInput.b2DistanceInput = function () {}; | |
b2DistanceOutput.b2DistanceOutput = function () { | |
this.pointA = new b2Vec2(); | |
this.pointB = new b2Vec2(); | |
}; | |
b2DistanceProxy.b2DistanceProxy = function () {}; | |
b2DistanceProxy.prototype.Set = function (shape) { | |
switch (shape.GetType()) { | |
case b2Shape.e_circleShape: | |
{ | |
var circle = (shape instanceof b2CircleShape ? shape : null); | |
this.m_vertices = new Vector(1, true); | |
this.m_vertices[0] = circle.m_p; | |
this.m_count = 1; | |
this.m_radius = circle.m_radius; | |
} | |
break; | |
case b2Shape.e_polygonShape: | |
{ | |
var polygon = (shape instanceof b2PolygonShape ? shape : null); | |
this.m_vertices = polygon.m_vertices; | |
this.m_count = polygon.m_vertexCount; | |
this.m_radius = polygon.m_radius; | |
} | |
break; | |
default: | |
b2Settings.b2Assert(false); | |
} | |
} | |
b2DistanceProxy.prototype.GetSupport = function (d) { | |
var bestIndex = 0; | |
var bestValue = this.m_vertices[0].x * d.x + this.m_vertices[0].y * d.y; | |
for (var i = 1; i < this.m_count; ++i) { | |
var value = this.m_vertices[i].x * d.x + this.m_vertices[i].y * d.y; | |
if (value > bestValue) { | |
bestIndex = i; | |
bestValue = value; | |
} | |
} | |
return bestIndex; | |
} | |
b2DistanceProxy.prototype.GetSupportVertex = function (d) { | |
var bestIndex = 0; | |
var bestValue = this.m_vertices[0].x * d.x + this.m_vertices[0].y * d.y; | |
for (var i = 1; i < this.m_count; ++i) { | |
var value = this.m_vertices[i].x * d.x + this.m_vertices[i].y * d.y; | |
if (value > bestValue) { | |
bestIndex = i; | |
bestValue = value; | |
} | |
} | |
return this.m_vertices[bestIndex]; | |
} | |
b2DistanceProxy.prototype.GetVertexCount = function () { | |
return this.m_count; | |
} | |
b2DistanceProxy.prototype.GetVertex = function (index) { | |
if (index === undefined) index = 0; | |
b2Settings.b2Assert(0 <= index && index < this.m_count); | |
return this.m_vertices[index]; | |
} | |
b2DynamicTree.b2DynamicTree = function () {}; | |
b2DynamicTree.prototype.b2DynamicTree = function () { | |
this.m_root = null; | |
this.m_freeList = null; | |
this.m_path = 0; | |
this.m_insertionCount = 0; | |
} | |
b2DynamicTree.prototype.CreateProxy = function (aabb, userData) { | |
var node = this.AllocateNode(); | |
var extendX = b2Settings.b2_aabbExtension; | |
var extendY = b2Settings.b2_aabbExtension; | |
node.aabb.lowerBound.x = aabb.lowerBound.x - extendX; | |
node.aabb.lowerBound.y = aabb.lowerBound.y - extendY; | |
node.aabb.upperBound.x = aabb.upperBound.x + extendX; | |
node.aabb.upperBound.y = aabb.upperBound.y + extendY; | |
node.userData = userData; | |
this.InsertLeaf(node); | |
return node; | |
} | |
b2DynamicTree.prototype.DestroyProxy = function (proxy) { | |
this.RemoveLeaf(proxy); | |
this.FreeNode(proxy); | |
} | |
b2DynamicTree.prototype.MoveProxy = function (proxy, aabb, displacement) { | |
b2Settings.b2Assert(proxy.IsLeaf()); | |
if (proxy.aabb.Contains(aabb)) { | |
return false; | |
} | |
this.RemoveLeaf(proxy); | |
var extendX = b2Settings.b2_aabbExtension + b2Settings.b2_aabbMultiplier * (displacement.x > 0 ? displacement.x : (-displacement.x)); | |
var extendY = b2Settings.b2_aabbExtension + b2Settings.b2_aabbMultiplier * (displacement.y > 0 ? displacement.y : (-displacement.y)); | |
proxy.aabb.lowerBound.x = aabb.lowerBound.x - extendX; | |
proxy.aabb.lowerBound.y = aabb.lowerBound.y - extendY; | |
proxy.aabb.upperBound.x = aabb.upperBound.x + extendX; | |
proxy.aabb.upperBound.y = aabb.upperBound.y + extendY; | |
this.InsertLeaf(proxy); | |
return true; | |
} | |
b2DynamicTree.prototype.Rebalance = function (iterations) { | |
if (iterations === undefined) iterations = 0; | |
if (this.m_root == null) return; | |
for (var i = 0; i < iterations; i++) { | |
var node = this.m_root; | |
var bit = 0; | |
while (node.IsLeaf() == false) { | |
node = (this.m_path >> bit) & 1 ? node.child2 : node.child1; | |
bit = (bit + 1) & 31; | |
}++this.m_path; | |
this.RemoveLeaf(node); | |
this.InsertLeaf(node); | |
} | |
} | |
b2DynamicTree.prototype.GetFatAABB = function (proxy) { | |
return proxy.aabb; | |
} | |
b2DynamicTree.prototype.GetUserData = function (proxy) { | |
return proxy.userData; | |
} | |
b2DynamicTree.prototype.Query = function (callback, aabb) { | |
if (this.m_root == null) return; | |
var stack = new Vector(); | |
var count = 0; | |
stack[count++] = this.m_root; | |
while (count > 0) { | |
var node = stack[--count]; | |
if (node.aabb.TestOverlap(aabb)) { | |
if (node.IsLeaf()) { | |
var proceed = callback(node); | |
if (!proceed) return; | |
} | |
else { | |
stack[count++] = node.child1; | |
stack[count++] = node.child2; | |
} | |
} | |
} | |
} | |
b2DynamicTree.prototype.RayCast = function (callback, input) { | |
if (this.m_root == null) return; | |
var p1 = input.p1; | |
var p2 = input.p2; | |
var r = b2Math.SubtractVV(p1, p2); | |
r.Normalize(); | |
var v = b2Math.CrossFV(1.0, r); | |
var abs_v = b2Math.AbsV(v); | |
var maxFraction = input.maxFraction; | |
var segmentAABB = new b2AABB(); | |
var tX = 0; | |
var tY = 0; { | |
tX = p1.x + maxFraction * (p2.x - p1.x); | |
tY = p1.y + maxFraction * (p2.y - p1.y); | |
segmentAABB.lowerBound.x = Math.min(p1.x, tX); | |
segmentAABB.lowerBound.y = Math.min(p1.y, tY); | |
segmentAABB.upperBound.x = Math.max(p1.x, tX); | |
segmentAABB.upperBound.y = Math.max(p1.y, tY); | |
} | |
var stack = new Vector(); | |
var count = 0; | |
stack[count++] = this.m_root; | |
while (count > 0) { | |
var node = stack[--count]; | |
if (node.aabb.TestOverlap(segmentAABB) == false) { | |
continue; | |
} | |
var c = node.aabb.GetCenter(); | |
var h = node.aabb.GetExtents(); | |
var separation = Math.abs(v.x * (p1.x - c.x) + v.y * (p1.y - c.y)) - abs_v.x * h.x - abs_v.y * h.y; | |
if (separation > 0.0) continue; | |
if (node.IsLeaf()) { | |
var subInput = new b2RayCastInput(); | |
subInput.p1 = input.p1; | |
subInput.p2 = input.p2; | |
subInput.maxFraction = input.maxFraction; | |
maxFraction = callback(subInput, node); | |
if (maxFraction == 0.0) return; | |
if (maxFraction > 0.0) { | |
tX = p1.x + maxFraction * (p2.x - p1.x); | |
tY = p1.y + maxFraction * (p2.y - p1.y); | |
segmentAABB.lowerBound.x = Math.min(p1.x, tX); | |
segmentAABB.lowerBound.y = Math.min(p1.y, tY); | |
segmentAABB.upperBound.x = Math.max(p1.x, tX); | |
segmentAABB.upperBound.y = Math.max(p1.y, tY); | |
} | |
} | |
else { | |
stack[count++] = node.child1; | |
stack[count++] = node.child2; | |
} | |
} | |
} | |
b2DynamicTree.prototype.AllocateNode = function () { | |
if (this.m_freeList) { | |
var node = this.m_freeList; | |
this.m_freeList = node.parent; | |
node.parent = null; | |
node.child1 = null; | |
node.child2 = null; | |
return node; | |
} | |
return new b2DynamicTreeNode(); | |
} | |
b2DynamicTree.prototype.FreeNode = function (node) { | |
node.parent = this.m_freeList; | |
this.m_freeList = node; | |
} | |
b2DynamicTree.prototype.InsertLeaf = function (leaf) { | |
++this.m_insertionCount; | |
if (this.m_root == null) { | |
this.m_root = leaf; | |
this.m_root.parent = null; | |
return; | |
} | |
var center = leaf.aabb.GetCenter(); | |
var sibling = this.m_root; | |
if (sibling.IsLeaf() == false) { | |
do { | |
var child1 = sibling.child1; | |
var child2 = sibling.child2; | |
var norm1 = Math.abs((child1.aabb.lowerBound.x + child1.aabb.upperBound.x) / 2 - center.x) + Math.abs((child1.aabb.lowerBound.y + child1.aabb.upperBound.y) / 2 - center.y); | |
var norm2 = Math.abs((child2.aabb.lowerBound.x + child2.aabb.upperBound.x) / 2 - center.x) + Math.abs((child2.aabb.lowerBound.y + child2.aabb.upperBound.y) / 2 - center.y); | |
if (norm1 < norm2) { | |
sibling = child1; | |
} | |
else { | |
sibling = child2; | |
} | |
} | |
while (sibling.IsLeaf() == false) | |
} | |
var node1 = sibling.parent; | |
var node2 = this.AllocateNode(); | |
node2.parent = node1; | |
node2.userData = null; | |
node2.aabb.Combine(leaf.aabb, sibling.aabb); | |
if (node1) { | |
if (sibling.parent.child1 == sibling) { | |
node1.child1 = node2; | |
} | |
else { | |
node1.child2 = node2; | |
} | |
node2.child1 = sibling; | |
node2.child2 = leaf; | |
sibling.parent = node2; | |
leaf.parent = node2; | |
do { | |
if (node1.aabb.Contains(node2.aabb)) break; | |
node1.aabb.Combine(node1.child1.aabb, node1.child2.aabb); | |
node2 = node1; | |
node1 = node1.parent; | |
} | |
while (node1) | |
} | |
else { | |
node2.child1 = sibling; | |
node2.child2 = leaf; | |
sibling.parent = node2; | |
leaf.parent = node2; | |
this.m_root = node2; | |
} | |
} | |
b2DynamicTree.prototype.RemoveLeaf = function (leaf) { | |
if (leaf == this.m_root) { | |
this.m_root = null; | |
return; | |
} | |
var node2 = leaf.parent; | |
var node1 = node2.parent; | |
var sibling; | |
if (node2.child1 == leaf) { | |
sibling = node2.child2; | |
} | |
else { | |
sibling = node2.child1; | |
} | |
if (node1) { | |
if (node1.child1 == node2) { | |
node1.child1 = sibling; | |
} | |
else { | |
node1.child2 = sibling; | |
} | |
sibling.parent = node1; | |
this.FreeNode(node2); | |
while (node1) { | |
var oldAABB = node1.aabb; | |
node1.aabb = b2AABB.Combine(node1.child1.aabb, node1.child2.aabb); | |
if (oldAABB.Contains(node1.aabb)) break; | |
node1 = node1.parent; | |
} | |
} | |
else { | |
this.m_root = sibling; | |
sibling.parent = null; | |
this.FreeNode(node2); | |
} | |
} | |
b2DynamicTreeBroadPhase.b2DynamicTreeBroadPhase = function () { | |
this.m_tree = new b2DynamicTree(); | |
this.m_moveBuffer = new Vector(); | |
this.m_pairBuffer = new Vector(); | |
this.m_pairCount = 0; | |
}; | |
b2DynamicTreeBroadPhase.prototype.CreateProxy = function (aabb, userData) { | |
var proxy = this.m_tree.CreateProxy(aabb, userData); | |
++this.m_proxyCount; | |
this.BufferMove(proxy); | |
return proxy; | |
} | |
b2DynamicTreeBroadPhase.prototype.DestroyProxy = function (proxy) { | |
this.UnBufferMove(proxy); | |
--this.m_proxyCount; | |
this.m_tree.DestroyProxy(proxy); | |
} | |
b2DynamicTreeBroadPhase.prototype.MoveProxy = function (proxy, aabb, displacement) { | |
var buffer = this.m_tree.MoveProxy(proxy, aabb, displacement); | |
if (buffer) { | |
this.BufferMove(proxy); | |
} | |
} | |
b2DynamicTreeBroadPhase.prototype.TestOverlap = function (proxyA, proxyB) { | |
var aabbA = this.m_tree.GetFatAABB(proxyA); | |
var aabbB = this.m_tree.GetFatAABB(proxyB); | |
return aabbA.TestOverlap(aabbB); | |
} | |
b2DynamicTreeBroadPhase.prototype.GetUserData = function (proxy) { | |
return this.m_tree.GetUserData(proxy); | |
} | |
b2DynamicTreeBroadPhase.prototype.GetFatAABB = function (proxy) { | |
return this.m_tree.GetFatAABB(proxy); | |
} | |
b2DynamicTreeBroadPhase.prototype.GetProxyCount = function () { | |
return this.m_proxyCount; | |
} | |
b2DynamicTreeBroadPhase.prototype.UpdatePairs = function (callback) { | |
var __this = this; | |
__this.m_pairCount = 0; | |
var i = 0, | |
queryProxy; | |
for (i = 0; | |
i < __this.m_moveBuffer.length; ++i) { | |
queryProxy = __this.m_moveBuffer[i]; | |
function QueryCallback(proxy) { | |
if (proxy == queryProxy) return true; | |
if (__this.m_pairCount == __this.m_pairBuffer.length) { | |
__this.m_pairBuffer[__this.m_pairCount] = new b2DynamicTreePair(); | |
} | |
var pair = __this.m_pairBuffer[__this.m_pairCount]; | |
pair.proxyA = proxy < queryProxy ? proxy : queryProxy; | |
pair.proxyB = proxy >= queryProxy ? proxy : queryProxy;++__this.m_pairCount; | |
return true; | |
}; | |
var fatAABB = __this.m_tree.GetFatAABB(queryProxy); | |
__this.m_tree.Query(QueryCallback, fatAABB); | |
} | |
__this.m_moveBuffer.length = 0; | |
for (var i = 0; i < __this.m_pairCount;) { | |
var primaryPair = __this.m_pairBuffer[i]; | |
var userDataA = __this.m_tree.GetUserData(primaryPair.proxyA); | |
var userDataB = __this.m_tree.GetUserData(primaryPair.proxyB); | |
callback(userDataA, userDataB); | |
++i; | |
while (i < __this.m_pairCount) { | |
var pair = __this.m_pairBuffer[i]; | |
if (pair.proxyA != primaryPair.proxyA || pair.proxyB != primaryPair.proxyB) { | |
break; | |
}++i; | |
} | |
} | |
} | |
b2DynamicTreeBroadPhase.prototype.Query = function (callback, aabb) { | |
this.m_tree.Query(callback, aabb); | |
} | |
b2DynamicTreeBroadPhase.prototype.RayCast = function (callback, input) { | |
this.m_tree.RayCast(callback, input); | |
} | |
b2DynamicTreeBroadPhase.prototype.Validate = function () {} | |
b2DynamicTreeBroadPhase.prototype.Rebalance = function (iterations) { | |
if (iterations === undefined) iterations = 0; | |
this.m_tree.Rebalance(iterations); | |
} | |
b2DynamicTreeBroadPhase.prototype.BufferMove = function (proxy) { | |
this.m_moveBuffer[this.m_moveBuffer.length] = proxy; | |
} | |
b2DynamicTreeBroadPhase.prototype.UnBufferMove = function (proxy) { | |
var i = parseInt(this.m_moveBuffer.indexOf(proxy)); | |
this.m_moveBuffer.splice(i, 1); | |
} | |
b2DynamicTreeBroadPhase.prototype.ComparePairs = function (pair1, pair2) { | |
return 0; | |
} | |
b2DynamicTreeBroadPhase.__implements = {}; | |
b2DynamicTreeBroadPhase.__implements[IBroadPhase] = true; | |
b2DynamicTreeNode.b2DynamicTreeNode = function () { | |
this.aabb = new b2AABB(); | |
}; | |
b2DynamicTreeNode.prototype.IsLeaf = function () { | |
return this.child1 == null; | |
} | |
b2DynamicTreePair.b2DynamicTreePair = function () {}; | |
b2Manifold.b2Manifold = function () { | |
this.m_pointCount = 0; | |
}; | |
b2Manifold.prototype.b2Manifold = function () { | |
this.m_points = new Vector(b2Settings.b2_maxManifoldPoints); | |
for (var i = 0; i < b2Settings.b2_maxManifoldPoints; i++) { | |
this.m_points[i] = new b2ManifoldPoint(); | |
} | |
this.m_localPlaneNormal = new b2Vec2(); | |
this.m_localPoint = new b2Vec2(); | |
} | |
b2Manifold.prototype.Reset = function () { | |
for (var i = 0; i < b2Settings.b2_maxManifoldPoints; i++) { | |
((this.m_points[i] instanceof b2ManifoldPoint ? this.m_points[i] : null)).Reset(); | |
} | |
this.m_localPlaneNormal.SetZero(); | |
this.m_localPoint.SetZero(); | |
this.m_type = 0; | |
this.m_pointCount = 0; | |
} | |
b2Manifold.prototype.Set = function (m) { | |
this.m_pointCount = m.m_pointCount; | |
for (var i = 0; i < b2Settings.b2_maxManifoldPoints; i++) { | |
((this.m_points[i] instanceof b2ManifoldPoint ? this.m_points[i] : null)).Set(m.m_points[i]); | |
} | |
this.m_localPlaneNormal.SetV(m.m_localPlaneNormal); | |
this.m_localPoint.SetV(m.m_localPoint); | |
this.m_type = m.m_type; | |
} | |
b2Manifold.prototype.Copy = function () { | |
var copy = new b2Manifold(); | |
copy.Set(this); | |
return copy; | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Collision.b2Manifold.e_circles = 0x0001; | |
Box2D.Collision.b2Manifold.e_faceA = 0x0002; | |
Box2D.Collision.b2Manifold.e_faceB = 0x0004; | |
}); | |
b2ManifoldPoint.b2ManifoldPoint = function () { | |
this.m_localPoint = new b2Vec2(); | |
this.m_id = new b2ContactID(); | |
}; | |
b2ManifoldPoint.prototype.b2ManifoldPoint = function () { | |
this.Reset(); | |
} | |
b2ManifoldPoint.prototype.Reset = function () { | |
this.m_localPoint.SetZero(); | |
this.m_normalImpulse = 0.0; | |
this.m_tangentImpulse = 0.0; | |
this.m_id.key = 0; | |
} | |
b2ManifoldPoint.prototype.Set = function (m) { | |
this.m_localPoint.SetV(m.m_localPoint); | |
this.m_normalImpulse = m.m_normalImpulse; | |
this.m_tangentImpulse = m.m_tangentImpulse; | |
this.m_id.Set(m.m_id); | |
} | |
b2Point.b2Point = function () { | |
this.p = new b2Vec2(); | |
}; | |
b2Point.prototype.Support = function (xf, vX, vY) { | |
if (vX === undefined) vX = 0; | |
if (vY === undefined) vY = 0; | |
return this.p; | |
} | |
b2Point.prototype.GetFirstVertex = function (xf) { | |
return this.p; | |
} | |
b2RayCastInput.b2RayCastInput = function () { | |
this.p1 = new b2Vec2(); | |
this.p2 = new b2Vec2(); | |
}; | |
b2RayCastInput.prototype.b2RayCastInput = function (p1, p2, maxFraction) { | |
if (p1 === undefined) p1 = null; | |
if (p2 === undefined) p2 = null; | |
if (maxFraction === undefined) maxFraction = 1; | |
if (p1) this.p1.SetV(p1); | |
if (p2) this.p2.SetV(p2); | |
this.maxFraction = maxFraction; | |
} | |
b2RayCastOutput.b2RayCastOutput = function () { | |
this.normal = new b2Vec2(); | |
}; | |
b2Segment.b2Segment = function () { | |
this.p1 = new b2Vec2(); | |
this.p2 = new b2Vec2(); | |
}; | |
b2Segment.prototype.TestSegment = function (lambda, normal, segment, maxLambda) { | |
if (maxLambda === undefined) maxLambda = 0; | |
var s = segment.p1; | |
var rX = segment.p2.x - s.x; | |
var rY = segment.p2.y - s.y; | |
var dX = this.p2.x - this.p1.x; | |
var dY = this.p2.y - this.p1.y; | |
var nX = dY; | |
var nY = (-dX); | |
var k_slop = 100.0 * Number.MIN_VALUE; | |
var denom = (-(rX * nX + rY * nY)); | |
if (denom > k_slop) { | |
var bX = s.x - this.p1.x; | |
var bY = s.y - this.p1.y; | |
var a = (bX * nX + bY * nY); | |
if (0.0 <= a && a <= maxLambda * denom) { | |
var mu2 = (-rX * bY) + rY * bX; | |
if ((-k_slop * denom) <= mu2 && mu2 <= denom * (1.0 + k_slop)) { | |
a /= denom; | |
var nLen = Math.sqrt(nX * nX + nY * nY); | |
nX /= nLen; | |
nY /= nLen; | |
lambda[0] = a; | |
normal.Set(nX, nY); | |
return true; | |
} | |
} | |
} | |
return false; | |
} | |
b2Segment.prototype.Extend = function (aabb) { | |
this.ExtendForward(aabb); | |
this.ExtendBackward(aabb); | |
} | |
b2Segment.prototype.ExtendForward = function (aabb) { | |
var dX = this.p2.x - this.p1.x; | |
var dY = this.p2.y - this.p1.y; | |
var lambda = Math.min(dX > 0 ? (aabb.upperBound.x - this.p1.x) / dX : dX < 0 ? (aabb.lowerBound.x - this.p1.x) / dX : Number.POSITIVE_INFINITY, | |
dY > 0 ? (aabb.upperBound.y - this.p1.y) / dY : dY < 0 ? (aabb.lowerBound.y - this.p1.y) / dY : Number.POSITIVE_INFINITY); | |
this.p2.x = this.p1.x + dX * lambda; | |
this.p2.y = this.p1.y + dY * lambda; | |
} | |
b2Segment.prototype.ExtendBackward = function (aabb) { | |
var dX = (-this.p2.x) + this.p1.x; | |
var dY = (-this.p2.y) + this.p1.y; | |
var lambda = Math.min(dX > 0 ? (aabb.upperBound.x - this.p2.x) / dX : dX < 0 ? (aabb.lowerBound.x - this.p2.x) / dX : Number.POSITIVE_INFINITY, | |
dY > 0 ? (aabb.upperBound.y - this.p2.y) / dY : dY < 0 ? (aabb.lowerBound.y - this.p2.y) / dY : Number.POSITIVE_INFINITY); | |
this.p1.x = this.p2.x + dX * lambda; | |
this.p1.y = this.p2.y + dY * lambda; | |
} | |
b2SeparationFunction.b2SeparationFunction = function () { | |
this.m_localPoint = new b2Vec2(); | |
this.m_axis = new b2Vec2(); | |
}; | |
b2SeparationFunction.prototype.Initialize = function (cache, proxyA, transformA, proxyB, transformB) { | |
this.m_proxyA = proxyA; | |
this.m_proxyB = proxyB; | |
var count = parseInt(cache.count); | |
b2Settings.b2Assert(0 < count && count < 3); | |
var localPointA; | |
var localPointA1; | |
var localPointA2; | |
var localPointB; | |
var localPointB1; | |
var localPointB2; | |
var pointAX = 0; | |
var pointAY = 0; | |
var pointBX = 0; | |
var pointBY = 0; | |
var normalX = 0; | |
var normalY = 0; | |
var tMat; | |
var tVec; | |
var s = 0; | |
var sgn = 0; | |
if (count == 1) { | |
this.m_type = b2SeparationFunction.e_points; | |
localPointA = this.m_proxyA.GetVertex(cache.indexA[0]); | |
localPointB = this.m_proxyB.GetVertex(cache.indexB[0]); | |
tVec = localPointA; | |
tMat = transformA.R; | |
pointAX = transformA.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
pointAY = transformA.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
tVec = localPointB; | |
tMat = transformB.R; | |
pointBX = transformB.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
pointBY = transformB.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
this.m_axis.x = pointBX - pointAX; | |
this.m_axis.y = pointBY - pointAY; | |
this.m_axis.Normalize(); | |
} | |
else if (cache.indexB[0] == cache.indexB[1]) { | |
this.m_type = b2SeparationFunction.e_faceA; | |
localPointA1 = this.m_proxyA.GetVertex(cache.indexA[0]); | |
localPointA2 = this.m_proxyA.GetVertex(cache.indexA[1]); | |
localPointB = this.m_proxyB.GetVertex(cache.indexB[0]); | |
this.m_localPoint.x = 0.5 * (localPointA1.x + localPointA2.x); | |
this.m_localPoint.y = 0.5 * (localPointA1.y + localPointA2.y); | |
this.m_axis = b2Math.CrossVF(b2Math.SubtractVV(localPointA2, localPointA1), 1.0); | |
this.m_axis.Normalize(); | |
tVec = this.m_axis; | |
tMat = transformA.R; | |
normalX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; | |
normalY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; | |
tVec = this.m_localPoint; | |
tMat = transformA.R; | |
pointAX = transformA.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
pointAY = transformA.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
tVec = localPointB; | |
tMat = transformB.R; | |
pointBX = transformB.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
pointBY = transformB.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
s = (pointBX - pointAX) * normalX + (pointBY - pointAY) * normalY; | |
if (s < 0.0) { | |
this.m_axis.NegativeSelf(); | |
} | |
} | |
else if (cache.indexA[0] == cache.indexA[0]) { | |
this.m_type = b2SeparationFunction.e_faceB; | |
localPointB1 = this.m_proxyB.GetVertex(cache.indexB[0]); | |
localPointB2 = this.m_proxyB.GetVertex(cache.indexB[1]); | |
localPointA = this.m_proxyA.GetVertex(cache.indexA[0]); | |
this.m_localPoint.x = 0.5 * (localPointB1.x + localPointB2.x); | |
this.m_localPoint.y = 0.5 * (localPointB1.y + localPointB2.y); | |
this.m_axis = b2Math.CrossVF(b2Math.SubtractVV(localPointB2, localPointB1), 1.0); | |
this.m_axis.Normalize(); | |
tVec = this.m_axis; | |
tMat = transformB.R; | |
normalX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; | |
normalY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; | |
tVec = this.m_localPoint; | |
tMat = transformB.R; | |
pointBX = transformB.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
pointBY = transformB.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
tVec = localPointA; | |
tMat = transformA.R; | |
pointAX = transformA.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
pointAY = transformA.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
s = (pointAX - pointBX) * normalX + (pointAY - pointBY) * normalY; | |
if (s < 0.0) { | |
this.m_axis.NegativeSelf(); | |
} | |
} | |
else { | |
localPointA1 = this.m_proxyA.GetVertex(cache.indexA[0]); | |
localPointA2 = this.m_proxyA.GetVertex(cache.indexA[1]); | |
localPointB1 = this.m_proxyB.GetVertex(cache.indexB[0]); | |
localPointB2 = this.m_proxyB.GetVertex(cache.indexB[1]); | |
var pA = b2Math.MulX(transformA, localPointA); | |
var dA = b2Math.MulMV(transformA.R, b2Math.SubtractVV(localPointA2, localPointA1)); | |
var pB = b2Math.MulX(transformB, localPointB); | |
var dB = b2Math.MulMV(transformB.R, b2Math.SubtractVV(localPointB2, localPointB1)); | |
var a = dA.x * dA.x + dA.y * dA.y; | |
var e = dB.x * dB.x + dB.y * dB.y; | |
var r = b2Math.SubtractVV(dB, dA); | |
var c = dA.x * r.x + dA.y * r.y; | |
var f = dB.x * r.x + dB.y * r.y; | |
var b = dA.x * dB.x + dA.y * dB.y; | |
var denom = a * e - b * b; | |
s = 0.0; | |
if (denom != 0.0) { | |
s = b2Math.Clamp((b * f - c * e) / denom, 0.0, 1.0); | |
} | |
var t = (b * s + f) / e; | |
if (t < 0.0) { | |
t = 0.0; | |
s = b2Math.Clamp((b - c) / a, 0.0, 1.0); | |
} | |
localPointA = new b2Vec2(); | |
localPointA.x = localPointA1.x + s * (localPointA2.x - localPointA1.x); | |
localPointA.y = localPointA1.y + s * (localPointA2.y - localPointA1.y); | |
localPointB = new b2Vec2(); | |
localPointB.x = localPointB1.x + s * (localPointB2.x - localPointB1.x); | |
localPointB.y = localPointB1.y + s * (localPointB2.y - localPointB1.y); | |
if (s == 0.0 || s == 1.0) { | |
this.m_type = b2SeparationFunction.e_faceB; | |
this.m_axis = b2Math.CrossVF(b2Math.SubtractVV(localPointB2, localPointB1), 1.0); | |
this.m_axis.Normalize(); | |
this.m_localPoint = localPointB; | |
tVec = this.m_axis; | |
tMat = transformB.R; | |
normalX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; | |
normalY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; | |
tVec = this.m_localPoint; | |
tMat = transformB.R; | |
pointBX = transformB.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
pointBY = transformB.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
tVec = localPointA; | |
tMat = transformA.R; | |
pointAX = transformA.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
pointAY = transformA.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
sgn = (pointAX - pointBX) * normalX + (pointAY - pointBY) * normalY; | |
if (s < 0.0) { | |
this.m_axis.NegativeSelf(); | |
} | |
} | |
else { | |
this.m_type = b2SeparationFunction.e_faceA; | |
this.m_axis = b2Math.CrossVF(b2Math.SubtractVV(localPointA2, localPointA1), 1.0); | |
this.m_localPoint = localPointA; | |
tVec = this.m_axis; | |
tMat = transformA.R; | |
normalX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; | |
normalY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; | |
tVec = this.m_localPoint; | |
tMat = transformA.R; | |
pointAX = transformA.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
pointAY = transformA.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
tVec = localPointB; | |
tMat = transformB.R; | |
pointBX = transformB.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
pointBY = transformB.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
sgn = (pointBX - pointAX) * normalX + (pointBY - pointAY) * normalY; | |
if (s < 0.0) { | |
this.m_axis.NegativeSelf(); | |
} | |
} | |
} | |
} | |
b2SeparationFunction.prototype.Evaluate = function (transformA, transformB) { | |
var axisA; | |
var axisB; | |
var localPointA; | |
var localPointB; | |
var pointA; | |
var pointB; | |
var seperation = 0; | |
var normal; | |
switch (this.m_type) { | |
case b2SeparationFunction.e_points: | |
{ | |
axisA = b2Math.MulTMV(transformA.R, this.m_axis); | |
axisB = b2Math.MulTMV(transformB.R, this.m_axis.GetNegative()); | |
localPointA = this.m_proxyA.GetSupportVertex(axisA); | |
localPointB = this.m_proxyB.GetSupportVertex(axisB); | |
pointA = b2Math.MulX(transformA, localPointA); | |
pointB = b2Math.MulX(transformB, localPointB); | |
seperation = (pointB.x - pointA.x) * this.m_axis.x + (pointB.y - pointA.y) * this.m_axis.y; | |
return seperation; | |
} | |
case b2SeparationFunction.e_faceA: | |
{ | |
normal = b2Math.MulMV(transformA.R, this.m_axis); | |
pointA = b2Math.MulX(transformA, this.m_localPoint); | |
axisB = b2Math.MulTMV(transformB.R, normal.GetNegative()); | |
localPointB = this.m_proxyB.GetSupportVertex(axisB); | |
pointB = b2Math.MulX(transformB, localPointB); | |
seperation = (pointB.x - pointA.x) * normal.x + (pointB.y - pointA.y) * normal.y; | |
return seperation; | |
} | |
case b2SeparationFunction.e_faceB: | |
{ | |
normal = b2Math.MulMV(transformB.R, this.m_axis); | |
pointB = b2Math.MulX(transformB, this.m_localPoint); | |
axisA = b2Math.MulTMV(transformA.R, normal.GetNegative()); | |
localPointA = this.m_proxyA.GetSupportVertex(axisA); | |
pointA = b2Math.MulX(transformA, localPointA); | |
seperation = (pointA.x - pointB.x) * normal.x + (pointA.y - pointB.y) * normal.y; | |
return seperation; | |
} | |
default: | |
b2Settings.b2Assert(false); | |
return 0.0; | |
} | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Collision.b2SeparationFunction.e_points = 0x01; | |
Box2D.Collision.b2SeparationFunction.e_faceA = 0x02; | |
Box2D.Collision.b2SeparationFunction.e_faceB = 0x04; | |
}); | |
b2Simplex.b2Simplex = function () { | |
this.m_v1 = new b2SimplexVertex(); | |
this.m_v2 = new b2SimplexVertex(); | |
this.m_v3 = new b2SimplexVertex(); | |
this.m_vertices = new Vector(3); | |
}; | |
b2Simplex.prototype.b2Simplex = function () { | |
this.m_vertices[0] = this.m_v1; | |
this.m_vertices[1] = this.m_v2; | |
this.m_vertices[2] = this.m_v3; | |
} | |
b2Simplex.prototype.ReadCache = function (cache, proxyA, transformA, proxyB, transformB) { | |
b2Settings.b2Assert(0 <= cache.count && cache.count <= 3); | |
var wALocal; | |
var wBLocal; | |
this.m_count = cache.count; | |
var vertices = this.m_vertices; | |
for (var i = 0; i < this.m_count; i++) { | |
var v = vertices[i]; | |
v.indexA = cache.indexA[i]; | |
v.indexB = cache.indexB[i]; | |
wALocal = proxyA.GetVertex(v.indexA); | |
wBLocal = proxyB.GetVertex(v.indexB); | |
v.wA = b2Math.MulX(transformA, wALocal); | |
v.wB = b2Math.MulX(transformB, wBLocal); | |
v.w = b2Math.SubtractVV(v.wB, v.wA); | |
v.a = 0; | |
} | |
if (this.m_count > 1) { | |
var metric1 = cache.metric; | |
var metric2 = this.GetMetric(); | |
if (metric2 < .5 * metric1 || 2.0 * metric1 < metric2 || metric2 < Number.MIN_VALUE) { | |
this.m_count = 0; | |
} | |
} | |
if (this.m_count == 0) { | |
v = vertices[0]; | |
v.indexA = 0; | |
v.indexB = 0; | |
wALocal = proxyA.GetVertex(0); | |
wBLocal = proxyB.GetVertex(0); | |
v.wA = b2Math.MulX(transformA, wALocal); | |
v.wB = b2Math.MulX(transformB, wBLocal); | |
v.w = b2Math.SubtractVV(v.wB, v.wA); | |
this.m_count = 1; | |
} | |
} | |
b2Simplex.prototype.WriteCache = function (cache) { | |
cache.metric = this.GetMetric(); | |
cache.count = Box2D.parseUInt(this.m_count); | |
var vertices = this.m_vertices; | |
for (var i = 0; i < this.m_count; i++) { | |
cache.indexA[i] = Box2D.parseUInt(vertices[i].indexA); | |
cache.indexB[i] = Box2D.parseUInt(vertices[i].indexB); | |
} | |
} | |
b2Simplex.prototype.GetSearchDirection = function () { | |
switch (this.m_count) { | |
case 1: | |
return this.m_v1.w.GetNegative(); | |
case 2: | |
{ | |
var e12 = b2Math.SubtractVV(this.m_v2.w, this.m_v1.w); | |
var sgn = b2Math.CrossVV(e12, this.m_v1.w.GetNegative()); | |
if (sgn > 0.0) { | |
return b2Math.CrossFV(1.0, e12); | |
} | |
else { | |
return b2Math.CrossVF(e12, 1.0); | |
} | |
} | |
default: | |
b2Settings.b2Assert(false); | |
return new b2Vec2(); | |
} | |
} | |
b2Simplex.prototype.GetClosestPoint = function () { | |
switch (this.m_count) { | |
case 0: | |
b2Settings.b2Assert(false); | |
return new b2Vec2(); | |
case 1: | |
return this.m_v1.w; | |
case 2: | |
return new b2Vec2(this.m_v1.a * this.m_v1.w.x + this.m_v2.a * this.m_v2.w.x, this.m_v1.a * this.m_v1.w.y + this.m_v2.a * this.m_v2.w.y); | |
default: | |
b2Settings.b2Assert(false); | |
return new b2Vec2(); | |
} | |
} | |
b2Simplex.prototype.GetWitnessPoints = function (pA, pB) { | |
switch (this.m_count) { | |
case 0: | |
b2Settings.b2Assert(false); | |
break; | |
case 1: | |
pA.SetV(this.m_v1.wA); | |
pB.SetV(this.m_v1.wB); | |
break; | |
case 2: | |
pA.x = this.m_v1.a * this.m_v1.wA.x + this.m_v2.a * this.m_v2.wA.x; | |
pA.y = this.m_v1.a * this.m_v1.wA.y + this.m_v2.a * this.m_v2.wA.y; | |
pB.x = this.m_v1.a * this.m_v1.wB.x + this.m_v2.a * this.m_v2.wB.x; | |
pB.y = this.m_v1.a * this.m_v1.wB.y + this.m_v2.a * this.m_v2.wB.y; | |
break; | |
case 3: | |
pB.x = pA.x = this.m_v1.a * this.m_v1.wA.x + this.m_v2.a * this.m_v2.wA.x + this.m_v3.a * this.m_v3.wA.x; | |
pB.y = pA.y = this.m_v1.a * this.m_v1.wA.y + this.m_v2.a * this.m_v2.wA.y + this.m_v3.a * this.m_v3.wA.y; | |
break; | |
default: | |
b2Settings.b2Assert(false); | |
break; | |
} | |
} | |
b2Simplex.prototype.GetMetric = function () { | |
switch (this.m_count) { | |
case 0: | |
b2Settings.b2Assert(false); | |
return 0.0; | |
case 1: | |
return 0.0; | |
case 2: | |
return b2Math.SubtractVV(this.m_v1.w, this.m_v2.w).Length(); | |
case 3: | |
return b2Math.CrossVV(b2Math.SubtractVV(this.m_v2.w, this.m_v1.w), b2Math.SubtractVV(this.m_v3.w, this.m_v1.w)); | |
default: | |
b2Settings.b2Assert(false); | |
return 0.0; | |
} | |
} | |
b2Simplex.prototype.Solve2 = function () { | |
var w1 = this.m_v1.w; | |
var w2 = this.m_v2.w; | |
var e12 = b2Math.SubtractVV(w2, w1); | |
var d12_2 = (-(w1.x * e12.x + w1.y * e12.y)); | |
if (d12_2 <= 0.0) { | |
this.m_v1.a = 1.0; | |
this.m_count = 1; | |
return; | |
} | |
var d12_1 = (w2.x * e12.x + w2.y * e12.y); | |
if (d12_1 <= 0.0) { | |
this.m_v2.a = 1.0; | |
this.m_count = 1; | |
this.m_v1.Set(this.m_v2); | |
return; | |
} | |
var inv_d12 = 1.0 / (d12_1 + d12_2); | |
this.m_v1.a = d12_1 * inv_d12; | |
this.m_v2.a = d12_2 * inv_d12; | |
this.m_count = 2; | |
} | |
b2Simplex.prototype.Solve3 = function () { | |
var w1 = this.m_v1.w; | |
var w2 = this.m_v2.w; | |
var w3 = this.m_v3.w; | |
var e12 = b2Math.SubtractVV(w2, w1); | |
var w1e12 = b2Math.Dot(w1, e12); | |
var w2e12 = b2Math.Dot(w2, e12); | |
var d12_1 = w2e12; | |
var d12_2 = (-w1e12); | |
var e13 = b2Math.SubtractVV(w3, w1); | |
var w1e13 = b2Math.Dot(w1, e13); | |
var w3e13 = b2Math.Dot(w3, e13); | |
var d13_1 = w3e13; | |
var d13_2 = (-w1e13); | |
var e23 = b2Math.SubtractVV(w3, w2); | |
var w2e23 = b2Math.Dot(w2, e23); | |
var w3e23 = b2Math.Dot(w3, e23); | |
var d23_1 = w3e23; | |
var d23_2 = (-w2e23); | |
var n123 = b2Math.CrossVV(e12, e13); | |
var d123_1 = n123 * b2Math.CrossVV(w2, w3); | |
var d123_2 = n123 * b2Math.CrossVV(w3, w1); | |
var d123_3 = n123 * b2Math.CrossVV(w1, w2); | |
if (d12_2 <= 0.0 && d13_2 <= 0.0) { | |
this.m_v1.a = 1.0; | |
this.m_count = 1; | |
return; | |
} | |
if (d12_1 > 0.0 && d12_2 > 0.0 && d123_3 <= 0.0) { | |
var inv_d12 = 1.0 / (d12_1 + d12_2); | |
this.m_v1.a = d12_1 * inv_d12; | |
this.m_v2.a = d12_2 * inv_d12; | |
this.m_count = 2; | |
return; | |
} | |
if (d13_1 > 0.0 && d13_2 > 0.0 && d123_2 <= 0.0) { | |
var inv_d13 = 1.0 / (d13_1 + d13_2); | |
this.m_v1.a = d13_1 * inv_d13; | |
this.m_v3.a = d13_2 * inv_d13; | |
this.m_count = 2; | |
this.m_v2.Set(this.m_v3); | |
return; | |
} | |
if (d12_1 <= 0.0 && d23_2 <= 0.0) { | |
this.m_v2.a = 1.0; | |
this.m_count = 1; | |
this.m_v1.Set(this.m_v2); | |
return; | |
} | |
if (d13_1 <= 0.0 && d23_1 <= 0.0) { | |
this.m_v3.a = 1.0; | |
this.m_count = 1; | |
this.m_v1.Set(this.m_v3); | |
return; | |
} | |
if (d23_1 > 0.0 && d23_2 > 0.0 && d123_1 <= 0.0) { | |
var inv_d23 = 1.0 / (d23_1 + d23_2); | |
this.m_v2.a = d23_1 * inv_d23; | |
this.m_v3.a = d23_2 * inv_d23; | |
this.m_count = 2; | |
this.m_v1.Set(this.m_v3); | |
return; | |
} | |
var inv_d123 = 1.0 / (d123_1 + d123_2 + d123_3); | |
this.m_v1.a = d123_1 * inv_d123; | |
this.m_v2.a = d123_2 * inv_d123; | |
this.m_v3.a = d123_3 * inv_d123; | |
this.m_count = 3; | |
} | |
b2SimplexCache.b2SimplexCache = function () { | |
this.indexA = new Vector_a2j_Number(3); | |
this.indexB = new Vector_a2j_Number(3); | |
}; | |
b2SimplexVertex.b2SimplexVertex = function () {}; | |
b2SimplexVertex.prototype.Set = function (other) { | |
this.wA.SetV(other.wA); | |
this.wB.SetV(other.wB); | |
this.w.SetV(other.w); | |
this.a = other.a; | |
this.indexA = other.indexA; | |
this.indexB = other.indexB; | |
} | |
b2TimeOfImpact.b2TimeOfImpact = function () {}; | |
b2TimeOfImpact.TimeOfImpact = function (input) { | |
++b2TimeOfImpact.b2_toiCalls; | |
var proxyA = input.proxyA; | |
var proxyB = input.proxyB; | |
var sweepA = input.sweepA; | |
var sweepB = input.sweepB; | |
b2Settings.b2Assert(sweepA.t0 == sweepB.t0); | |
b2Settings.b2Assert(1.0 - sweepA.t0 > Number.MIN_VALUE); | |
var radius = proxyA.m_radius + proxyB.m_radius; | |
var tolerance = input.tolerance; | |
var alpha = 0.0; | |
var k_maxIterations = 1000; | |
var iter = 0; | |
var target = 0.0; | |
b2TimeOfImpact.s_cache.count = 0; | |
b2TimeOfImpact.s_distanceInput.useRadii = false; | |
for (;;) { | |
sweepA.GetTransform(b2TimeOfImpact.s_xfA, alpha); | |
sweepB.GetTransform(b2TimeOfImpact.s_xfB, alpha); | |
b2TimeOfImpact.s_distanceInput.proxyA = proxyA; | |
b2TimeOfImpact.s_distanceInput.proxyB = proxyB; | |
b2TimeOfImpact.s_distanceInput.transformA = b2TimeOfImpact.s_xfA; | |
b2TimeOfImpact.s_distanceInput.transformB = b2TimeOfImpact.s_xfB; | |
b2Distance.Distance(b2TimeOfImpact.s_distanceOutput, b2TimeOfImpact.s_cache, b2TimeOfImpact.s_distanceInput); | |
if (b2TimeOfImpact.s_distanceOutput.distance <= 0.0) { | |
alpha = 1.0; | |
break; | |
} | |
b2TimeOfImpact.s_fcn.Initialize(b2TimeOfImpact.s_cache, proxyA, b2TimeOfImpact.s_xfA, proxyB, b2TimeOfImpact.s_xfB); | |
var separation = b2TimeOfImpact.s_fcn.Evaluate(b2TimeOfImpact.s_xfA, b2TimeOfImpact.s_xfB); | |
if (separation <= 0.0) { | |
alpha = 1.0; | |
break; | |
} | |
if (iter == 0) { | |
if (separation > radius) { | |
target = b2Math.Max(radius - tolerance, 0.75 * radius); | |
} | |
else { | |
target = b2Math.Max(separation - tolerance, 0.02 * radius); | |
} | |
} | |
if (separation - target < 0.5 * tolerance) { | |
if (iter == 0) { | |
alpha = 1.0; | |
break; | |
} | |
break; | |
} | |
var newAlpha = alpha; { | |
var x1 = alpha; | |
var x2 = 1.0; | |
var f1 = separation; | |
sweepA.GetTransform(b2TimeOfImpact.s_xfA, x2); | |
sweepB.GetTransform(b2TimeOfImpact.s_xfB, x2); | |
var f2 = b2TimeOfImpact.s_fcn.Evaluate(b2TimeOfImpact.s_xfA, b2TimeOfImpact.s_xfB); | |
if (f2 >= target) { | |
alpha = 1.0; | |
break; | |
} | |
var rootIterCount = 0; | |
for (;;) { | |
var x = 0; | |
if (rootIterCount & 1) { | |
x = x1 + (target - f1) * (x2 - x1) / (f2 - f1); | |
} | |
else { | |
x = 0.5 * (x1 + x2); | |
} | |
sweepA.GetTransform(b2TimeOfImpact.s_xfA, x); | |
sweepB.GetTransform(b2TimeOfImpact.s_xfB, x); | |
var f = b2TimeOfImpact.s_fcn.Evaluate(b2TimeOfImpact.s_xfA, b2TimeOfImpact.s_xfB); | |
if (b2Math.Abs(f - target) < 0.025 * tolerance) { | |
newAlpha = x; | |
break; | |
} | |
if (f > target) { | |
x1 = x; | |
f1 = f; | |
} | |
else { | |
x2 = x; | |
f2 = f; | |
}++rootIterCount; | |
++b2TimeOfImpact.b2_toiRootIters; | |
if (rootIterCount == 50) { | |
break; | |
} | |
} | |
b2TimeOfImpact.b2_toiMaxRootIters = b2Math.Max(b2TimeOfImpact.b2_toiMaxRootIters, rootIterCount); | |
} | |
if (newAlpha < (1.0 + 100.0 * Number.MIN_VALUE) * alpha) { | |
break; | |
} | |
alpha = newAlpha; | |
iter++; | |
++b2TimeOfImpact.b2_toiIters; | |
if (iter == k_maxIterations) { | |
break; | |
} | |
} | |
b2TimeOfImpact.b2_toiMaxIters = b2Math.Max(b2TimeOfImpact.b2_toiMaxIters, iter); | |
return alpha; | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Collision.b2TimeOfImpact.b2_toiCalls = 0; | |
Box2D.Collision.b2TimeOfImpact.b2_toiIters = 0; | |
Box2D.Collision.b2TimeOfImpact.b2_toiMaxIters = 0; | |
Box2D.Collision.b2TimeOfImpact.b2_toiRootIters = 0; | |
Box2D.Collision.b2TimeOfImpact.b2_toiMaxRootIters = 0; | |
Box2D.Collision.b2TimeOfImpact.s_cache = new b2SimplexCache(); | |
Box2D.Collision.b2TimeOfImpact.s_distanceInput = new b2DistanceInput(); | |
Box2D.Collision.b2TimeOfImpact.s_xfA = new b2Transform(); | |
Box2D.Collision.b2TimeOfImpact.s_xfB = new b2Transform(); | |
Box2D.Collision.b2TimeOfImpact.s_fcn = new b2SeparationFunction(); | |
Box2D.Collision.b2TimeOfImpact.s_distanceOutput = new b2DistanceOutput(); | |
}); | |
b2TOIInput.b2TOIInput = function () { | |
this.proxyA = new b2DistanceProxy(); | |
this.proxyB = new b2DistanceProxy(); | |
this.sweepA = new b2Sweep(); | |
this.sweepB = new b2Sweep(); | |
}; | |
b2WorldManifold.b2WorldManifold = function () { | |
this.m_normal = new b2Vec2(); | |
}; | |
b2WorldManifold.prototype.b2WorldManifold = function () { | |
this.m_points = new Vector(b2Settings.b2_maxManifoldPoints); | |
for (var i = 0; i < b2Settings.b2_maxManifoldPoints; i++) { | |
this.m_points[i] = new b2Vec2(); | |
} | |
} | |
b2WorldManifold.prototype.Initialize = function (manifold, xfA, radiusA, xfB, radiusB) { | |
if (radiusA === undefined) radiusA = 0; | |
if (radiusB === undefined) radiusB = 0; | |
if (manifold.m_pointCount == 0) { | |
return; | |
} | |
var i = 0; | |
var tVec; | |
var tMat; | |
var normalX = 0; | |
var normalY = 0; | |
var planePointX = 0; | |
var planePointY = 0; | |
var clipPointX = 0; | |
var clipPointY = 0; | |
switch (manifold.m_type) { | |
case b2Manifold.e_circles: | |
{ | |
tMat = xfA.R; | |
tVec = manifold.m_localPoint; | |
var pointAX = xfA.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; | |
var pointAY = xfA.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; | |
tMat = xfB.R; | |
tVec = manifold.m_points[0].m_localPoint; | |
var pointBX = xfB.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; | |
var pointBY = xfB.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; | |
var dX = pointBX - pointAX; | |
var dY = pointBY - pointAY; | |
var d2 = dX * dX + dY * dY; | |
if (d2 > Number.MIN_VALUE * Number.MIN_VALUE) { | |
var d = Math.sqrt(d2); | |
this.m_normal.x = dX / d; | |
this.m_normal.y = dY / d; | |
} | |
else { | |
this.m_normal.x = 1; | |
this.m_normal.y = 0; | |
} | |
var cAX = pointAX + radiusA * this.m_normal.x; | |
var cAY = pointAY + radiusA * this.m_normal.y; | |
var cBX = pointBX - radiusB * this.m_normal.x; | |
var cBY = pointBY - radiusB * this.m_normal.y; | |
this.m_points[0].x = 0.5 * (cAX + cBX); | |
this.m_points[0].y = 0.5 * (cAY + cBY); | |
} | |
break; | |
case b2Manifold.e_faceA: | |
{ | |
tMat = xfA.R; | |
tVec = manifold.m_localPlaneNormal; | |
normalX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; | |
normalY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; | |
tMat = xfA.R; | |
tVec = manifold.m_localPoint; | |
planePointX = xfA.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; | |
planePointY = xfA.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; | |
this.m_normal.x = normalX; | |
this.m_normal.y = normalY; | |
for (i = 0; | |
i < manifold.m_pointCount; i++) { | |
tMat = xfB.R; | |
tVec = manifold.m_points[i].m_localPoint; | |
clipPointX = xfB.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; | |
clipPointY = xfB.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; | |
this.m_points[i].x = clipPointX + 0.5 * (radiusA - (clipPointX - planePointX) * normalX - (clipPointY - planePointY) * normalY - radiusB) * normalX; | |
this.m_points[i].y = clipPointY + 0.5 * (radiusA - (clipPointX - planePointX) * normalX - (clipPointY - planePointY) * normalY - radiusB) * normalY; | |
} | |
} | |
break; | |
case b2Manifold.e_faceB: | |
{ | |
tMat = xfB.R; | |
tVec = manifold.m_localPlaneNormal; | |
normalX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; | |
normalY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; | |
tMat = xfB.R; | |
tVec = manifold.m_localPoint; | |
planePointX = xfB.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; | |
planePointY = xfB.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; | |
this.m_normal.x = (-normalX); | |
this.m_normal.y = (-normalY); | |
for (i = 0; | |
i < manifold.m_pointCount; i++) { | |
tMat = xfA.R; | |
tVec = manifold.m_points[i].m_localPoint; | |
clipPointX = xfA.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; | |
clipPointY = xfA.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; | |
this.m_points[i].x = clipPointX + 0.5 * (radiusB - (clipPointX - planePointX) * normalX - (clipPointY - planePointY) * normalY - radiusA) * normalX; | |
this.m_points[i].y = clipPointY + 0.5 * (radiusB - (clipPointX - planePointX) * normalX - (clipPointY - planePointY) * normalY - radiusA) * normalY; | |
} | |
} | |
break; | |
} | |
} | |
ClipVertex.ClipVertex = function () { | |
this.v = new b2Vec2(); | |
this.id = new b2ContactID(); | |
}; | |
ClipVertex.prototype.Set = function (other) { | |
this.v.SetV(other.v); | |
this.id.Set(other.id); | |
} | |
Features.Features = function () {}; | |
Object.defineProperty(Features.prototype, 'referenceEdge', { | |
enumerable: false, | |
configurable: true, | |
get: function () { | |
return this._referenceEdge; | |
} | |
}); | |
Object.defineProperty(Features.prototype, 'referenceEdge', { | |
enumerable: false, | |
configurable: true, | |
set: function (value) { | |
if (value === undefined) value = 0; | |
this._referenceEdge = value; | |
this._m_id._key = (this._m_id._key & 0xffffff00) | (this._referenceEdge & 0x000000ff); | |
} | |
}); | |
Object.defineProperty(Features.prototype, 'incidentEdge', { | |
enumerable: false, | |
configurable: true, | |
get: function () { | |
return this._incidentEdge; | |
} | |
}); | |
Object.defineProperty(Features.prototype, 'incidentEdge', { | |
enumerable: false, | |
configurable: true, | |
set: function (value) { | |
if (value === undefined) value = 0; | |
this._incidentEdge = value; | |
this._m_id._key = (this._m_id._key & 0xffff00ff) | ((this._incidentEdge << 8) & 0x0000ff00); | |
} | |
}); | |
Object.defineProperty(Features.prototype, 'incidentVertex', { | |
enumerable: false, | |
configurable: true, | |
get: function () { | |
return this._incidentVertex; | |
} | |
}); | |
Object.defineProperty(Features.prototype, 'incidentVertex', { | |
enumerable: false, | |
configurable: true, | |
set: function (value) { | |
if (value === undefined) value = 0; | |
this._incidentVertex = value; | |
this._m_id._key = (this._m_id._key & 0xff00ffff) | ((this._incidentVertex << 16) & 0x00ff0000); | |
} | |
}); | |
Object.defineProperty(Features.prototype, 'flip', { | |
enumerable: false, | |
configurable: true, | |
get: function () { | |
return this._flip; | |
} | |
}); | |
Object.defineProperty(Features.prototype, 'flip', { | |
enumerable: false, | |
configurable: true, | |
set: function (value) { | |
if (value === undefined) value = 0; | |
this._flip = value; | |
this._m_id._key = (this._m_id._key & 0x00ffffff) | ((this._flip << 24) & 0xff000000); | |
} | |
}); | |
})(); | |
(function () { | |
var b2Color = Box2D.Common.b2Color, | |
b2internal = Box2D.Common.b2internal, | |
b2Settings = Box2D.Common.b2Settings, | |
b2CircleShape = Box2D.Collision.Shapes.b2CircleShape, | |
b2EdgeChainDef = Box2D.Collision.Shapes.b2EdgeChainDef, | |
b2EdgeShape = Box2D.Collision.Shapes.b2EdgeShape, | |
b2MassData = Box2D.Collision.Shapes.b2MassData, | |
b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape, | |
b2Shape = Box2D.Collision.Shapes.b2Shape, | |
b2Mat22 = Box2D.Common.Math.b2Mat22, | |
b2Mat33 = Box2D.Common.Math.b2Mat33, | |
b2Math = Box2D.Common.Math.b2Math, | |
b2Sweep = Box2D.Common.Math.b2Sweep, | |
b2Transform = Box2D.Common.Math.b2Transform, | |
b2Vec2 = Box2D.Common.Math.b2Vec2, | |
b2Vec3 = Box2D.Common.Math.b2Vec3, | |
b2Body = Box2D.Dynamics.b2Body, | |
b2BodyDef = Box2D.Dynamics.b2BodyDef, | |
b2ContactFilter = Box2D.Dynamics.b2ContactFilter, | |
b2ContactImpulse = Box2D.Dynamics.b2ContactImpulse, | |
b2ContactListener = Box2D.Dynamics.b2ContactListener, | |
b2ContactManager = Box2D.Dynamics.b2ContactManager, | |
b2DebugDraw = Box2D.Dynamics.b2DebugDraw, | |
b2DestructionListener = Box2D.Dynamics.b2DestructionListener, | |
b2FilterData = Box2D.Dynamics.b2FilterData, | |
b2Fixture = Box2D.Dynamics.b2Fixture, | |
b2FixtureDef = Box2D.Dynamics.b2FixtureDef, | |
b2Island = Box2D.Dynamics.b2Island, | |
b2TimeStep = Box2D.Dynamics.b2TimeStep, | |
b2World = Box2D.Dynamics.b2World, | |
b2AABB = Box2D.Collision.b2AABB, | |
b2Bound = Box2D.Collision.b2Bound, | |
b2BoundValues = Box2D.Collision.b2BoundValues, | |
b2Collision = Box2D.Collision.b2Collision, | |
b2ContactID = Box2D.Collision.b2ContactID, | |
b2ContactPoint = Box2D.Collision.b2ContactPoint, | |
b2Distance = Box2D.Collision.b2Distance, | |
b2DistanceInput = Box2D.Collision.b2DistanceInput, | |
b2DistanceOutput = Box2D.Collision.b2DistanceOutput, | |
b2DistanceProxy = Box2D.Collision.b2DistanceProxy, | |
b2DynamicTree = Box2D.Collision.b2DynamicTree, | |
b2DynamicTreeBroadPhase = Box2D.Collision.b2DynamicTreeBroadPhase, | |
b2DynamicTreeNode = Box2D.Collision.b2DynamicTreeNode, | |
b2DynamicTreePair = Box2D.Collision.b2DynamicTreePair, | |
b2Manifold = Box2D.Collision.b2Manifold, | |
b2ManifoldPoint = Box2D.Collision.b2ManifoldPoint, | |
b2Point = Box2D.Collision.b2Point, | |
b2RayCastInput = Box2D.Collision.b2RayCastInput, | |
b2RayCastOutput = Box2D.Collision.b2RayCastOutput, | |
b2Segment = Box2D.Collision.b2Segment, | |
b2SeparationFunction = Box2D.Collision.b2SeparationFunction, | |
b2Simplex = Box2D.Collision.b2Simplex, | |
b2SimplexCache = Box2D.Collision.b2SimplexCache, | |
b2SimplexVertex = Box2D.Collision.b2SimplexVertex, | |
b2TimeOfImpact = Box2D.Collision.b2TimeOfImpact, | |
b2TOIInput = Box2D.Collision.b2TOIInput, | |
b2WorldManifold = Box2D.Collision.b2WorldManifold, | |
ClipVertex = Box2D.Collision.ClipVertex, | |
Features = Box2D.Collision.Features, | |
IBroadPhase = Box2D.Collision.IBroadPhase; | |
Box2D.inherit(b2CircleShape, Box2D.Collision.Shapes.b2Shape); | |
b2CircleShape.prototype.__super = Box2D.Collision.Shapes.b2Shape.prototype; | |
b2CircleShape.b2CircleShape = function () { | |
Box2D.Collision.Shapes.b2Shape.b2Shape.apply(this, arguments); | |
this.m_p = new b2Vec2(); | |
}; | |
b2CircleShape.prototype.Copy = function () { | |
var s = new b2CircleShape(); | |
s.Set(this); | |
return s; | |
} | |
b2CircleShape.prototype.Set = function (other) { | |
this.__super.Set.call(this, other); | |
if (Box2D.is(other, b2CircleShape)) { | |
var other2 = (other instanceof b2CircleShape ? other : null); | |
this.m_p.SetV(other2.m_p); | |
} | |
} | |
b2CircleShape.prototype.TestPoint = function (transform, p) { | |
var tMat = transform.R; | |
var dX = transform.position.x + (tMat.col1.x * this.m_p.x + tMat.col2.x * this.m_p.y); | |
var dY = transform.position.y + (tMat.col1.y * this.m_p.x + tMat.col2.y * this.m_p.y); | |
dX = p.x - dX; | |
dY = p.y - dY; | |
return (dX * dX + dY * dY) <= this.m_radius * this.m_radius; | |
} | |
b2CircleShape.prototype.RayCast = function (output, input, transform) { | |
var tMat = transform.R; | |
var positionX = transform.position.x + (tMat.col1.x * this.m_p.x + tMat.col2.x * this.m_p.y); | |
var positionY = transform.position.y + (tMat.col1.y * this.m_p.x + tMat.col2.y * this.m_p.y); | |
var sX = input.p1.x - positionX; | |
var sY = input.p1.y - positionY; | |
var b = (sX * sX + sY * sY) - this.m_radius * this.m_radius; | |
var rX = input.p2.x - input.p1.x; | |
var rY = input.p2.y - input.p1.y; | |
var c = (sX * rX + sY * rY); | |
var rr = (rX * rX + rY * rY); | |
var sigma = c * c - rr * b; | |
if (sigma < 0.0 || rr < Number.MIN_VALUE) { | |
return false; | |
} | |
var a = (-(c + Math.sqrt(sigma))); | |
if (0.0 <= a && a <= input.maxFraction * rr) { | |
a /= rr; | |
output.fraction = a; | |
output.normal.x = sX + a * rX; | |
output.normal.y = sY + a * rY; | |
output.normal.Normalize(); | |
return true; | |
} | |
return false; | |
} | |
b2CircleShape.prototype.ComputeAABB = function (aabb, transform) { | |
var tMat = transform.R; | |
var pX = transform.position.x + (tMat.col1.x * this.m_p.x + tMat.col2.x * this.m_p.y); | |
var pY = transform.position.y + (tMat.col1.y * this.m_p.x + tMat.col2.y * this.m_p.y); | |
aabb.lowerBound.Set(pX - this.m_radius, pY - this.m_radius); | |
aabb.upperBound.Set(pX + this.m_radius, pY + this.m_radius); | |
} | |
b2CircleShape.prototype.ComputeMass = function (massData, density) { | |
if (density === undefined) density = 0; | |
massData.mass = density * b2Settings.b2_pi * this.m_radius * this.m_radius; | |
massData.center.SetV(this.m_p); | |
massData.I = massData.mass * (0.5 * this.m_radius * this.m_radius + (this.m_p.x * this.m_p.x + this.m_p.y * this.m_p.y)); | |
} | |
b2CircleShape.prototype.ComputeSubmergedArea = function (normal, offset, xf, c) { | |
if (offset === undefined) offset = 0; | |
var p = b2Math.MulX(xf, this.m_p); | |
var l = (-(b2Math.Dot(normal, p) - offset)); | |
if (l < (-this.m_radius) + Number.MIN_VALUE) { | |
return 0; | |
} | |
if (l > this.m_radius) { | |
c.SetV(p); | |
return Math.PI * this.m_radius * this.m_radius; | |
} | |
var r2 = this.m_radius * this.m_radius; | |
var l2 = l * l; | |
var area = r2 * (Math.asin(l / this.m_radius) + Math.PI / 2) + l * Math.sqrt(r2 - l2); | |
var com = (-2 / 3 * Math.pow(r2 - l2, 1.5) / area); | |
c.x = p.x + normal.x * com; | |
c.y = p.y + normal.y * com; | |
return area; | |
} | |
b2CircleShape.prototype.GetLocalPosition = function () { | |
return this.m_p; | |
} | |
b2CircleShape.prototype.SetLocalPosition = function (position) { | |
this.m_p.SetV(position); | |
} | |
b2CircleShape.prototype.GetRadius = function () { | |
return this.m_radius; | |
} | |
b2CircleShape.prototype.SetRadius = function (radius) { | |
if (radius === undefined) radius = 0; | |
this.m_radius = radius; | |
} | |
b2CircleShape.prototype.b2CircleShape = function (radius) { | |
if (radius === undefined) radius = 0; | |
this.__super.b2Shape.call(this); | |
this.m_type = b2Shape.e_circleShape; | |
this.m_radius = radius; | |
} | |
b2EdgeChainDef.b2EdgeChainDef = function () {}; | |
b2EdgeChainDef.prototype.b2EdgeChainDef = function () { | |
this.vertexCount = 0; | |
this.isALoop = true; | |
this.vertices = []; | |
} | |
Box2D.inherit(b2EdgeShape, Box2D.Collision.Shapes.b2Shape); | |
b2EdgeShape.prototype.__super = Box2D.Collision.Shapes.b2Shape.prototype; | |
b2EdgeShape.b2EdgeShape = function () { | |
Box2D.Collision.Shapes.b2Shape.b2Shape.apply(this, arguments); | |
this.s_supportVec = new b2Vec2(); | |
this.m_v1 = new b2Vec2(); | |
this.m_v2 = new b2Vec2(); | |
this.m_coreV1 = new b2Vec2(); | |
this.m_coreV2 = new b2Vec2(); | |
this.m_normal = new b2Vec2(); | |
this.m_direction = new b2Vec2(); | |
this.m_cornerDir1 = new b2Vec2(); | |
this.m_cornerDir2 = new b2Vec2(); | |
}; | |
b2EdgeShape.prototype.TestPoint = function (transform, p) { | |
return false; | |
} | |
b2EdgeShape.prototype.RayCast = function (output, input, transform) { | |
var tMat; | |
var rX = input.p2.x - input.p1.x; | |
var rY = input.p2.y - input.p1.y; | |
tMat = transform.R; | |
var v1X = transform.position.x + (tMat.col1.x * this.m_v1.x + tMat.col2.x * this.m_v1.y); | |
var v1Y = transform.position.y + (tMat.col1.y * this.m_v1.x + tMat.col2.y * this.m_v1.y); | |
var nX = transform.position.y + (tMat.col1.y * this.m_v2.x + tMat.col2.y * this.m_v2.y) - v1Y; | |
var nY = (-(transform.position.x + (tMat.col1.x * this.m_v2.x + tMat.col2.x * this.m_v2.y) - v1X)); | |
var k_slop = 100.0 * Number.MIN_VALUE; | |
var denom = (-(rX * nX + rY * nY)); | |
if (denom > k_slop) { | |
var bX = input.p1.x - v1X; | |
var bY = input.p1.y - v1Y; | |
var a = (bX * nX + bY * nY); | |
if (0.0 <= a && a <= input.maxFraction * denom) { | |
var mu2 = (-rX * bY) + rY * bX; | |
if ((-k_slop * denom) <= mu2 && mu2 <= denom * (1.0 + k_slop)) { | |
a /= denom; | |
output.fraction = a; | |
var nLen = Math.sqrt(nX * nX + nY * nY); | |
output.normal.x = nX / nLen; | |
output.normal.y = nY / nLen; | |
return true; | |
} | |
} | |
} | |
return false; | |
} | |
b2EdgeShape.prototype.ComputeAABB = function (aabb, transform) { | |
var tMat = transform.R; | |
var v1X = transform.position.x + (tMat.col1.x * this.m_v1.x + tMat.col2.x * this.m_v1.y); | |
var v1Y = transform.position.y + (tMat.col1.y * this.m_v1.x + tMat.col2.y * this.m_v1.y); | |
var v2X = transform.position.x + (tMat.col1.x * this.m_v2.x + tMat.col2.x * this.m_v2.y); | |
var v2Y = transform.position.y + (tMat.col1.y * this.m_v2.x + tMat.col2.y * this.m_v2.y); | |
if (v1X < v2X) { | |
aabb.lowerBound.x = v1X; | |
aabb.upperBound.x = v2X; | |
} | |
else { | |
aabb.lowerBound.x = v2X; | |
aabb.upperBound.x = v1X; | |
} | |
if (v1Y < v2Y) { | |
aabb.lowerBound.y = v1Y; | |
aabb.upperBound.y = v2Y; | |
} | |
else { | |
aabb.lowerBound.y = v2Y; | |
aabb.upperBound.y = v1Y; | |
} | |
} | |
b2EdgeShape.prototype.ComputeMass = function (massData, density) { | |
if (density === undefined) density = 0; | |
massData.mass = 0; | |
massData.center.SetV(this.m_v1); | |
massData.I = 0; | |
} | |
b2EdgeShape.prototype.ComputeSubmergedArea = function (normal, offset, xf, c) { | |
if (offset === undefined) offset = 0; | |
var v0 = new b2Vec2(normal.x * offset, normal.y * offset); | |
var v1 = b2Math.MulX(xf, this.m_v1); | |
var v2 = b2Math.MulX(xf, this.m_v2); | |
var d1 = b2Math.Dot(normal, v1) - offset; | |
var d2 = b2Math.Dot(normal, v2) - offset; | |
if (d1 > 0) { | |
if (d2 > 0) { | |
return 0; | |
} | |
else { | |
v1.x = (-d2 / (d1 - d2) * v1.x) + d1 / (d1 - d2) * v2.x; | |
v1.y = (-d2 / (d1 - d2) * v1.y) + d1 / (d1 - d2) * v2.y; | |
} | |
} | |
else { | |
if (d2 > 0) { | |
v2.x = (-d2 / (d1 - d2) * v1.x) + d1 / (d1 - d2) * v2.x; | |
v2.y = (-d2 / (d1 - d2) * v1.y) + d1 / (d1 - d2) * v2.y; | |
} | |
else {} | |
} | |
c.x = (v0.x + v1.x + v2.x) / 3; | |
c.y = (v0.y + v1.y + v2.y) / 3; | |
return 0.5 * ((v1.x - v0.x) * (v2.y - v0.y) - (v1.y - v0.y) * (v2.x - v0.x)); | |
} | |
b2EdgeShape.prototype.GetLength = function () { | |
return this.m_length; | |
} | |
b2EdgeShape.prototype.GetVertex1 = function () { | |
return this.m_v1; | |
} | |
b2EdgeShape.prototype.GetVertex2 = function () { | |
return this.m_v2; | |
} | |
b2EdgeShape.prototype.GetCoreVertex1 = function () { | |
return this.m_coreV1; | |
} | |
b2EdgeShape.prototype.GetCoreVertex2 = function () { | |
return this.m_coreV2; | |
} | |
b2EdgeShape.prototype.GetNormalVector = function () { | |
return this.m_normal; | |
} | |
b2EdgeShape.prototype.GetDirectionVector = function () { | |
return this.m_direction; | |
} | |
b2EdgeShape.prototype.GetCorner1Vector = function () { | |
return this.m_cornerDir1; | |
} | |
b2EdgeShape.prototype.GetCorner2Vector = function () { | |
return this.m_cornerDir2; | |
} | |
b2EdgeShape.prototype.Corner1IsConvex = function () { | |
return this.m_cornerConvex1; | |
} | |
b2EdgeShape.prototype.Corner2IsConvex = function () { | |
return this.m_cornerConvex2; | |
} | |
b2EdgeShape.prototype.GetFirstVertex = function (xf) { | |
var tMat = xf.R; | |
return new b2Vec2(xf.position.x + (tMat.col1.x * this.m_coreV1.x + tMat.col2.x * this.m_coreV1.y), xf.position.y + (tMat.col1.y * this.m_coreV1.x + tMat.col2.y * this.m_coreV1.y)); | |
} | |
b2EdgeShape.prototype.GetNextEdge = function () { | |
return this.m_nextEdge; | |
} | |
b2EdgeShape.prototype.GetPrevEdge = function () { | |
return this.m_prevEdge; | |
} | |
b2EdgeShape.prototype.Support = function (xf, dX, dY) { | |
if (dX === undefined) dX = 0; | |
if (dY === undefined) dY = 0; | |
var tMat = xf.R; | |
var v1X = xf.position.x + (tMat.col1.x * this.m_coreV1.x + tMat.col2.x * this.m_coreV1.y); | |
var v1Y = xf.position.y + (tMat.col1.y * this.m_coreV1.x + tMat.col2.y * this.m_coreV1.y); | |
var v2X = xf.position.x + (tMat.col1.x * this.m_coreV2.x + tMat.col2.x * this.m_coreV2.y); | |
var v2Y = xf.position.y + (tMat.col1.y * this.m_coreV2.x + tMat.col2.y * this.m_coreV2.y); | |
if ((v1X * dX + v1Y * dY) > (v2X * dX + v2Y * dY)) { | |
this.s_supportVec.x = v1X; | |
this.s_supportVec.y = v1Y; | |
} | |
else { | |
this.s_supportVec.x = v2X; | |
this.s_supportVec.y = v2Y; | |
} | |
return this.s_supportVec; | |
} | |
b2EdgeShape.prototype.b2EdgeShape = function (v1, v2) { | |
this.__super.b2Shape.call(this); | |
this.m_type = b2Shape.e_edgeShape; | |
this.m_prevEdge = null; | |
this.m_nextEdge = null; | |
this.m_v1 = v1; | |
this.m_v2 = v2; | |
this.m_direction.Set(this.m_v2.x - this.m_v1.x, this.m_v2.y - this.m_v1.y); | |
this.m_length = this.m_direction.Normalize(); | |
this.m_normal.Set(this.m_direction.y, (-this.m_direction.x)); | |
this.m_coreV1.Set((-b2Settings.b2_toiSlop * (this.m_normal.x - this.m_direction.x)) + this.m_v1.x, (-b2Settings.b2_toiSlop * (this.m_normal.y - this.m_direction.y)) + this.m_v1.y); | |
this.m_coreV2.Set((-b2Settings.b2_toiSlop * (this.m_normal.x + this.m_direction.x)) + this.m_v2.x, (-b2Settings.b2_toiSlop * (this.m_normal.y + this.m_direction.y)) + this.m_v2.y); | |
this.m_cornerDir1 = this.m_normal; | |
this.m_cornerDir2.Set((-this.m_normal.x), (-this.m_normal.y)); | |
} | |
b2EdgeShape.prototype.SetPrevEdge = function (edge, core, cornerDir, convex) { | |
this.m_prevEdge = edge; | |
this.m_coreV1 = core; | |
this.m_cornerDir1 = cornerDir; | |
this.m_cornerConvex1 = convex; | |
} | |
b2EdgeShape.prototype.SetNextEdge = function (edge, core, cornerDir, convex) { | |
this.m_nextEdge = edge; | |
this.m_coreV2 = core; | |
this.m_cornerDir2 = cornerDir; | |
this.m_cornerConvex2 = convex; | |
} | |
b2MassData.b2MassData = function () { | |
this.mass = 0.0; | |
this.center = new b2Vec2(0, 0); | |
this.I = 0.0; | |
}; | |
Box2D.inherit(b2PolygonShape, Box2D.Collision.Shapes.b2Shape); | |
b2PolygonShape.prototype.__super = Box2D.Collision.Shapes.b2Shape.prototype; | |
b2PolygonShape.b2PolygonShape = function () { | |
Box2D.Collision.Shapes.b2Shape.b2Shape.apply(this, arguments); | |
}; | |
b2PolygonShape.prototype.Copy = function () { | |
var s = new b2PolygonShape(); | |
s.Set(this); | |
return s; | |
} | |
b2PolygonShape.prototype.Set = function (other) { | |
this.__super.Set.call(this, other); | |
if (Box2D.is(other, b2PolygonShape)) { | |
var other2 = (other instanceof b2PolygonShape ? other : null); | |
this.m_centroid.SetV(other2.m_centroid); | |
this.m_vertexCount = other2.m_vertexCount; | |
this.Reserve(this.m_vertexCount); | |
for (var i = 0; i < this.m_vertexCount; i++) { | |
this.m_vertices[i].SetV(other2.m_vertices[i]); | |
this.m_normals[i].SetV(other2.m_normals[i]); | |
} | |
} | |
} | |
b2PolygonShape.prototype.SetAsArray = function (vertices, vertexCount) { | |
if (vertexCount === undefined) vertexCount = 0; | |
var v = new Vector(); | |
var i = 0, | |
tVec; | |
for (i = 0; | |
i < vertices.length; ++i) { | |
tVec = vertices[i]; | |
v.push(tVec); | |
} | |
this.SetAsVector(v, vertexCount); | |
} | |
b2PolygonShape.AsArray = function (vertices, vertexCount) { | |
if (vertexCount === undefined) vertexCount = 0; | |
var polygonShape = new b2PolygonShape(); | |
polygonShape.SetAsArray(vertices, vertexCount); | |
return polygonShape; | |
} | |
b2PolygonShape.prototype.SetAsVector = function (vertices, vertexCount) { | |
if (vertexCount === undefined) vertexCount = 0; | |
if (vertexCount == 0) vertexCount = vertices.length; | |
b2Settings.b2Assert(2 <= vertexCount); | |
this.m_vertexCount = vertexCount; | |
this.Reserve(vertexCount); | |
var i = 0; | |
for (i = 0; | |
i < this.m_vertexCount; i++) { | |
this.m_vertices[i].SetV(vertices[i]); | |
} | |
for (i = 0; | |
i < this.m_vertexCount; ++i) { | |
var i1 = parseInt(i); | |
var i2 = parseInt(i + 1 < this.m_vertexCount ? i + 1 : 0); | |
var edge = b2Math.SubtractVV(this.m_vertices[i2], this.m_vertices[i1]); | |
b2Settings.b2Assert(edge.LengthSquared() > Number.MIN_VALUE); | |
this.m_normals[i].SetV(b2Math.CrossVF(edge, 1.0)); | |
this.m_normals[i].Normalize(); | |
} | |
this.m_centroid = b2PolygonShape.ComputeCentroid(this.m_vertices, this.m_vertexCount); | |
} | |
b2PolygonShape.AsVector = function (vertices, vertexCount) { | |
if (vertexCount === undefined) vertexCount = 0; | |
var polygonShape = new b2PolygonShape(); | |
polygonShape.SetAsVector(vertices, vertexCount); | |
return polygonShape; | |
} | |
b2PolygonShape.prototype.SetAsBox = function (hx, hy) { | |
if (hx === undefined) hx = 0; | |
if (hy === undefined) hy = 0; | |
this.m_vertexCount = 4; | |
this.Reserve(4); | |
this.m_vertices[0].Set((-hx), (-hy)); | |
this.m_vertices[1].Set(hx, (-hy)); | |
this.m_vertices[2].Set(hx, hy); | |
this.m_vertices[3].Set((-hx), hy); | |
this.m_normals[0].Set(0.0, (-1.0)); | |
this.m_normals[1].Set(1.0, 0.0); | |
this.m_normals[2].Set(0.0, 1.0); | |
this.m_normals[3].Set((-1.0), 0.0); | |
this.m_centroid.SetZero(); | |
} | |
b2PolygonShape.AsBox = function (hx, hy) { | |
if (hx === undefined) hx = 0; | |
if (hy === undefined) hy = 0; | |
var polygonShape = new b2PolygonShape(); | |
polygonShape.SetAsBox(hx, hy); | |
return polygonShape; | |
} | |
b2PolygonShape.prototype.SetAsOrientedBox = function (hx, hy, center, angle) { | |
if (hx === undefined) hx = 0; | |
if (hy === undefined) hy = 0; | |
if (center === undefined) center = null; | |
if (angle === undefined) angle = 0.0; | |
this.m_vertexCount = 4; | |
this.Reserve(4); | |
this.m_vertices[0].Set((-hx), (-hy)); | |
this.m_vertices[1].Set(hx, (-hy)); | |
this.m_vertices[2].Set(hx, hy); | |
this.m_vertices[3].Set((-hx), hy); | |
this.m_normals[0].Set(0.0, (-1.0)); | |
this.m_normals[1].Set(1.0, 0.0); | |
this.m_normals[2].Set(0.0, 1.0); | |
this.m_normals[3].Set((-1.0), 0.0); | |
this.m_centroid = center; | |
var xf = new b2Transform(); | |
xf.position = center; | |
xf.R.Set(angle); | |
for (var i = 0; i < this.m_vertexCount; ++i) { | |
this.m_vertices[i] = b2Math.MulX(xf, this.m_vertices[i]); | |
this.m_normals[i] = b2Math.MulMV(xf.R, this.m_normals[i]); | |
} | |
} | |
b2PolygonShape.AsOrientedBox = function (hx, hy, center, angle) { | |
if (hx === undefined) hx = 0; | |
if (hy === undefined) hy = 0; | |
if (center === undefined) center = null; | |
if (angle === undefined) angle = 0.0; | |
var polygonShape = new b2PolygonShape(); | |
polygonShape.SetAsOrientedBox(hx, hy, center, angle); | |
return polygonShape; | |
} | |
b2PolygonShape.prototype.SetAsEdge = function (v1, v2) { | |
this.m_vertexCount = 2; | |
this.Reserve(2); | |
this.m_vertices[0].SetV(v1); | |
this.m_vertices[1].SetV(v2); | |
this.m_centroid.x = 0.5 * (v1.x + v2.x); | |
this.m_centroid.y = 0.5 * (v1.y + v2.y); | |
this.m_normals[0] = b2Math.CrossVF(b2Math.SubtractVV(v2, v1), 1.0); | |
this.m_normals[0].Normalize(); | |
this.m_normals[1].x = (-this.m_normals[0].x); | |
this.m_normals[1].y = (-this.m_normals[0].y); | |
} | |
b2PolygonShape.AsEdge = function (v1, v2) { | |
var polygonShape = new b2PolygonShape(); | |
polygonShape.SetAsEdge(v1, v2); | |
return polygonShape; | |
} | |
b2PolygonShape.prototype.TestPoint = function (xf, p) { | |
var tVec; | |
var tMat = xf.R; | |
var tX = p.x - xf.position.x; | |
var tY = p.y - xf.position.y; | |
var pLocalX = (tX * tMat.col1.x + tY * tMat.col1.y); | |
var pLocalY = (tX * tMat.col2.x + tY * tMat.col2.y); | |
for (var i = 0; i < this.m_vertexCount; ++i) { | |
tVec = this.m_vertices[i]; | |
tX = pLocalX - tVec.x; | |
tY = pLocalY - tVec.y; | |
tVec = this.m_normals[i]; | |
var dot = (tVec.x * tX + tVec.y * tY); | |
if (dot > 0.0) { | |
return false; | |
} | |
} | |
return true; | |
} | |
b2PolygonShape.prototype.RayCast = function (output, input, transform) { | |
var lower = 0.0; | |
var upper = input.maxFraction; | |
var tX = 0; | |
var tY = 0; | |
var tMat; | |
var tVec; | |
tX = input.p1.x - transform.position.x; | |
tY = input.p1.y - transform.position.y; | |
tMat = transform.R; | |
var p1X = (tX * tMat.col1.x + tY * tMat.col1.y); | |
var p1Y = (tX * tMat.col2.x + tY * tMat.col2.y); | |
tX = input.p2.x - transform.position.x; | |
tY = input.p2.y - transform.position.y; | |
tMat = transform.R; | |
var p2X = (tX * tMat.col1.x + tY * tMat.col1.y); | |
var p2Y = (tX * tMat.col2.x + tY * tMat.col2.y); | |
var dX = p2X - p1X; | |
var dY = p2Y - p1Y; | |
var index = parseInt((-1)); | |
for (var i = 0; i < this.m_vertexCount; ++i) { | |
tVec = this.m_vertices[i]; | |
tX = tVec.x - p1X; | |
tY = tVec.y - p1Y; | |
tVec = this.m_normals[i]; | |
var numerator = (tVec.x * tX + tVec.y * tY); | |
var denominator = (tVec.x * dX + tVec.y * dY); | |
if (denominator == 0.0) { | |
if (numerator < 0.0) { | |
return false; | |
} | |
} | |
else { | |
if (denominator < 0.0 && numerator < lower * denominator) { | |
lower = numerator / denominator; | |
index = i; | |
} | |
else if (denominator > 0.0 && numerator < upper * denominator) { | |
upper = numerator / denominator; | |
} | |
} | |
if (upper < lower - Number.MIN_VALUE) { | |
return false; | |
} | |
} | |
if (index >= 0) { | |
output.fraction = lower; | |
tMat = transform.R; | |
tVec = this.m_normals[index]; | |
output.normal.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
output.normal.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
return true; | |
} | |
return false; | |
} | |
b2PolygonShape.prototype.ComputeAABB = function (aabb, xf) { | |
var tMat = xf.R; | |
var tVec = this.m_vertices[0]; | |
var lowerX = xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
var lowerY = xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
var upperX = lowerX; | |
var upperY = lowerY; | |
for (var i = 1; i < this.m_vertexCount; ++i) { | |
tVec = this.m_vertices[i]; | |
var vX = xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
var vY = xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
lowerX = lowerX < vX ? lowerX : vX; | |
lowerY = lowerY < vY ? lowerY : vY; | |
upperX = upperX > vX ? upperX : vX; | |
upperY = upperY > vY ? upperY : vY; | |
} | |
aabb.lowerBound.x = lowerX - this.m_radius; | |
aabb.lowerBound.y = lowerY - this.m_radius; | |
aabb.upperBound.x = upperX + this.m_radius; | |
aabb.upperBound.y = upperY + this.m_radius; | |
} | |
b2PolygonShape.prototype.ComputeMass = function (massData, density) { | |
if (density === undefined) density = 0; | |
if (this.m_vertexCount == 2) { | |
massData.center.x = 0.5 * (this.m_vertices[0].x + this.m_vertices[1].x); | |
massData.center.y = 0.5 * (this.m_vertices[0].y + this.m_vertices[1].y); | |
massData.mass = 0.0; | |
massData.I = 0.0; | |
return; | |
} | |
var centerX = 0.0; | |
var centerY = 0.0; | |
var area = 0.0; | |
var I = 0.0; | |
var p1X = 0.0; | |
var p1Y = 0.0; | |
var k_inv3 = 1.0 / 3.0; | |
for (var i = 0; i < this.m_vertexCount; ++i) { | |
var p2 = this.m_vertices[i]; | |
var p3 = i + 1 < this.m_vertexCount ? this.m_vertices[parseInt(i + 1)] : this.m_vertices[0]; | |
var e1X = p2.x - p1X; | |
var e1Y = p2.y - p1Y; | |
var e2X = p3.x - p1X; | |
var e2Y = p3.y - p1Y; | |
var D = e1X * e2Y - e1Y * e2X; | |
var triangleArea = 0.5 * D;area += triangleArea; | |
centerX += triangleArea * k_inv3 * (p1X + p2.x + p3.x); | |
centerY += triangleArea * k_inv3 * (p1Y + p2.y + p3.y); | |
var px = p1X; | |
var py = p1Y; | |
var ex1 = e1X; | |
var ey1 = e1Y; | |
var ex2 = e2X; | |
var ey2 = e2Y; | |
var intx2 = k_inv3 * (0.25 * (ex1 * ex1 + ex2 * ex1 + ex2 * ex2) + (px * ex1 + px * ex2)) + 0.5 * px * px; | |
var inty2 = k_inv3 * (0.25 * (ey1 * ey1 + ey2 * ey1 + ey2 * ey2) + (py * ey1 + py * ey2)) + 0.5 * py * py;I += D * (intx2 + inty2); | |
} | |
massData.mass = density * area; | |
centerX *= 1.0 / area; | |
centerY *= 1.0 / area; | |
massData.center.Set(centerX, centerY); | |
massData.I = density * I; | |
} | |
b2PolygonShape.prototype.ComputeSubmergedArea = function (normal, offset, xf, c) { | |
if (offset === undefined) offset = 0; | |
var normalL = b2Math.MulTMV(xf.R, normal); | |
var offsetL = offset - b2Math.Dot(normal, xf.position); | |
var depths = new Vector_a2j_Number(); | |
var diveCount = 0; | |
var intoIndex = parseInt((-1)); | |
var outoIndex = parseInt((-1)); | |
var lastSubmerged = false; | |
var i = 0; | |
for (i = 0; | |
i < this.m_vertexCount; ++i) { | |
depths[i] = b2Math.Dot(normalL, this.m_vertices[i]) - offsetL; | |
var isSubmerged = depths[i] < (-Number.MIN_VALUE); | |
if (i > 0) { | |
if (isSubmerged) { | |
if (!lastSubmerged) { | |
intoIndex = i - 1; | |
diveCount++; | |
} | |
} | |
else { | |
if (lastSubmerged) { | |
outoIndex = i - 1; | |
diveCount++; | |
} | |
} | |
} | |
lastSubmerged = isSubmerged; | |
} | |
switch (diveCount) { | |
case 0: | |
if (lastSubmerged) { | |
var md = new b2MassData(); | |
this.ComputeMass(md, 1); | |
c.SetV(b2Math.MulX(xf, md.center)); | |
return md.mass; | |
} | |
else { | |
return 0; | |
} | |
break; | |
case 1: | |
if (intoIndex == (-1)) { | |
intoIndex = this.m_vertexCount - 1; | |
} | |
else { | |
outoIndex = this.m_vertexCount - 1; | |
} | |
break; | |
} | |
var intoIndex2 = parseInt((intoIndex + 1) % this.m_vertexCount); | |
var outoIndex2 = parseInt((outoIndex + 1) % this.m_vertexCount); | |
var intoLamdda = (0 - depths[intoIndex]) / (depths[intoIndex2] - depths[intoIndex]); | |
var outoLamdda = (0 - depths[outoIndex]) / (depths[outoIndex2] - depths[outoIndex]); | |
var intoVec = new b2Vec2(this.m_vertices[intoIndex].x * (1 - intoLamdda) + this.m_vertices[intoIndex2].x * intoLamdda, this.m_vertices[intoIndex].y * (1 - intoLamdda) + this.m_vertices[intoIndex2].y * intoLamdda); | |
var outoVec = new b2Vec2(this.m_vertices[outoIndex].x * (1 - outoLamdda) + this.m_vertices[outoIndex2].x * outoLamdda, this.m_vertices[outoIndex].y * (1 - outoLamdda) + this.m_vertices[outoIndex2].y * outoLamdda); | |
var area = 0; | |
var center = new b2Vec2(); | |
var p2 = this.m_vertices[intoIndex2]; | |
var p3; | |
i = intoIndex2; | |
while (i != outoIndex2) { | |
i = (i + 1) % this.m_vertexCount; | |
if (i == outoIndex2) p3 = outoVec; | |
else p3 = this.m_vertices[i]; | |
var triangleArea = 0.5 * ((p2.x - intoVec.x) * (p3.y - intoVec.y) - (p2.y - intoVec.y) * (p3.x - intoVec.x)); | |
area += triangleArea; | |
center.x += triangleArea * (intoVec.x + p2.x + p3.x) / 3; | |
center.y += triangleArea * (intoVec.y + p2.y + p3.y) / 3; | |
p2 = p3; | |
} | |
center.Multiply(1 / area); | |
c.SetV(b2Math.MulX(xf, center)); | |
return area; | |
} | |
b2PolygonShape.prototype.GetVertexCount = function () { | |
return this.m_vertexCount; | |
} | |
b2PolygonShape.prototype.GetVertices = function () { | |
return this.m_vertices; | |
} | |
b2PolygonShape.prototype.GetNormals = function () { | |
return this.m_normals; | |
} | |
b2PolygonShape.prototype.GetSupport = function (d) { | |
var bestIndex = 0; | |
var bestValue = this.m_vertices[0].x * d.x + this.m_vertices[0].y * d.y; | |
for (var i = 1; i < this.m_vertexCount; ++i) { | |
var value = this.m_vertices[i].x * d.x + this.m_vertices[i].y * d.y; | |
if (value > bestValue) { | |
bestIndex = i; | |
bestValue = value; | |
} | |
} | |
return bestIndex; | |
} | |
b2PolygonShape.prototype.GetSupportVertex = function (d) { | |
var bestIndex = 0; | |
var bestValue = this.m_vertices[0].x * d.x + this.m_vertices[0].y * d.y; | |
for (var i = 1; i < this.m_vertexCount; ++i) { | |
var value = this.m_vertices[i].x * d.x + this.m_vertices[i].y * d.y; | |
if (value > bestValue) { | |
bestIndex = i; | |
bestValue = value; | |
} | |
} | |
return this.m_vertices[bestIndex]; | |
} | |
b2PolygonShape.prototype.Validate = function () { | |
return false; | |
} | |
b2PolygonShape.prototype.b2PolygonShape = function () { | |
this.__super.b2Shape.call(this); | |
this.m_type = b2Shape.e_polygonShape; | |
this.m_centroid = new b2Vec2(); | |
this.m_vertices = new Vector(); | |
this.m_normals = new Vector(); | |
} | |
b2PolygonShape.prototype.Reserve = function (count) { | |
if (count === undefined) count = 0; | |
for (var i = parseInt(this.m_vertices.length); i < count; i++) { | |
this.m_vertices[i] = new b2Vec2(); | |
this.m_normals[i] = new b2Vec2(); | |
} | |
} | |
b2PolygonShape.ComputeCentroid = function (vs, count) { | |
if (count === undefined) count = 0; | |
var c = new b2Vec2(); | |
var area = 0.0; | |
var p1X = 0.0; | |
var p1Y = 0.0; | |
var inv3 = 1.0 / 3.0; | |
for (var i = 0; i < count; ++i) { | |
var p2 = vs[i]; | |
var p3 = i + 1 < count ? vs[parseInt(i + 1)] : vs[0]; | |
var e1X = p2.x - p1X; | |
var e1Y = p2.y - p1Y; | |
var e2X = p3.x - p1X; | |
var e2Y = p3.y - p1Y; | |
var D = (e1X * e2Y - e1Y * e2X); | |
var triangleArea = 0.5 * D;area += triangleArea; | |
c.x += triangleArea * inv3 * (p1X + p2.x + p3.x); | |
c.y += triangleArea * inv3 * (p1Y + p2.y + p3.y); | |
} | |
c.x *= 1.0 / area; | |
c.y *= 1.0 / area; | |
return c; | |
} | |
b2PolygonShape.ComputeOBB = function (obb, vs, count) { | |
if (count === undefined) count = 0; | |
var i = 0; | |
var p = new Vector(count + 1); | |
for (i = 0; | |
i < count; ++i) { | |
p[i] = vs[i]; | |
} | |
p[count] = p[0]; | |
var minArea = Number.MAX_VALUE; | |
for (i = 1; | |
i <= count; ++i) { | |
var root = p[parseInt(i - 1)]; | |
var uxX = p[i].x - root.x; | |
var uxY = p[i].y - root.y; | |
var length = Math.sqrt(uxX * uxX + uxY * uxY); | |
uxX /= length; | |
uxY /= length; | |
var uyX = (-uxY); | |
var uyY = uxX; | |
var lowerX = Number.MAX_VALUE; | |
var lowerY = Number.MAX_VALUE; | |
var upperX = (-Number.MAX_VALUE); | |
var upperY = (-Number.MAX_VALUE); | |
for (var j = 0; j < count; ++j) { | |
var dX = p[j].x - root.x; | |
var dY = p[j].y - root.y; | |
var rX = (uxX * dX + uxY * dY); | |
var rY = (uyX * dX + uyY * dY); | |
if (rX < lowerX) lowerX = rX; | |
if (rY < lowerY) lowerY = rY; | |
if (rX > upperX) upperX = rX; | |
if (rY > upperY) upperY = rY; | |
} | |
var area = (upperX - lowerX) * (upperY - lowerY); | |
if (area < 0.95 * minArea) { | |
minArea = area; | |
obb.R.col1.x = uxX; | |
obb.R.col1.y = uxY; | |
obb.R.col2.x = uyX; | |
obb.R.col2.y = uyY; | |
var centerX = 0.5 * (lowerX + upperX); | |
var centerY = 0.5 * (lowerY + upperY); | |
var tMat = obb.R; | |
obb.center.x = root.x + (tMat.col1.x * centerX + tMat.col2.x * centerY); | |
obb.center.y = root.y + (tMat.col1.y * centerX + tMat.col2.y * centerY); | |
obb.extents.x = 0.5 * (upperX - lowerX); | |
obb.extents.y = 0.5 * (upperY - lowerY); | |
} | |
} | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Collision.Shapes.b2PolygonShape.s_mat = new b2Mat22(); | |
}); | |
b2Shape.b2Shape = function () {}; | |
b2Shape.prototype.Copy = function () { | |
return null; | |
} | |
b2Shape.prototype.Set = function (other) { | |
this.m_radius = other.m_radius; | |
} | |
b2Shape.prototype.GetType = function () { | |
return this.m_type; | |
} | |
b2Shape.prototype.TestPoint = function (xf, p) { | |
return false; | |
} | |
b2Shape.prototype.RayCast = function (output, input, transform) { | |
return false; | |
} | |
b2Shape.prototype.ComputeAABB = function (aabb, xf) {} | |
b2Shape.prototype.ComputeMass = function (massData, density) { | |
if (density === undefined) density = 0; | |
} | |
b2Shape.prototype.ComputeSubmergedArea = function (normal, offset, xf, c) { | |
if (offset === undefined) offset = 0; | |
return 0; | |
} | |
b2Shape.TestOverlap = function (shape1, transform1, shape2, transform2) { | |
var input = new b2DistanceInput(); | |
input.proxyA = new b2DistanceProxy(); | |
input.proxyA.Set(shape1); | |
input.proxyB = new b2DistanceProxy(); | |
input.proxyB.Set(shape2); | |
input.transformA = transform1; | |
input.transformB = transform2; | |
input.useRadii = true; | |
var simplexCache = new b2SimplexCache(); | |
simplexCache.count = 0; | |
var output = new b2DistanceOutput(); | |
b2Distance.Distance(output, simplexCache, input); | |
return output.distance < 10.0 * Number.MIN_VALUE; | |
} | |
b2Shape.prototype.b2Shape = function () { | |
this.m_type = b2Shape.e_unknownShape; | |
this.m_radius = b2Settings.b2_linearSlop; | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Collision.Shapes.b2Shape.e_unknownShape = parseInt((-1)); | |
Box2D.Collision.Shapes.b2Shape.e_circleShape = 0; | |
Box2D.Collision.Shapes.b2Shape.e_polygonShape = 1; | |
Box2D.Collision.Shapes.b2Shape.e_edgeShape = 2; | |
Box2D.Collision.Shapes.b2Shape.e_shapeTypeCount = 3; | |
Box2D.Collision.Shapes.b2Shape.e_hitCollide = 1; | |
Box2D.Collision.Shapes.b2Shape.e_missCollide = 0; | |
Box2D.Collision.Shapes.b2Shape.e_startsInsideCollide = parseInt((-1)); | |
}); | |
})(); | |
(function () { | |
var b2Color = Box2D.Common.b2Color, | |
b2internal = Box2D.Common.b2internal, | |
b2Settings = Box2D.Common.b2Settings, | |
b2Mat22 = Box2D.Common.Math.b2Mat22, | |
b2Mat33 = Box2D.Common.Math.b2Mat33, | |
b2Math = Box2D.Common.Math.b2Math, | |
b2Sweep = Box2D.Common.Math.b2Sweep, | |
b2Transform = Box2D.Common.Math.b2Transform, | |
b2Vec2 = Box2D.Common.Math.b2Vec2, | |
b2Vec3 = Box2D.Common.Math.b2Vec3; | |
b2Color.b2Color = function () { | |
this._r = 0; | |
this._g = 0; | |
this._b = 0; | |
}; | |
b2Color.prototype.b2Color = function (rr, gg, bb) { | |
if (rr === undefined) rr = 0; | |
if (gg === undefined) gg = 0; | |
if (bb === undefined) bb = 0; | |
this._r = Box2D.parseUInt(255 * b2Math.Clamp(rr, 0.0, 1.0)); | |
this._g = Box2D.parseUInt(255 * b2Math.Clamp(gg, 0.0, 1.0)); | |
this._b = Box2D.parseUInt(255 * b2Math.Clamp(bb, 0.0, 1.0)); | |
} | |
b2Color.prototype.Set = function (rr, gg, bb) { | |
if (rr === undefined) rr = 0; | |
if (gg === undefined) gg = 0; | |
if (bb === undefined) bb = 0; | |
this._r = Box2D.parseUInt(255 * b2Math.Clamp(rr, 0.0, 1.0)); | |
this._g = Box2D.parseUInt(255 * b2Math.Clamp(gg, 0.0, 1.0)); | |
this._b = Box2D.parseUInt(255 * b2Math.Clamp(bb, 0.0, 1.0)); | |
} | |
Object.defineProperty(b2Color.prototype, 'r', { | |
enumerable: false, | |
configurable: true, | |
set: function (rr) { | |
if (rr === undefined) rr = 0; | |
this._r = Box2D.parseUInt(255 * b2Math.Clamp(rr, 0.0, 1.0)); | |
} | |
}); | |
Object.defineProperty(b2Color.prototype, 'g', { | |
enumerable: false, | |
configurable: true, | |
set: function (gg) { | |
if (gg === undefined) gg = 0; | |
this._g = Box2D.parseUInt(255 * b2Math.Clamp(gg, 0.0, 1.0)); | |
} | |
}); | |
Object.defineProperty(b2Color.prototype, 'b', { | |
enumerable: false, | |
configurable: true, | |
set: function (bb) { | |
if (bb === undefined) bb = 0; | |
this._b = Box2D.parseUInt(255 * b2Math.Clamp(bb, 0.0, 1.0)); | |
} | |
}); | |
Object.defineProperty(b2Color.prototype, 'color', { | |
enumerable: false, | |
configurable: true, | |
get: function () { | |
return (this._r << 16) | (this._g << 8) | (this._b); | |
} | |
}); | |
b2Settings.b2Settings = function () {}; | |
b2Settings.b2MixFriction = function (friction1, friction2) { | |
if (friction1 === undefined) friction1 = 0; | |
if (friction2 === undefined) friction2 = 0; | |
return Math.sqrt(friction1 * friction2); | |
} | |
b2Settings.b2MixRestitution = function (restitution1, restitution2) { | |
if (restitution1 === undefined) restitution1 = 0; | |
if (restitution2 === undefined) restitution2 = 0; | |
return restitution1 > restitution2 ? restitution1 : restitution2; | |
} | |
b2Settings.b2Assert = function (a) { | |
if (!a) { | |
throw "Assertion Failed"; | |
} | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Common.b2Settings.VERSION = "2.1alpha"; | |
Box2D.Common.b2Settings.USHRT_MAX = 0x0000ffff; | |
Box2D.Common.b2Settings.b2_pi = Math.PI; | |
Box2D.Common.b2Settings.b2_maxManifoldPoints = 2; | |
Box2D.Common.b2Settings.b2_aabbExtension = 0.1; | |
Box2D.Common.b2Settings.b2_aabbMultiplier = 2.0; | |
Box2D.Common.b2Settings.b2_polygonRadius = 2.0 * b2Settings.b2_linearSlop; | |
Box2D.Common.b2Settings.b2_linearSlop = 0.005; | |
Box2D.Common.b2Settings.b2_angularSlop = 2.0 / 180.0 * b2Settings.b2_pi; | |
Box2D.Common.b2Settings.b2_toiSlop = 8.0 * b2Settings.b2_linearSlop; | |
Box2D.Common.b2Settings.b2_maxTOIContactsPerIsland = 32; | |
Box2D.Common.b2Settings.b2_maxTOIJointsPerIsland = 32; | |
Box2D.Common.b2Settings.b2_velocityThreshold = 1.0; | |
Box2D.Common.b2Settings.b2_maxLinearCorrection = 0.2; | |
Box2D.Common.b2Settings.b2_maxAngularCorrection = 8.0 / 180.0 * b2Settings.b2_pi; | |
Box2D.Common.b2Settings.b2_maxTranslation = 2.0; | |
Box2D.Common.b2Settings.b2_maxTranslationSquared = b2Settings.b2_maxTranslation * b2Settings.b2_maxTranslation; | |
Box2D.Common.b2Settings.b2_maxRotation = 0.5 * b2Settings.b2_pi; | |
Box2D.Common.b2Settings.b2_maxRotationSquared = b2Settings.b2_maxRotation * b2Settings.b2_maxRotation; | |
Box2D.Common.b2Settings.b2_contactBaumgarte = 0.2; | |
Box2D.Common.b2Settings.b2_timeToSleep = 0.5; | |
Box2D.Common.b2Settings.b2_linearSleepTolerance = 0.01; | |
Box2D.Common.b2Settings.b2_angularSleepTolerance = 2.0 / 180.0 * b2Settings.b2_pi; | |
}); | |
})(); | |
(function () { | |
var b2AABB = Box2D.Collision.b2AABB, | |
b2Color = Box2D.Common.b2Color, | |
b2internal = Box2D.Common.b2internal, | |
b2Settings = Box2D.Common.b2Settings, | |
b2Mat22 = Box2D.Common.Math.b2Mat22, | |
b2Mat33 = Box2D.Common.Math.b2Mat33, | |
b2Math = Box2D.Common.Math.b2Math, | |
b2Sweep = Box2D.Common.Math.b2Sweep, | |
b2Transform = Box2D.Common.Math.b2Transform, | |
b2Vec2 = Box2D.Common.Math.b2Vec2, | |
b2Vec3 = Box2D.Common.Math.b2Vec3; | |
b2Mat22.b2Mat22 = function () { | |
this.col1 = new b2Vec2(); | |
this.col2 = new b2Vec2(); | |
}; | |
b2Mat22.prototype.b2Mat22 = function () { | |
this.SetIdentity(); | |
} | |
b2Mat22.FromAngle = function (angle) { | |
if (angle === undefined) angle = 0; | |
var mat = new b2Mat22(); | |
mat.Set(angle); | |
return mat; | |
} | |
b2Mat22.FromVV = function (c1, c2) { | |
var mat = new b2Mat22(); | |
mat.SetVV(c1, c2); | |
return mat; | |
} | |
b2Mat22.prototype.Set = function (angle) { | |
if (angle === undefined) angle = 0; | |
var c = Math.cos(angle); | |
var s = Math.sin(angle); | |
this.col1.x = c; | |
this.col2.x = (-s); | |
this.col1.y = s; | |
this.col2.y = c; | |
} | |
b2Mat22.prototype.SetVV = function (c1, c2) { | |
this.col1.SetV(c1); | |
this.col2.SetV(c2); | |
} | |
b2Mat22.prototype.Copy = function () { | |
var mat = new b2Mat22(); | |
mat.SetM(this); | |
return mat; | |
} | |
b2Mat22.prototype.SetM = function (m) { | |
this.col1.SetV(m.col1); | |
this.col2.SetV(m.col2); | |
} | |
b2Mat22.prototype.AddM = function (m) { | |
this.col1.x += m.col1.x; | |
this.col1.y += m.col1.y; | |
this.col2.x += m.col2.x; | |
this.col2.y += m.col2.y; | |
} | |
b2Mat22.prototype.SetIdentity = function () { | |
this.col1.x = 1.0; | |
this.col2.x = 0.0; | |
this.col1.y = 0.0; | |
this.col2.y = 1.0; | |
} | |
b2Mat22.prototype.SetZero = function () { | |
this.col1.x = 0.0; | |
this.col2.x = 0.0; | |
this.col1.y = 0.0; | |
this.col2.y = 0.0; | |
} | |
b2Mat22.prototype.GetAngle = function () { | |
return Math.atan2(this.col1.y, this.col1.x); | |
} | |
b2Mat22.prototype.GetInverse = function (out) { | |
var a = this.col1.x; | |
var b = this.col2.x; | |
var c = this.col1.y; | |
var d = this.col2.y; | |
var det = a * d - b * c; | |
if (det != 0.0) { | |
det = 1.0 / det; | |
} | |
out.col1.x = det * d; | |
out.col2.x = (-det * b); | |
out.col1.y = (-det * c); | |
out.col2.y = det * a; | |
return out; | |
} | |
b2Mat22.prototype.Solve = function (out, bX, bY) { | |
if (bX === undefined) bX = 0; | |
if (bY === undefined) bY = 0; | |
var a11 = this.col1.x; | |
var a12 = this.col2.x; | |
var a21 = this.col1.y; | |
var a22 = this.col2.y; | |
var det = a11 * a22 - a12 * a21; | |
if (det != 0.0) { | |
det = 1.0 / det; | |
} | |
out.x = det * (a22 * bX - a12 * bY); | |
out.y = det * (a11 * bY - a21 * bX); | |
return out; | |
} | |
b2Mat22.prototype.Abs = function () { | |
this.col1.Abs(); | |
this.col2.Abs(); | |
} | |
b2Mat33.b2Mat33 = function () { | |
this.col1 = new b2Vec3(); | |
this.col2 = new b2Vec3(); | |
this.col3 = new b2Vec3(); | |
}; | |
b2Mat33.prototype.b2Mat33 = function (c1, c2, c3) { | |
if (c1 === undefined) c1 = null; | |
if (c2 === undefined) c2 = null; | |
if (c3 === undefined) c3 = null; | |
if (!c1 && !c2 && !c3) { | |
this.col1.SetZero(); | |
this.col2.SetZero(); | |
this.col3.SetZero(); | |
} | |
else { | |
this.col1.SetV(c1); | |
this.col2.SetV(c2); | |
this.col3.SetV(c3); | |
} | |
} | |
b2Mat33.prototype.SetVVV = function (c1, c2, c3) { | |
this.col1.SetV(c1); | |
this.col2.SetV(c2); | |
this.col3.SetV(c3); | |
} | |
b2Mat33.prototype.Copy = function () { | |
return new b2Mat33(this.col1, this.col2, this.col3); | |
} | |
b2Mat33.prototype.SetM = function (m) { | |
this.col1.SetV(m.col1); | |
this.col2.SetV(m.col2); | |
this.col3.SetV(m.col3); | |
} | |
b2Mat33.prototype.AddM = function (m) { | |
this.col1.x += m.col1.x; | |
this.col1.y += m.col1.y; | |
this.col1.z += m.col1.z; | |
this.col2.x += m.col2.x; | |
this.col2.y += m.col2.y; | |
this.col2.z += m.col2.z; | |
this.col3.x += m.col3.x; | |
this.col3.y += m.col3.y; | |
this.col3.z += m.col3.z; | |
} | |
b2Mat33.prototype.SetIdentity = function () { | |
this.col1.x = 1.0; | |
this.col2.x = 0.0; | |
this.col3.x = 0.0; | |
this.col1.y = 0.0; | |
this.col2.y = 1.0; | |
this.col3.y = 0.0; | |
this.col1.z = 0.0; | |
this.col2.z = 0.0; | |
this.col3.z = 1.0; | |
} | |
b2Mat33.prototype.SetZero = function () { | |
this.col1.x = 0.0; | |
this.col2.x = 0.0; | |
this.col3.x = 0.0; | |
this.col1.y = 0.0; | |
this.col2.y = 0.0; | |
this.col3.y = 0.0; | |
this.col1.z = 0.0; | |
this.col2.z = 0.0; | |
this.col3.z = 0.0; | |
} | |
b2Mat33.prototype.Solve22 = function (out, bX, bY) { | |
if (bX === undefined) bX = 0; | |
if (bY === undefined) bY = 0; | |
var a11 = this.col1.x; | |
var a12 = this.col2.x; | |
var a21 = this.col1.y; | |
var a22 = this.col2.y; | |
var det = a11 * a22 - a12 * a21; | |
if (det != 0.0) { | |
det = 1.0 / det; | |
} | |
out.x = det * (a22 * bX - a12 * bY); | |
out.y = det * (a11 * bY - a21 * bX); | |
return out; | |
} | |
b2Mat33.prototype.Solve33 = function (out, bX, bY, bZ) { | |
if (bX === undefined) bX = 0; | |
if (bY === undefined) bY = 0; | |
if (bZ === undefined) bZ = 0; | |
var a11 = this.col1.x; | |
var a21 = this.col1.y; | |
var a31 = this.col1.z; | |
var a12 = this.col2.x; | |
var a22 = this.col2.y; | |
var a32 = this.col2.z; | |
var a13 = this.col3.x; | |
var a23 = this.col3.y; | |
var a33 = this.col3.z; | |
var det = a11 * (a22 * a33 - a32 * a23) + a21 * (a32 * a13 - a12 * a33) + a31 * (a12 * a23 - a22 * a13); | |
if (det != 0.0) { | |
det = 1.0 / det; | |
} | |
out.x = det * (bX * (a22 * a33 - a32 * a23) + bY * (a32 * a13 - a12 * a33) + bZ * (a12 * a23 - a22 * a13)); | |
out.y = det * (a11 * (bY * a33 - bZ * a23) + a21 * (bZ * a13 - bX * a33) + a31 * (bX * a23 - bY * a13)); | |
out.z = det * (a11 * (a22 * bZ - a32 * bY) + a21 * (a32 * bX - a12 * bZ) + a31 * (a12 * bY - a22 * bX)); | |
return out; | |
} | |
b2Math.b2Math = function () {}; | |
b2Math.IsValid = function (x) { | |
if (x === undefined) x = 0; | |
return isFinite(x); | |
} | |
b2Math.Dot = function (a, b) { | |
return a.x * b.x + a.y * b.y; | |
} | |
b2Math.CrossVV = function (a, b) { | |
return a.x * b.y - a.y * b.x; | |
} | |
b2Math.CrossVF = function (a, s) { | |
if (s === undefined) s = 0; | |
var v = new b2Vec2(s * a.y, (-s * a.x)); | |
return v; | |
} | |
b2Math.CrossFV = function (s, a) { | |
if (s === undefined) s = 0; | |
var v = new b2Vec2((-s * a.y), s * a.x); | |
return v; | |
} | |
b2Math.MulMV = function (A, v) { | |
var u = new b2Vec2(A.col1.x * v.x + A.col2.x * v.y, A.col1.y * v.x + A.col2.y * v.y); | |
return u; | |
} | |
b2Math.MulTMV = function (A, v) { | |
var u = new b2Vec2(b2Math.Dot(v, A.col1), b2Math.Dot(v, A.col2)); | |
return u; | |
} | |
b2Math.MulX = function (T, v) { | |
var a = b2Math.MulMV(T.R, v); | |
a.x += T.position.x; | |
a.y += T.position.y; | |
return a; | |
} | |
b2Math.MulXT = function (T, v) { | |
var a = b2Math.SubtractVV(v, T.position); | |
var tX = (a.x * T.R.col1.x + a.y * T.R.col1.y); | |
a.y = (a.x * T.R.col2.x + a.y * T.R.col2.y); | |
a.x = tX; | |
return a; | |
} | |
b2Math.AddVV = function (a, b) { | |
var v = new b2Vec2(a.x + b.x, a.y + b.y); | |
return v; | |
} | |
b2Math.SubtractVV = function (a, b) { | |
var v = new b2Vec2(a.x - b.x, a.y - b.y); | |
return v; | |
} | |
b2Math.Distance = function (a, b) { | |
var cX = a.x - b.x; | |
var cY = a.y - b.y; | |
return Math.sqrt(cX * cX + cY * cY); | |
} | |
b2Math.DistanceSquared = function (a, b) { | |
var cX = a.x - b.x; | |
var cY = a.y - b.y; | |
return (cX * cX + cY * cY); | |
} | |
b2Math.MulFV = function (s, a) { | |
if (s === undefined) s = 0; | |
var v = new b2Vec2(s * a.x, s * a.y); | |
return v; | |
} | |
b2Math.AddMM = function (A, B) { | |
var C = b2Mat22.FromVV(b2Math.AddVV(A.col1, B.col1), b2Math.AddVV(A.col2, B.col2)); | |
return C; | |
} | |
b2Math.MulMM = function (A, B) { | |
var C = b2Mat22.FromVV(b2Math.MulMV(A, B.col1), b2Math.MulMV(A, B.col2)); | |
return C; | |
} | |
b2Math.MulTMM = function (A, B) { | |
var c1 = new b2Vec2(b2Math.Dot(A.col1, B.col1), b2Math.Dot(A.col2, B.col1)); | |
var c2 = new b2Vec2(b2Math.Dot(A.col1, B.col2), b2Math.Dot(A.col2, B.col2)); | |
var C = b2Mat22.FromVV(c1, c2); | |
return C; | |
} | |
b2Math.Abs = function (a) { | |
if (a === undefined) a = 0; | |
return a > 0.0 ? a : (-a); | |
} | |
b2Math.AbsV = function (a) { | |
var b = new b2Vec2(b2Math.Abs(a.x), b2Math.Abs(a.y)); | |
return b; | |
} | |
b2Math.AbsM = function (A) { | |
var B = b2Mat22.FromVV(b2Math.AbsV(A.col1), b2Math.AbsV(A.col2)); | |
return B; | |
} | |
b2Math.Min = function (a, b) { | |
if (a === undefined) a = 0; | |
if (b === undefined) b = 0; | |
return a < b ? a : b; | |
} | |
b2Math.MinV = function (a, b) { | |
var c = new b2Vec2(b2Math.Min(a.x, b.x), b2Math.Min(a.y, b.y)); | |
return c; | |
} | |
b2Math.Max = function (a, b) { | |
if (a === undefined) a = 0; | |
if (b === undefined) b = 0; | |
return a > b ? a : b; | |
} | |
b2Math.MaxV = function (a, b) { | |
var c = new b2Vec2(b2Math.Max(a.x, b.x), b2Math.Max(a.y, b.y)); | |
return c; | |
} | |
b2Math.Clamp = function (a, low, high) { | |
if (a === undefined) a = 0; | |
if (low === undefined) low = 0; | |
if (high === undefined) high = 0; | |
return a < low ? low : a > high ? high : a; | |
} | |
b2Math.ClampV = function (a, low, high) { | |
return b2Math.MaxV(low, b2Math.MinV(a, high)); | |
} | |
b2Math.Swap = function (a, b) { | |
var tmp = a[0]; | |
a[0] = b[0]; | |
b[0] = tmp; | |
} | |
b2Math.Random = function () { | |
return Math.random() * 2 - 1; | |
} | |
b2Math.RandomRange = function (lo, hi) { | |
if (lo === undefined) lo = 0; | |
if (hi === undefined) hi = 0; | |
var r = Math.random(); | |
r = (hi - lo) * r + lo; | |
return r; | |
} | |
b2Math.NextPowerOfTwo = function (x) { | |
if (x === undefined) x = 0; | |
x |= (x >> 1) & 0x7FFFFFFF; | |
x |= (x >> 2) & 0x3FFFFFFF; | |
x |= (x >> 4) & 0x0FFFFFFF; | |
x |= (x >> 8) & 0x00FFFFFF; | |
x |= (x >> 16) & 0x0000FFFF; | |
return x + 1; | |
} | |
b2Math.IsPowerOfTwo = function (x) { | |
if (x === undefined) x = 0; | |
var result = x > 0 && (x & (x - 1)) == 0; | |
return result; | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Common.Math.b2Math.b2Vec2_zero = new b2Vec2(0.0, 0.0); | |
Box2D.Common.Math.b2Math.b2Mat22_identity = b2Mat22.FromVV(new b2Vec2(1.0, 0.0), new b2Vec2(0.0, 1.0)); | |
Box2D.Common.Math.b2Math.b2Transform_identity = new b2Transform(b2Math.b2Vec2_zero, b2Math.b2Mat22_identity); | |
}); | |
b2Sweep.b2Sweep = function () { | |
this.localCenter = new b2Vec2(); | |
this.c0 = new b2Vec2; | |
this.c = new b2Vec2(); | |
}; | |
b2Sweep.prototype.Set = function (other) { | |
this.localCenter.SetV(other.localCenter); | |
this.c0.SetV(other.c0); | |
this.c.SetV(other.c); | |
this.a0 = other.a0; | |
this.a = other.a; | |
this.t0 = other.t0; | |
} | |
b2Sweep.prototype.Copy = function () { | |
var copy = new b2Sweep(); | |
copy.localCenter.SetV(this.localCenter); | |
copy.c0.SetV(this.c0); | |
copy.c.SetV(this.c); | |
copy.a0 = this.a0; | |
copy.a = this.a; | |
copy.t0 = this.t0; | |
return copy; | |
} | |
b2Sweep.prototype.GetTransform = function (xf, alpha) { | |
if (alpha === undefined) alpha = 0; | |
xf.position.x = (1.0 - alpha) * this.c0.x + alpha * this.c.x; | |
xf.position.y = (1.0 - alpha) * this.c0.y + alpha * this.c.y; | |
var angle = (1.0 - alpha) * this.a0 + alpha * this.a; | |
xf.R.Set(angle); | |
var tMat = xf.R; | |
xf.position.x -= (tMat.col1.x * this.localCenter.x + tMat.col2.x * this.localCenter.y); | |
xf.position.y -= (tMat.col1.y * this.localCenter.x + tMat.col2.y * this.localCenter.y); | |
} | |
b2Sweep.prototype.Advance = function (t) { | |
if (t === undefined) t = 0; | |
if (this.t0 < t && 1.0 - this.t0 > Number.MIN_VALUE) { | |
var alpha = (t - this.t0) / (1.0 - this.t0); | |
this.c0.x = (1.0 - alpha) * this.c0.x + alpha * this.c.x; | |
this.c0.y = (1.0 - alpha) * this.c0.y + alpha * this.c.y; | |
this.a0 = (1.0 - alpha) * this.a0 + alpha * this.a; | |
this.t0 = t; | |
} | |
} | |
b2Transform.b2Transform = function () { | |
this.position = new b2Vec2; | |
this.R = new b2Mat22(); | |
}; | |
b2Transform.prototype.b2Transform = function (pos, r) { | |
if (pos === undefined) pos = null; | |
if (r === undefined) r = null; | |
if (pos) { | |
this.position.SetV(pos); | |
this.R.SetM(r); | |
} | |
} | |
b2Transform.prototype.Initialize = function (pos, r) { | |
this.position.SetV(pos); | |
this.R.SetM(r); | |
} | |
b2Transform.prototype.SetIdentity = function () { | |
this.position.SetZero(); | |
this.R.SetIdentity(); | |
} | |
b2Transform.prototype.Set = function (x) { | |
this.position.SetV(x.position); | |
this.R.SetM(x.R); | |
} | |
b2Transform.prototype.GetAngle = function () { | |
return Math.atan2(this.R.col1.y, this.R.col1.x); | |
} | |
b2Vec2.b2Vec2 = function () {}; | |
b2Vec2.prototype.b2Vec2 = function (x_, y_) { | |
if (x_ === undefined) x_ = 0; | |
if (y_ === undefined) y_ = 0; | |
this.x = x_; | |
this.y = y_; | |
} | |
b2Vec2.prototype.SetZero = function () { | |
this.x = 0.0; | |
this.y = 0.0; | |
} | |
b2Vec2.prototype.Set = function (x_, y_) { | |
if (x_ === undefined) x_ = 0; | |
if (y_ === undefined) y_ = 0; | |
this.x = x_; | |
this.y = y_; | |
} | |
b2Vec2.prototype.SetV = function (v) { | |
this.x = v.x; | |
this.y = v.y; | |
} | |
b2Vec2.prototype.GetNegative = function () { | |
return new b2Vec2((-this.x), (-this.y)); | |
} | |
b2Vec2.prototype.NegativeSelf = function () { | |
this.x = (-this.x); | |
this.y = (-this.y); | |
} | |
b2Vec2.Make = function (x_, y_) { | |
if (x_ === undefined) x_ = 0; | |
if (y_ === undefined) y_ = 0; | |
return new b2Vec2(x_, y_); | |
} | |
b2Vec2.prototype.Copy = function () { | |
return new b2Vec2(this.x, this.y); | |
} | |
b2Vec2.prototype.Add = function (v) { | |
this.x += v.x; | |
this.y += v.y; | |
} | |
b2Vec2.prototype.Subtract = function (v) { | |
this.x -= v.x; | |
this.y -= v.y; | |
} | |
b2Vec2.prototype.Multiply = function (a) { | |
if (a === undefined) a = 0; | |
this.x *= a; | |
this.y *= a; | |
} | |
b2Vec2.prototype.MulM = function (A) { | |
var tX = this.x; | |
this.x = A.col1.x * tX + A.col2.x * this.y; | |
this.y = A.col1.y * tX + A.col2.y * this.y; | |
} | |
b2Vec2.prototype.MulTM = function (A) { | |
var tX = b2Math.Dot(this, A.col1); | |
this.y = b2Math.Dot(this, A.col2); | |
this.x = tX; | |
} | |
b2Vec2.prototype.CrossVF = function (s) { | |
if (s === undefined) s = 0; | |
var tX = this.x; | |
this.x = s * this.y; | |
this.y = (-s * tX); | |
} | |
b2Vec2.prototype.CrossFV = function (s) { | |
if (s === undefined) s = 0; | |
var tX = this.x; | |
this.x = (-s * this.y); | |
this.y = s * tX; | |
} | |
b2Vec2.prototype.MinV = function (b) { | |
this.x = this.x < b.x ? this.x : b.x; | |
this.y = this.y < b.y ? this.y : b.y; | |
} | |
b2Vec2.prototype.MaxV = function (b) { | |
this.x = this.x > b.x ? this.x : b.x; | |
this.y = this.y > b.y ? this.y : b.y; | |
} | |
b2Vec2.prototype.Abs = function () { | |
if (this.x < 0) this.x = (-this.x); | |
if (this.y < 0) this.y = (-this.y); | |
} | |
b2Vec2.prototype.Length = function () { | |
return Math.sqrt(this.x * this.x + this.y * this.y); | |
} | |
b2Vec2.prototype.LengthSquared = function () { | |
return (this.x * this.x + this.y * this.y); | |
} | |
b2Vec2.prototype.Normalize = function () { | |
var length = Math.sqrt(this.x * this.x + this.y * this.y); | |
if (length < Number.MIN_VALUE) { | |
return 0.0; | |
} | |
var invLength = 1.0 / length; | |
this.x *= invLength; | |
this.y *= invLength; | |
return length; | |
} | |
b2Vec2.prototype.IsValid = function () { | |
return b2Math.IsValid(this.x) && b2Math.IsValid(this.y); | |
} | |
b2Vec3.b2Vec3 = function () {}; | |
b2Vec3.prototype.b2Vec3 = function (x, y, z) { | |
if (x === undefined) x = 0; | |
if (y === undefined) y = 0; | |
if (z === undefined) z = 0; | |
this.x = x; | |
this.y = y; | |
this.z = z; | |
} | |
b2Vec3.prototype.SetZero = function () { | |
this.x = this.y = this.z = 0.0; | |
} | |
b2Vec3.prototype.Set = function (x, y, z) { | |
if (x === undefined) x = 0; | |
if (y === undefined) y = 0; | |
if (z === undefined) z = 0; | |
this.x = x; | |
this.y = y; | |
this.z = z; | |
} | |
b2Vec3.prototype.SetV = function (v) { | |
this.x = v.x; | |
this.y = v.y; | |
this.z = v.z; | |
} | |
b2Vec3.prototype.GetNegative = function () { | |
return new b2Vec3((-this.x), (-this.y), (-this.z)); | |
} | |
b2Vec3.prototype.NegativeSelf = function () { | |
this.x = (-this.x); | |
this.y = (-this.y); | |
this.z = (-this.z); | |
} | |
b2Vec3.prototype.Copy = function () { | |
return new b2Vec3(this.x, this.y, this.z); | |
} | |
b2Vec3.prototype.Add = function (v) { | |
this.x += v.x; | |
this.y += v.y; | |
this.z += v.z; | |
} | |
b2Vec3.prototype.Subtract = function (v) { | |
this.x -= v.x; | |
this.y -= v.y; | |
this.z -= v.z; | |
} | |
b2Vec3.prototype.Multiply = function (a) { | |
if (a === undefined) a = 0; | |
this.x *= a; | |
this.y *= a; | |
this.z *= a; | |
} | |
})(); | |
(function () { | |
var b2ControllerEdge = Box2D.Dynamics.Controllers.b2ControllerEdge, | |
b2Mat22 = Box2D.Common.Math.b2Mat22, | |
b2Mat33 = Box2D.Common.Math.b2Mat33, | |
b2Math = Box2D.Common.Math.b2Math, | |
b2Sweep = Box2D.Common.Math.b2Sweep, | |
b2Transform = Box2D.Common.Math.b2Transform, | |
b2Vec2 = Box2D.Common.Math.b2Vec2, | |
b2Vec3 = Box2D.Common.Math.b2Vec3, | |
b2Color = Box2D.Common.b2Color, | |
b2internal = Box2D.Common.b2internal, | |
b2Settings = Box2D.Common.b2Settings, | |
b2AABB = Box2D.Collision.b2AABB, | |
b2Bound = Box2D.Collision.b2Bound, | |
b2BoundValues = Box2D.Collision.b2BoundValues, | |
b2Collision = Box2D.Collision.b2Collision, | |
b2ContactID = Box2D.Collision.b2ContactID, | |
b2ContactPoint = Box2D.Collision.b2ContactPoint, | |
b2Distance = Box2D.Collision.b2Distance, | |
b2DistanceInput = Box2D.Collision.b2DistanceInput, | |
b2DistanceOutput = Box2D.Collision.b2DistanceOutput, | |
b2DistanceProxy = Box2D.Collision.b2DistanceProxy, | |
b2DynamicTree = Box2D.Collision.b2DynamicTree, | |
b2DynamicTreeBroadPhase = Box2D.Collision.b2DynamicTreeBroadPhase, | |
b2DynamicTreeNode = Box2D.Collision.b2DynamicTreeNode, | |
b2DynamicTreePair = Box2D.Collision.b2DynamicTreePair, | |
b2Manifold = Box2D.Collision.b2Manifold, | |
b2ManifoldPoint = Box2D.Collision.b2ManifoldPoint, | |
b2Point = Box2D.Collision.b2Point, | |
b2RayCastInput = Box2D.Collision.b2RayCastInput, | |
b2RayCastOutput = Box2D.Collision.b2RayCastOutput, | |
b2Segment = Box2D.Collision.b2Segment, | |
b2SeparationFunction = Box2D.Collision.b2SeparationFunction, | |
b2Simplex = Box2D.Collision.b2Simplex, | |
b2SimplexCache = Box2D.Collision.b2SimplexCache, | |
b2SimplexVertex = Box2D.Collision.b2SimplexVertex, | |
b2TimeOfImpact = Box2D.Collision.b2TimeOfImpact, | |
b2TOIInput = Box2D.Collision.b2TOIInput, | |
b2WorldManifold = Box2D.Collision.b2WorldManifold, | |
ClipVertex = Box2D.Collision.ClipVertex, | |
Features = Box2D.Collision.Features, | |
IBroadPhase = Box2D.Collision.IBroadPhase, | |
b2CircleShape = Box2D.Collision.Shapes.b2CircleShape, | |
b2EdgeChainDef = Box2D.Collision.Shapes.b2EdgeChainDef, | |
b2EdgeShape = Box2D.Collision.Shapes.b2EdgeShape, | |
b2MassData = Box2D.Collision.Shapes.b2MassData, | |
b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape, | |
b2Shape = Box2D.Collision.Shapes.b2Shape, | |
b2Body = Box2D.Dynamics.b2Body, | |
b2BodyDef = Box2D.Dynamics.b2BodyDef, | |
b2ContactFilter = Box2D.Dynamics.b2ContactFilter, | |
b2ContactImpulse = Box2D.Dynamics.b2ContactImpulse, | |
b2ContactListener = Box2D.Dynamics.b2ContactListener, | |
b2ContactManager = Box2D.Dynamics.b2ContactManager, | |
b2DebugDraw = Box2D.Dynamics.b2DebugDraw, | |
b2DestructionListener = Box2D.Dynamics.b2DestructionListener, | |
b2FilterData = Box2D.Dynamics.b2FilterData, | |
b2Fixture = Box2D.Dynamics.b2Fixture, | |
b2FixtureDef = Box2D.Dynamics.b2FixtureDef, | |
b2Island = Box2D.Dynamics.b2Island, | |
b2TimeStep = Box2D.Dynamics.b2TimeStep, | |
b2World = Box2D.Dynamics.b2World, | |
b2CircleContact = Box2D.Dynamics.Contacts.b2CircleContact, | |
b2Contact = Box2D.Dynamics.Contacts.b2Contact, | |
b2ContactConstraint = Box2D.Dynamics.Contacts.b2ContactConstraint, | |
b2ContactConstraintPoint = Box2D.Dynamics.Contacts.b2ContactConstraintPoint, | |
b2ContactEdge = Box2D.Dynamics.Contacts.b2ContactEdge, | |
b2ContactFactory = Box2D.Dynamics.Contacts.b2ContactFactory, | |
b2ContactRegister = Box2D.Dynamics.Contacts.b2ContactRegister, | |
b2ContactResult = Box2D.Dynamics.Contacts.b2ContactResult, | |
b2ContactSolver = Box2D.Dynamics.Contacts.b2ContactSolver, | |
b2EdgeAndCircleContact = Box2D.Dynamics.Contacts.b2EdgeAndCircleContact, | |
b2NullContact = Box2D.Dynamics.Contacts.b2NullContact, | |
b2PolyAndCircleContact = Box2D.Dynamics.Contacts.b2PolyAndCircleContact, | |
b2PolyAndEdgeContact = Box2D.Dynamics.Contacts.b2PolyAndEdgeContact, | |
b2PolygonContact = Box2D.Dynamics.Contacts.b2PolygonContact, | |
b2PositionSolverManifold = Box2D.Dynamics.Contacts.b2PositionSolverManifold, | |
b2Controller = Box2D.Dynamics.Controllers.b2Controller, | |
b2DistanceJoint = Box2D.Dynamics.Joints.b2DistanceJoint, | |
b2DistanceJointDef = Box2D.Dynamics.Joints.b2DistanceJointDef, | |
b2FrictionJoint = Box2D.Dynamics.Joints.b2FrictionJoint, | |
b2FrictionJointDef = Box2D.Dynamics.Joints.b2FrictionJointDef, | |
b2GearJoint = Box2D.Dynamics.Joints.b2GearJoint, | |
b2GearJointDef = Box2D.Dynamics.Joints.b2GearJointDef, | |
b2Jacobian = Box2D.Dynamics.Joints.b2Jacobian, | |
b2Joint = Box2D.Dynamics.Joints.b2Joint, | |
b2JointDef = Box2D.Dynamics.Joints.b2JointDef, | |
b2JointEdge = Box2D.Dynamics.Joints.b2JointEdge, | |
b2LineJoint = Box2D.Dynamics.Joints.b2LineJoint, | |
b2LineJointDef = Box2D.Dynamics.Joints.b2LineJointDef, | |
b2MouseJoint = Box2D.Dynamics.Joints.b2MouseJoint, | |
b2MouseJointDef = Box2D.Dynamics.Joints.b2MouseJointDef, | |
b2PrismaticJoint = Box2D.Dynamics.Joints.b2PrismaticJoint, | |
b2PrismaticJointDef = Box2D.Dynamics.Joints.b2PrismaticJointDef, | |
b2PulleyJoint = Box2D.Dynamics.Joints.b2PulleyJoint, | |
b2PulleyJointDef = Box2D.Dynamics.Joints.b2PulleyJointDef, | |
b2RevoluteJoint = Box2D.Dynamics.Joints.b2RevoluteJoint, | |
b2RevoluteJointDef = Box2D.Dynamics.Joints.b2RevoluteJointDef, | |
b2WeldJoint = Box2D.Dynamics.Joints.b2WeldJoint, | |
b2WeldJointDef = Box2D.Dynamics.Joints.b2WeldJointDef; | |
b2Body.b2Body = function () { | |
this.m_xf = new b2Transform(); | |
this.m_sweep = new b2Sweep(); | |
this.m_linearVelocity = new b2Vec2(); | |
this.m_force = new b2Vec2(); | |
}; | |
b2Body.prototype.connectEdges = function (s1, s2, angle1) { | |
if (angle1 === undefined) angle1 = 0; | |
var angle2 = Math.atan2(s2.GetDirectionVector().y, s2.GetDirectionVector().x); | |
var coreOffset = Math.tan((angle2 - angle1) * 0.5); | |
var core = b2Math.MulFV(coreOffset, s2.GetDirectionVector()); | |
core = b2Math.SubtractVV(core, s2.GetNormalVector()); | |
core = b2Math.MulFV(b2Settings.b2_toiSlop, core); | |
core = b2Math.AddVV(core, s2.GetVertex1()); | |
var cornerDir = b2Math.AddVV(s1.GetDirectionVector(), s2.GetDirectionVector()); | |
cornerDir.Normalize(); | |
var convex = b2Math.Dot(s1.GetDirectionVector(), s2.GetNormalVector()) > 0.0; | |
s1.SetNextEdge(s2, core, cornerDir, convex); | |
s2.SetPrevEdge(s1, core, cornerDir, convex); | |
return angle2; | |
} | |
b2Body.prototype.CreateFixture = function (def) { | |
if (this.m_world.IsLocked() == true) { | |
return null; | |
} | |
var fixture = new b2Fixture(); | |
fixture.Create(this, this.m_xf, def); | |
if (this.m_flags & b2Body.e_activeFlag) { | |
var broadPhase = this.m_world.m_contactManager.m_broadPhase; | |
fixture.CreateProxy(broadPhase, this.m_xf); | |
} | |
fixture.m_next = this.m_fixtureList; | |
this.m_fixtureList = fixture; | |
++this.m_fixtureCount; | |
fixture.m_body = this; | |
if (fixture.m_density > 0.0) { | |
this.ResetMassData(); | |
} | |
this.m_world.m_flags |= b2World.e_newFixture; | |
return fixture; | |
} | |
b2Body.prototype.CreateFixture2 = function (shape, density) { | |
if (density === undefined) density = 0.0; | |
var def = new b2FixtureDef(); | |
def.shape = shape; | |
def.density = density; | |
return this.CreateFixture(def); | |
} | |
b2Body.prototype.DestroyFixture = function (fixture) { | |
if (this.m_world.IsLocked() == true) { | |
return; | |
} | |
var node = this.m_fixtureList; | |
var ppF = null; | |
var found = false; | |
while (node != null) { | |
if (node == fixture) { | |
if (ppF) ppF.m_next = fixture.m_next; | |
else this.m_fixtureList = fixture.m_next; | |
found = true; | |
break; | |
} | |
ppF = node; | |
node = node.m_next; | |
} | |
var edge = this.m_contactList; | |
while (edge) { | |
var c = edge.contact; | |
edge = edge.next; | |
var fixtureA = c.GetFixtureA(); | |
var fixtureB = c.GetFixtureB(); | |
if (fixture == fixtureA || fixture == fixtureB) { | |
this.m_world.m_contactManager.Destroy(c); | |
} | |
} | |
if (this.m_flags & b2Body.e_activeFlag) { | |
var broadPhase = this.m_world.m_contactManager.m_broadPhase; | |
fixture.DestroyProxy(broadPhase); | |
} | |
else {} | |
fixture.Destroy(); | |
fixture.m_body = null; | |
fixture.m_next = null; | |
--this.m_fixtureCount; | |
this.ResetMassData(); | |
} | |
b2Body.prototype.SetPositionAndAngle = function (position, angle) { | |
if (angle === undefined) angle = 0; | |
var f; | |
if (this.m_world.IsLocked() == true) { | |
return; | |
} | |
this.m_xf.R.Set(angle); | |
this.m_xf.position.SetV(position); | |
var tMat = this.m_xf.R; | |
var tVec = this.m_sweep.localCenter; | |
this.m_sweep.c.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
this.m_sweep.c.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
this.m_sweep.c.x += this.m_xf.position.x; | |
this.m_sweep.c.y += this.m_xf.position.y; | |
this.m_sweep.c0.SetV(this.m_sweep.c); | |
this.m_sweep.a0 = this.m_sweep.a = angle; | |
var broadPhase = this.m_world.m_contactManager.m_broadPhase; | |
for (f = this.m_fixtureList; | |
f; f = f.m_next) { | |
f.Synchronize(broadPhase, this.m_xf, this.m_xf); | |
} | |
this.m_world.m_contactManager.FindNewContacts(); | |
} | |
b2Body.prototype.SetTransform = function (xf) { | |
this.SetPositionAndAngle(xf.position, xf.GetAngle()); | |
} | |
b2Body.prototype.GetTransform = function () { | |
return this.m_xf; | |
} | |
b2Body.prototype.GetPosition = function () { | |
return this.m_xf.position; | |
} | |
b2Body.prototype.SetPosition = function (position) { | |
this.SetPositionAndAngle(position, this.GetAngle()); | |
} | |
b2Body.prototype.GetAngle = function () { | |
return this.m_sweep.a; | |
} | |
b2Body.prototype.SetAngle = function (angle) { | |
if (angle === undefined) angle = 0; | |
this.SetPositionAndAngle(this.GetPosition(), angle); | |
} | |
b2Body.prototype.GetWorldCenter = function () { | |
return this.m_sweep.c; | |
} | |
b2Body.prototype.GetLocalCenter = function () { | |
return this.m_sweep.localCenter; | |
} | |
b2Body.prototype.SetLinearVelocity = function (v) { | |
if (this.m_type == b2Body.b2_staticBody) { | |
return; | |
} | |
this.m_linearVelocity.SetV(v); | |
} | |
b2Body.prototype.GetLinearVelocity = function () { | |
return this.m_linearVelocity; | |
} | |
b2Body.prototype.SetAngularVelocity = function (omega) { | |
if (omega === undefined) omega = 0; | |
if (this.m_type == b2Body.b2_staticBody) { | |
return; | |
} | |
this.m_angularVelocity = omega; | |
} | |
b2Body.prototype.GetAngularVelocity = function () { | |
return this.m_angularVelocity; | |
} | |
b2Body.prototype.GetDefinition = function () { | |
var bd = new b2BodyDef(); | |
bd.type = this.GetType(); | |
bd.allowSleep = (this.m_flags & b2Body.e_allowSleepFlag) == b2Body.e_allowSleepFlag; | |
bd.angle = this.GetAngle(); | |
bd.angularDamping = this.m_angularDamping; | |
bd.angularVelocity = this.m_angularVelocity; | |
bd.fixedRotation = (this.m_flags & b2Body.e_fixedRotationFlag) == b2Body.e_fixedRotationFlag; | |
bd.bullet = (this.m_flags & b2Body.e_bulletFlag) == b2Body.e_bulletFlag; | |
bd.awake = (this.m_flags & b2Body.e_awakeFlag) == b2Body.e_awakeFlag; | |
bd.linearDamping = this.m_linearDamping; | |
bd.linearVelocity.SetV(this.GetLinearVelocity()); | |
bd.position = this.GetPosition(); | |
bd.userData = this.GetUserData(); | |
return bd; | |
} | |
b2Body.prototype.ApplyForce = function (force, point) { | |
if (this.m_type != b2Body.b2_dynamicBody) { | |
return; | |
} | |
if (this.IsAwake() == false) { | |
this.SetAwake(true); | |
} | |
this.m_force.x += force.x; | |
this.m_force.y += force.y; | |
this.m_torque += ((point.x - this.m_sweep.c.x) * force.y - (point.y - this.m_sweep.c.y) * force.x); | |
} | |
b2Body.prototype.ApplyTorque = function (torque) { | |
if (torque === undefined) torque = 0; | |
if (this.m_type != b2Body.b2_dynamicBody) { | |
return; | |
} | |
if (this.IsAwake() == false) { | |
this.SetAwake(true); | |
} | |
this.m_torque += torque; | |
} | |
b2Body.prototype.ApplyImpulse = function (impulse, point) { | |
if (this.m_type != b2Body.b2_dynamicBody) { | |
return; | |
} | |
if (this.IsAwake() == false) { | |
this.SetAwake(true); | |
} | |
this.m_linearVelocity.x += this.m_invMass * impulse.x; | |
this.m_linearVelocity.y += this.m_invMass * impulse.y; | |
this.m_angularVelocity += this.m_invI * ((point.x - this.m_sweep.c.x) * impulse.y - (point.y - this.m_sweep.c.y) * impulse.x); | |
} | |
b2Body.prototype.Split = function (callback) { | |
var linearVelocity = this.GetLinearVelocity().Copy(); | |
var angularVelocity = this.GetAngularVelocity(); | |
var center = this.GetWorldCenter(); | |
var body1 = this; | |
var body2 = this.m_world.CreateBody(this.GetDefinition()); | |
var prev; | |
for (var f = body1.m_fixtureList; f;) { | |
if (callback(f)) { | |
var next = f.m_next; | |
if (prev) { | |
prev.m_next = next; | |
} | |
else { | |
body1.m_fixtureList = next; | |
} | |
body1.m_fixtureCount--; | |
f.m_next = body2.m_fixtureList; | |
body2.m_fixtureList = f; | |
body2.m_fixtureCount++; | |
f.m_body = body2; | |
f = next; | |
} | |
else { | |
prev = f; | |
f = f.m_next; | |
} | |
} | |
body1.ResetMassData(); | |
body2.ResetMassData(); | |
var center1 = body1.GetWorldCenter(); | |
var center2 = body2.GetWorldCenter(); | |
var velocity1 = b2Math.AddVV(linearVelocity, b2Math.CrossFV(angularVelocity, b2Math.SubtractVV(center1, center))); | |
var velocity2 = b2Math.AddVV(linearVelocity, b2Math.CrossFV(angularVelocity, b2Math.SubtractVV(center2, center))); | |
body1.SetLinearVelocity(velocity1); | |
body2.SetLinearVelocity(velocity2); | |
body1.SetAngularVelocity(angularVelocity); | |
body2.SetAngularVelocity(angularVelocity); | |
body1.SynchronizeFixtures(); | |
body2.SynchronizeFixtures(); | |
return body2; | |
} | |
b2Body.prototype.Merge = function (other) { | |
var f; | |
for (f = other.m_fixtureList; | |
f;) { | |
var next = f.m_next; | |
other.m_fixtureCount--; | |
f.m_next = this.m_fixtureList; | |
this.m_fixtureList = f; | |
this.m_fixtureCount++; | |
f.m_body = body2; | |
f = next; | |
} | |
body1.m_fixtureCount = 0; | |
var body1 = this; | |
var body2 = other; | |
var center1 = body1.GetWorldCenter(); | |
var center2 = body2.GetWorldCenter(); | |
var velocity1 = body1.GetLinearVelocity().Copy(); | |
var velocity2 = body2.GetLinearVelocity().Copy(); | |
var angular1 = body1.GetAngularVelocity(); | |
var angular = body2.GetAngularVelocity(); | |
body1.ResetMassData(); | |
this.SynchronizeFixtures(); | |
} | |
b2Body.prototype.GetMass = function () { | |
return this.m_mass; | |
} | |
b2Body.prototype.GetInertia = function () { | |
return this.m_I; | |
} | |
b2Body.prototype.GetMassData = function (data) { | |
data.mass = this.m_mass; | |
data.I = this.m_I; | |
data.center.SetV(this.m_sweep.localCenter); | |
} | |
b2Body.prototype.SetMassData = function (massData) { | |
b2Settings.b2Assert(this.m_world.IsLocked() == false); | |
if (this.m_world.IsLocked() == true) { | |
return; | |
} | |
if (this.m_type != b2Body.b2_dynamicBody) { | |
return; | |
} | |
this.m_invMass = 0.0; | |
this.m_I = 0.0; | |
this.m_invI = 0.0; | |
this.m_mass = massData.mass; | |
if (this.m_mass <= 0.0) { | |
this.m_mass = 1.0; | |
} | |
this.m_invMass = 1.0 / this.m_mass; | |
if (massData.I > 0.0 && (this.m_flags & b2Body.e_fixedRotationFlag) == 0) { | |
this.m_I = massData.I - this.m_mass * (massData.center.x * massData.center.x + massData.center.y * massData.center.y); | |
this.m_invI = 1.0 / this.m_I; | |
} | |
var oldCenter = this.m_sweep.c.Copy(); | |
this.m_sweep.localCenter.SetV(massData.center); | |
this.m_sweep.c0.SetV(b2Math.MulX(this.m_xf, this.m_sweep.localCenter)); | |
this.m_sweep.c.SetV(this.m_sweep.c0); | |
this.m_linearVelocity.x += this.m_angularVelocity * (-(this.m_sweep.c.y - oldCenter.y)); | |
this.m_linearVelocity.y += this.m_angularVelocity * (+(this.m_sweep.c.x - oldCenter.x)); | |
} | |
b2Body.prototype.ResetMassData = function () { | |
this.m_mass = 0.0; | |
this.m_invMass = 0.0; | |
this.m_I = 0.0; | |
this.m_invI = 0.0; | |
this.m_sweep.localCenter.SetZero(); | |
if (this.m_type == b2Body.b2_staticBody || this.m_type == b2Body.b2_kinematicBody) { | |
return; | |
} | |
var center = b2Vec2.Make(0, 0); | |
for (var f = this.m_fixtureList; f; f = f.m_next) { | |
if (f.m_density == 0.0) { | |
continue; | |
} | |
var massData = f.GetMassData(); | |
this.m_mass += massData.mass; | |
center.x += massData.center.x * massData.mass; | |
center.y += massData.center.y * massData.mass; | |
this.m_I += massData.I; | |
} | |
if (this.m_mass > 0.0) { | |
this.m_invMass = 1.0 / this.m_mass; | |
center.x *= this.m_invMass; | |
center.y *= this.m_invMass; | |
} | |
else { | |
this.m_mass = 1.0; | |
this.m_invMass = 1.0; | |
} | |
if (this.m_I > 0.0 && (this.m_flags & b2Body.e_fixedRotationFlag) == 0) { | |
this.m_I -= this.m_mass * (center.x * center.x + center.y * center.y); | |
this.m_I *= this.m_inertiaScale; | |
b2Settings.b2Assert(this.m_I > 0); | |
this.m_invI = 1.0 / this.m_I; | |
} | |
else { | |
this.m_I = 0.0; | |
this.m_invI = 0.0; | |
} | |
var oldCenter = this.m_sweep.c.Copy(); | |
this.m_sweep.localCenter.SetV(center); | |
this.m_sweep.c0.SetV(b2Math.MulX(this.m_xf, this.m_sweep.localCenter)); | |
this.m_sweep.c.SetV(this.m_sweep.c0); | |
this.m_linearVelocity.x += this.m_angularVelocity * (-(this.m_sweep.c.y - oldCenter.y)); | |
this.m_linearVelocity.y += this.m_angularVelocity * (+(this.m_sweep.c.x - oldCenter.x)); | |
} | |
b2Body.prototype.GetWorldPoint = function (localPoint) { | |
var A = this.m_xf.R; | |
var u = new b2Vec2(A.col1.x * localPoint.x + A.col2.x * localPoint.y, A.col1.y * localPoint.x + A.col2.y * localPoint.y); | |
u.x += this.m_xf.position.x; | |
u.y += this.m_xf.position.y; | |
return u; | |
} | |
b2Body.prototype.GetWorldVector = function (localVector) { | |
return b2Math.MulMV(this.m_xf.R, localVector); | |
} | |
b2Body.prototype.GetLocalPoint = function (worldPoint) { | |
return b2Math.MulXT(this.m_xf, worldPoint); | |
} | |
b2Body.prototype.GetLocalVector = function (worldVector) { | |
return b2Math.MulTMV(this.m_xf.R, worldVector); | |
} | |
b2Body.prototype.GetLinearVelocityFromWorldPoint = function (worldPoint) { | |
return new b2Vec2(this.m_linearVelocity.x - this.m_angularVelocity * (worldPoint.y - this.m_sweep.c.y), this.m_linearVelocity.y + this.m_angularVelocity * (worldPoint.x - this.m_sweep.c.x)); | |
} | |
b2Body.prototype.GetLinearVelocityFromLocalPoint = function (localPoint) { | |
var A = this.m_xf.R; | |
var worldPoint = new b2Vec2(A.col1.x * localPoint.x + A.col2.x * localPoint.y, A.col1.y * localPoint.x + A.col2.y * localPoint.y); | |
worldPoint.x += this.m_xf.position.x; | |
worldPoint.y += this.m_xf.position.y; | |
return new b2Vec2(this.m_linearVelocity.x - this.m_angularVelocity * (worldPoint.y - this.m_sweep.c.y), this.m_linearVelocity.y + this.m_angularVelocity * (worldPoint.x - this.m_sweep.c.x)); | |
} | |
b2Body.prototype.GetLinearDamping = function () { | |
return this.m_linearDamping; | |
} | |
b2Body.prototype.SetLinearDamping = function (linearDamping) { | |
if (linearDamping === undefined) linearDamping = 0; | |
this.m_linearDamping = linearDamping; | |
} | |
b2Body.prototype.GetAngularDamping = function () { | |
return this.m_angularDamping; | |
} | |
b2Body.prototype.SetAngularDamping = function (angularDamping) { | |
if (angularDamping === undefined) angularDamping = 0; | |
this.m_angularDamping = angularDamping; | |
} | |
b2Body.prototype.SetType = function (type) { | |
if (type === undefined) type = 0; | |
if (this.m_type == type) { | |
return; | |
} | |
this.m_type = type; | |
this.ResetMassData(); | |
if (this.m_type == b2Body.b2_staticBody) { | |
this.m_linearVelocity.SetZero(); | |
this.m_angularVelocity = 0.0; | |
} | |
this.SetAwake(true); | |
this.m_force.SetZero(); | |
this.m_torque = 0.0; | |
for (var ce = this.m_contactList; ce; ce = ce.next) { | |
ce.contact.FlagForFiltering(); | |
} | |
} | |
b2Body.prototype.GetType = function () { | |
return this.m_type; | |
} | |
b2Body.prototype.SetBullet = function (flag) { | |
if (flag) { | |
this.m_flags |= b2Body.e_bulletFlag; | |
} | |
else { | |
this.m_flags &= ~b2Body.e_bulletFlag; | |
} | |
} | |
b2Body.prototype.IsBullet = function () { | |
return (this.m_flags & b2Body.e_bulletFlag) == b2Body.e_bulletFlag; | |
} | |
b2Body.prototype.SetSleepingAllowed = function (flag) { | |
if (flag) { | |
this.m_flags |= b2Body.e_allowSleepFlag; | |
} | |
else { | |
this.m_flags &= ~b2Body.e_allowSleepFlag; | |
this.SetAwake(true); | |
} | |
} | |
b2Body.prototype.SetAwake = function (flag) { | |
if (flag) { | |
this.m_flags |= b2Body.e_awakeFlag; | |
this.m_sleepTime = 0.0; | |
} | |
else { | |
this.m_flags &= ~b2Body.e_awakeFlag; | |
this.m_sleepTime = 0.0; | |
this.m_linearVelocity.SetZero(); | |
this.m_angularVelocity = 0.0; | |
this.m_force.SetZero(); | |
this.m_torque = 0.0; | |
} | |
} | |
b2Body.prototype.IsAwake = function () { | |
return (this.m_flags & b2Body.e_awakeFlag) == b2Body.e_awakeFlag; | |
} | |
b2Body.prototype.SetFixedRotation = function (fixed) { | |
if (fixed) { | |
this.m_flags |= b2Body.e_fixedRotationFlag; | |
} | |
else { | |
this.m_flags &= ~b2Body.e_fixedRotationFlag; | |
} | |
this.ResetMassData(); | |
} | |
b2Body.prototype.IsFixedRotation = function () { | |
return (this.m_flags & b2Body.e_fixedRotationFlag) == b2Body.e_fixedRotationFlag; | |
} | |
b2Body.prototype.SetActive = function (flag) { | |
if (flag == this.IsActive()) { | |
return; | |
} | |
var broadPhase; | |
var f; | |
if (flag) { | |
this.m_flags |= b2Body.e_activeFlag; | |
broadPhase = this.m_world.m_contactManager.m_broadPhase; | |
for (f = this.m_fixtureList; | |
f; f = f.m_next) { | |
f.CreateProxy(broadPhase, this.m_xf); | |
} | |
} | |
else { | |
this.m_flags &= ~b2Body.e_activeFlag; | |
broadPhase = this.m_world.m_contactManager.m_broadPhase; | |
for (f = this.m_fixtureList; | |
f; f = f.m_next) { | |
f.DestroyProxy(broadPhase); | |
} | |
var ce = this.m_contactList; | |
while (ce) { | |
var ce0 = ce; | |
ce = ce.next; | |
this.m_world.m_contactManager.Destroy(ce0.contact); | |
} | |
this.m_contactList = null; | |
} | |
} | |
b2Body.prototype.IsActive = function () { | |
return (this.m_flags & b2Body.e_activeFlag) == b2Body.e_activeFlag; | |
} | |
b2Body.prototype.IsSleepingAllowed = function () { | |
return (this.m_flags & b2Body.e_allowSleepFlag) == b2Body.e_allowSleepFlag; | |
} | |
b2Body.prototype.GetFixtureList = function () { | |
return this.m_fixtureList; | |
} | |
b2Body.prototype.GetJointList = function () { | |
return this.m_jointList; | |
} | |
b2Body.prototype.GetControllerList = function () { | |
return this.m_controllerList; | |
} | |
b2Body.prototype.GetContactList = function () { | |
return this.m_contactList; | |
} | |
b2Body.prototype.GetNext = function () { | |
return this.m_next; | |
} | |
b2Body.prototype.GetUserData = function () { | |
return this.m_userData; | |
} | |
b2Body.prototype.SetUserData = function (data) { | |
this.m_userData = data; | |
} | |
b2Body.prototype.GetWorld = function () { | |
return this.m_world; | |
} | |
b2Body.prototype.b2Body = function (bd, world) { | |
this.m_flags = 0; | |
if (bd.bullet) { | |
this.m_flags |= b2Body.e_bulletFlag; | |
} | |
if (bd.fixedRotation) { | |
this.m_flags |= b2Body.e_fixedRotationFlag; | |
} | |
if (bd.allowSleep) { | |
this.m_flags |= b2Body.e_allowSleepFlag; | |
} | |
if (bd.awake) { | |
this.m_flags |= b2Body.e_awakeFlag; | |
} | |
if (bd.active) { | |
this.m_flags |= b2Body.e_activeFlag; | |
} | |
this.m_world = world; | |
this.m_xf.position.SetV(bd.position); | |
this.m_xf.R.Set(bd.angle); | |
this.m_sweep.localCenter.SetZero(); | |
this.m_sweep.t0 = 1.0; | |
this.m_sweep.a0 = this.m_sweep.a = bd.angle; | |
var tMat = this.m_xf.R; | |
var tVec = this.m_sweep.localCenter; | |
this.m_sweep.c.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
this.m_sweep.c.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
this.m_sweep.c.x += this.m_xf.position.x; | |
this.m_sweep.c.y += this.m_xf.position.y; | |
this.m_sweep.c0.SetV(this.m_sweep.c); | |
this.m_jointList = null; | |
this.m_controllerList = null; | |
this.m_contactList = null; | |
this.m_controllerCount = 0; | |
this.m_prev = null; | |
this.m_next = null; | |
this.m_linearVelocity.SetV(bd.linearVelocity); | |
this.m_angularVelocity = bd.angularVelocity; | |
this.m_linearDamping = bd.linearDamping; | |
this.m_angularDamping = bd.angularDamping; | |
this.m_force.Set(0.0, 0.0); | |
this.m_torque = 0.0; | |
this.m_sleepTime = 0.0; | |
this.m_type = bd.type; | |
if (this.m_type == b2Body.b2_dynamicBody) { | |
this.m_mass = 1.0; | |
this.m_invMass = 1.0; | |
} | |
else { | |
this.m_mass = 0.0; | |
this.m_invMass = 0.0; | |
} | |
this.m_I = 0.0; | |
this.m_invI = 0.0; | |
this.m_inertiaScale = bd.inertiaScale; | |
this.m_userData = bd.userData; | |
this.m_fixtureList = null; | |
this.m_fixtureCount = 0; | |
} | |
b2Body.prototype.SynchronizeFixtures = function () { | |
var xf1 = b2Body.s_xf1; | |
xf1.R.Set(this.m_sweep.a0); | |
var tMat = xf1.R; | |
var tVec = this.m_sweep.localCenter; | |
xf1.position.x = this.m_sweep.c0.x - (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
xf1.position.y = this.m_sweep.c0.y - (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
var f; | |
var broadPhase = this.m_world.m_contactManager.m_broadPhase; | |
for (f = this.m_fixtureList; | |
f; f = f.m_next) { | |
f.Synchronize(broadPhase, xf1, this.m_xf); | |
} | |
} | |
b2Body.prototype.SynchronizeTransform = function () { | |
this.m_xf.R.Set(this.m_sweep.a); | |
var tMat = this.m_xf.R; | |
var tVec = this.m_sweep.localCenter; | |
this.m_xf.position.x = this.m_sweep.c.x - (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
this.m_xf.position.y = this.m_sweep.c.y - (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
} | |
b2Body.prototype.ShouldCollide = function (other) { | |
if (this.m_type != b2Body.b2_dynamicBody && other.m_type != b2Body.b2_dynamicBody) { | |
return false; | |
} | |
for (var jn = this.m_jointList; jn; jn = jn.next) { | |
if (jn.other == other) if (jn.joint.m_collideConnected == false) { | |
return false; | |
} | |
} | |
return true; | |
} | |
b2Body.prototype.Advance = function (t) { | |
if (t === undefined) t = 0; | |
this.m_sweep.Advance(t); | |
this.m_sweep.c.SetV(this.m_sweep.c0); | |
this.m_sweep.a = this.m_sweep.a0; | |
this.SynchronizeTransform(); | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Dynamics.b2Body.s_xf1 = new b2Transform(); | |
Box2D.Dynamics.b2Body.e_islandFlag = 0x0001; | |
Box2D.Dynamics.b2Body.e_awakeFlag = 0x0002; | |
Box2D.Dynamics.b2Body.e_allowSleepFlag = 0x0004; | |
Box2D.Dynamics.b2Body.e_bulletFlag = 0x0008; | |
Box2D.Dynamics.b2Body.e_fixedRotationFlag = 0x0010; | |
Box2D.Dynamics.b2Body.e_activeFlag = 0x0020; | |
Box2D.Dynamics.b2Body.b2_staticBody = 0; | |
Box2D.Dynamics.b2Body.b2_kinematicBody = 1; | |
Box2D.Dynamics.b2Body.b2_dynamicBody = 2; | |
}); | |
b2BodyDef.b2BodyDef = function () { | |
this.position = new b2Vec2(); | |
this.linearVelocity = new b2Vec2(); | |
}; | |
b2BodyDef.prototype.b2BodyDef = function () { | |
this.userData = null; | |
this.position.Set(0.0, 0.0); | |
this.angle = 0.0; | |
this.linearVelocity.Set(0, 0); | |
this.angularVelocity = 0.0; | |
this.linearDamping = 0.0; | |
this.angularDamping = 0.0; | |
this.allowSleep = true; | |
this.awake = true; | |
this.fixedRotation = false; | |
this.bullet = false; | |
this.type = b2Body.b2_staticBody; | |
this.active = true; | |
this.inertiaScale = 1.0; | |
} | |
b2ContactFilter.b2ContactFilter = function () {}; | |
b2ContactFilter.prototype.ShouldCollide = function (fixtureA, fixtureB) { | |
var filter1 = fixtureA.GetFilterData(); | |
var filter2 = fixtureB.GetFilterData(); | |
if (filter1.groupIndex == filter2.groupIndex && filter1.groupIndex != 0) { | |
return filter1.groupIndex > 0; | |
} | |
var collide = (filter1.maskBits & filter2.categoryBits) != 0 && (filter1.categoryBits & filter2.maskBits) != 0; | |
return collide; | |
} | |
b2ContactFilter.prototype.RayCollide = function (userData, fixture) { | |
if (!userData) return true; | |
return this.ShouldCollide((userData instanceof b2Fixture ? userData : null), fixture); | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Dynamics.b2ContactFilter.b2_defaultFilter = new b2ContactFilter(); | |
}); | |
b2ContactImpulse.b2ContactImpulse = function () { | |
this.normalImpulses = new Vector_a2j_Number(b2Settings.b2_maxManifoldPoints); | |
this.tangentImpulses = new Vector_a2j_Number(b2Settings.b2_maxManifoldPoints); | |
}; | |
b2ContactListener.b2ContactListener = function () {}; | |
b2ContactListener.prototype.BeginContact = function (contact) {} | |
b2ContactListener.prototype.EndContact = function (contact) {} | |
b2ContactListener.prototype.PreSolve = function (contact, oldManifold) {} | |
b2ContactListener.prototype.PostSolve = function (contact, impulse) {} | |
Box2D.postDefs.push(function () { | |
Box2D.Dynamics.b2ContactListener.b2_defaultListener = new b2ContactListener(); | |
}); | |
b2ContactManager.b2ContactManager = function () {}; | |
b2ContactManager.prototype.b2ContactManager = function () { | |
this.m_world = null; | |
this.m_contactCount = 0; | |
this.m_contactFilter = b2ContactFilter.b2_defaultFilter; | |
this.m_contactListener = b2ContactListener.b2_defaultListener; | |
this.m_contactFactory = new b2ContactFactory(this.m_allocator); | |
this.m_broadPhase = new b2DynamicTreeBroadPhase(); | |
} | |
b2ContactManager.prototype.AddPair = function (proxyUserDataA, proxyUserDataB) { | |
var fixtureA = (proxyUserDataA instanceof b2Fixture ? proxyUserDataA : null); | |
var fixtureB = (proxyUserDataB instanceof b2Fixture ? proxyUserDataB : null); | |
var bodyA = fixtureA.GetBody(); | |
var bodyB = fixtureB.GetBody(); | |
if (bodyA == bodyB) return; | |
var edge = bodyB.GetContactList(); | |
while (edge) { | |
if (edge.other == bodyA) { | |
var fA = edge.contact.GetFixtureA(); | |
var fB = edge.contact.GetFixtureB(); | |
if (fA == fixtureA && fB == fixtureB) return; | |
if (fA == fixtureB && fB == fixtureA) return; | |
} | |
edge = edge.next; | |
} | |
if (bodyB.ShouldCollide(bodyA) == false) { | |
return; | |
} | |
if (this.m_contactFilter.ShouldCollide(fixtureA, fixtureB) == false) { | |
return; | |
} | |
var c = this.m_contactFactory.Create(fixtureA, fixtureB); | |
fixtureA = c.GetFixtureA(); | |
fixtureB = c.GetFixtureB(); | |
bodyA = fixtureA.m_body; | |
bodyB = fixtureB.m_body; | |
c.m_prev = null; | |
c.m_next = this.m_world.m_contactList; | |
if (this.m_world.m_contactList != null) { | |
this.m_world.m_contactList.m_prev = c; | |
} | |
this.m_world.m_contactList = c; | |
c.m_nodeA.contact = c; | |
c.m_nodeA.other = bodyB; | |
c.m_nodeA.prev = null; | |
c.m_nodeA.next = bodyA.m_contactList; | |
if (bodyA.m_contactList != null) { | |
bodyA.m_contactList.prev = c.m_nodeA; | |
} | |
bodyA.m_contactList = c.m_nodeA; | |
c.m_nodeB.contact = c; | |
c.m_nodeB.other = bodyA; | |
c.m_nodeB.prev = null; | |
c.m_nodeB.next = bodyB.m_contactList; | |
if (bodyB.m_contactList != null) { | |
bodyB.m_contactList.prev = c.m_nodeB; | |
} | |
bodyB.m_contactList = c.m_nodeB; | |
++this.m_world.m_contactCount; | |
return; | |
} | |
b2ContactManager.prototype.FindNewContacts = function () { | |
this.m_broadPhase.UpdatePairs(Box2D.generateCallback(this, this.AddPair)); | |
} | |
b2ContactManager.prototype.Destroy = function (c) { | |
var fixtureA = c.GetFixtureA(); | |
var fixtureB = c.GetFixtureB(); | |
var bodyA = fixtureA.GetBody(); | |
var bodyB = fixtureB.GetBody(); | |
if (c.IsTouching()) { | |
this.m_contactListener.EndContact(c); | |
} | |
if (c.m_prev) { | |
c.m_prev.m_next = c.m_next; | |
} | |
if (c.m_next) { | |
c.m_next.m_prev = c.m_prev; | |
} | |
if (c == this.m_world.m_contactList) { | |
this.m_world.m_contactList = c.m_next; | |
} | |
if (c.m_nodeA.prev) { | |
c.m_nodeA.prev.next = c.m_nodeA.next; | |
} | |
if (c.m_nodeA.next) { | |
c.m_nodeA.next.prev = c.m_nodeA.prev; | |
} | |
if (c.m_nodeA == bodyA.m_contactList) { | |
bodyA.m_contactList = c.m_nodeA.next; | |
} | |
if (c.m_nodeB.prev) { | |
c.m_nodeB.prev.next = c.m_nodeB.next; | |
} | |
if (c.m_nodeB.next) { | |
c.m_nodeB.next.prev = c.m_nodeB.prev; | |
} | |
if (c.m_nodeB == bodyB.m_contactList) { | |
bodyB.m_contactList = c.m_nodeB.next; | |
} | |
this.m_contactFactory.Destroy(c); | |
--this.m_contactCount; | |
} | |
b2ContactManager.prototype.Collide = function () { | |
var c = this.m_world.m_contactList; | |
while (c) { | |
var fixtureA = c.GetFixtureA(); | |
var fixtureB = c.GetFixtureB(); | |
var bodyA = fixtureA.GetBody(); | |
var bodyB = fixtureB.GetBody(); | |
if (bodyA.IsAwake() == false && bodyB.IsAwake() == false) { | |
c = c.GetNext(); | |
continue; | |
} | |
if (c.m_flags & b2Contact.e_filterFlag) { | |
if (bodyB.ShouldCollide(bodyA) == false) { | |
var cNuke = c; | |
c = cNuke.GetNext(); | |
this.Destroy(cNuke); | |
continue; | |
} | |
if (this.m_contactFilter.ShouldCollide(fixtureA, fixtureB) == false) { | |
cNuke = c; | |
c = cNuke.GetNext(); | |
this.Destroy(cNuke); | |
continue; | |
} | |
c.m_flags &= ~b2Contact.e_filterFlag; | |
} | |
var proxyA = fixtureA.m_proxy; | |
var proxyB = fixtureB.m_proxy; | |
var overlap = this.m_broadPhase.TestOverlap(proxyA, proxyB); | |
if (overlap == false) { | |
cNuke = c; | |
c = cNuke.GetNext(); | |
this.Destroy(cNuke); | |
continue; | |
} | |
c.Update(this.m_contactListener); | |
c = c.GetNext(); | |
} | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Dynamics.b2ContactManager.s_evalCP = new b2ContactPoint(); | |
}); | |
b2DebugDraw.b2DebugDraw = function () {}; | |
b2DebugDraw.prototype.b2DebugDraw = function () {} | |
b2DebugDraw.prototype.SetFlags = function (flags) { | |
if (flags === undefined) flags = 0; | |
} | |
b2DebugDraw.prototype.GetFlags = function () {} | |
b2DebugDraw.prototype.AppendFlags = function (flags) { | |
if (flags === undefined) flags = 0; | |
} | |
b2DebugDraw.prototype.ClearFlags = function (flags) { | |
if (flags === undefined) flags = 0; | |
} | |
b2DebugDraw.prototype.SetSprite = function (sprite) {} | |
b2DebugDraw.prototype.GetSprite = function () {} | |
b2DebugDraw.prototype.SetDrawScale = function (drawScale) { | |
if (drawScale === undefined) drawScale = 0; | |
} | |
b2DebugDraw.prototype.GetDrawScale = function () {} | |
b2DebugDraw.prototype.SetLineThickness = function (lineThickness) { | |
if (lineThickness === undefined) lineThickness = 0; | |
} | |
b2DebugDraw.prototype.GetLineThickness = function () {} | |
b2DebugDraw.prototype.SetAlpha = function (alpha) { | |
if (alpha === undefined) alpha = 0; | |
} | |
b2DebugDraw.prototype.GetAlpha = function () {} | |
b2DebugDraw.prototype.SetFillAlpha = function (alpha) { | |
if (alpha === undefined) alpha = 0; | |
} | |
b2DebugDraw.prototype.GetFillAlpha = function () {} | |
b2DebugDraw.prototype.SetXFormScale = function (xformScale) { | |
if (xformScale === undefined) xformScale = 0; | |
} | |
b2DebugDraw.prototype.GetXFormScale = function () {} | |
b2DebugDraw.prototype.DrawPolygon = function (vertices, vertexCount, color) { | |
if (vertexCount === undefined) vertexCount = 0; | |
} | |
b2DebugDraw.prototype.DrawSolidPolygon = function (vertices, vertexCount, color) { | |
if (vertexCount === undefined) vertexCount = 0; | |
} | |
b2DebugDraw.prototype.DrawCircle = function (center, radius, color) { | |
if (radius === undefined) radius = 0; | |
} | |
b2DebugDraw.prototype.DrawSolidCircle = function (center, radius, axis, color) { | |
if (radius === undefined) radius = 0; | |
} | |
b2DebugDraw.prototype.DrawSegment = function (p1, p2, color) {} | |
b2DebugDraw.prototype.DrawTransform = function (xf) {} | |
Box2D.postDefs.push(function () { | |
Box2D.Dynamics.b2DebugDraw.e_shapeBit = 0x0001; | |
Box2D.Dynamics.b2DebugDraw.e_jointBit = 0x0002; | |
Box2D.Dynamics.b2DebugDraw.e_aabbBit = 0x0004; | |
Box2D.Dynamics.b2DebugDraw.e_pairBit = 0x0008; | |
Box2D.Dynamics.b2DebugDraw.e_centerOfMassBit = 0x0010; | |
Box2D.Dynamics.b2DebugDraw.e_controllerBit = 0x0020; | |
}); | |
b2DestructionListener.b2DestructionListener = function () {}; | |
b2DestructionListener.prototype.SayGoodbyeJoint = function (joint) {} | |
b2DestructionListener.prototype.SayGoodbyeFixture = function (fixture) {} | |
b2FilterData.b2FilterData = function () { | |
this.categoryBits = 0x0001; | |
this.maskBits = 0xFFFF; | |
this.groupIndex = 0; | |
}; | |
b2FilterData.prototype.Copy = function () { | |
var copy = new b2FilterData(); | |
copy.categoryBits = this.categoryBits; | |
copy.maskBits = this.maskBits; | |
copy.groupIndex = this.groupIndex; | |
return copy; | |
} | |
b2Fixture.b2Fixture = function () { | |
this.m_filter = new b2FilterData(); | |
}; | |
b2Fixture.prototype.GetType = function () { | |
return this.m_shape.GetType(); | |
} | |
b2Fixture.prototype.GetShape = function () { | |
return this.m_shape; | |
} | |
b2Fixture.prototype.SetSensor = function (sensor) { | |
if (this.m_isSensor == sensor) return; | |
this.m_isSensor = sensor; | |
if (this.m_body == null) return; | |
var edge = this.m_body.GetContactList(); | |
while (edge) { | |
var contact = edge.contact; | |
var fixtureA = contact.GetFixtureA(); | |
var fixtureB = contact.GetFixtureB(); | |
if (fixtureA == this || fixtureB == this) contact.SetSensor(fixtureA.IsSensor() || fixtureB.IsSensor()); | |
edge = edge.next; | |
} | |
} | |
b2Fixture.prototype.IsSensor = function () { | |
return this.m_isSensor; | |
} | |
b2Fixture.prototype.SetFilterData = function (filter) { | |
this.m_filter = filter.Copy(); | |
if (this.m_body) return; | |
var edge = this.m_body.GetContactList(); | |
while (edge) { | |
var contact = edge.contact; | |
var fixtureA = contact.GetFixtureA(); | |
var fixtureB = contact.GetFixtureB(); | |
if (fixtureA == this || fixtureB == this) contact.FlagForFiltering(); | |
edge = edge.next; | |
} | |
} | |
b2Fixture.prototype.GetFilterData = function () { | |
return this.m_filter.Copy(); | |
} | |
b2Fixture.prototype.GetBody = function () { | |
return this.m_body; | |
} | |
b2Fixture.prototype.GetNext = function () { | |
return this.m_next; | |
} | |
b2Fixture.prototype.GetUserData = function () { | |
return this.m_userData; | |
} | |
b2Fixture.prototype.SetUserData = function (data) { | |
this.m_userData = data; | |
} | |
b2Fixture.prototype.TestPoint = function (p) { | |
return this.m_shape.TestPoint(this.m_body.GetTransform(), p); | |
} | |
b2Fixture.prototype.RayCast = function (output, input) { | |
return this.m_shape.RayCast(output, input, this.m_body.GetTransform()); | |
} | |
b2Fixture.prototype.GetMassData = function (massData) { | |
if (massData === undefined) massData = null; | |
if (massData == null) { | |
massData = new b2MassData(); | |
} | |
this.m_shape.ComputeMass(massData, this.m_density); | |
return massData; | |
} | |
b2Fixture.prototype.SetDensity = function (density) { | |
if (density === undefined) density = 0; | |
this.m_density = density; | |
} | |
b2Fixture.prototype.GetDensity = function () { | |
return this.m_density; | |
} | |
b2Fixture.prototype.GetFriction = function () { | |
return this.m_friction; | |
} | |
b2Fixture.prototype.SetFriction = function (friction) { | |
if (friction === undefined) friction = 0; | |
this.m_friction = friction; | |
} | |
b2Fixture.prototype.GetRestitution = function () { | |
return this.m_restitution; | |
} | |
b2Fixture.prototype.SetRestitution = function (restitution) { | |
if (restitution === undefined) restitution = 0; | |
this.m_restitution = restitution; | |
} | |
b2Fixture.prototype.GetAABB = function () { | |
return this.m_aabb; | |
} | |
b2Fixture.prototype.b2Fixture = function () { | |
this.m_aabb = new b2AABB(); | |
this.m_userData = null; | |
this.m_body = null; | |
this.m_next = null; | |
this.m_shape = null; | |
this.m_density = 0.0; | |
this.m_friction = 0.0; | |
this.m_restitution = 0.0; | |
} | |
b2Fixture.prototype.Create = function (body, xf, def) { | |
this.m_userData = def.userData; | |
this.m_friction = def.friction; | |
this.m_restitution = def.restitution; | |
this.m_body = body; | |
this.m_next = null; | |
this.m_filter = def.filter.Copy(); | |
this.m_isSensor = def.isSensor; | |
this.m_shape = def.shape.Copy(); | |
this.m_density = def.density; | |
} | |
b2Fixture.prototype.Destroy = function () { | |
this.m_shape = null; | |
} | |
b2Fixture.prototype.CreateProxy = function (broadPhase, xf) { | |
this.m_shape.ComputeAABB(this.m_aabb, xf); | |
this.m_proxy = broadPhase.CreateProxy(this.m_aabb, this); | |
} | |
b2Fixture.prototype.DestroyProxy = function (broadPhase) { | |
if (this.m_proxy == null) { | |
return; | |
} | |
broadPhase.DestroyProxy(this.m_proxy); | |
this.m_proxy = null; | |
} | |
b2Fixture.prototype.Synchronize = function (broadPhase, transform1, transform2) { | |
if (!this.m_proxy) return; | |
var aabb1 = new b2AABB(); | |
var aabb2 = new b2AABB(); | |
this.m_shape.ComputeAABB(aabb1, transform1); | |
this.m_shape.ComputeAABB(aabb2, transform2); | |
this.m_aabb.Combine(aabb1, aabb2); | |
var displacement = b2Math.SubtractVV(transform2.position, transform1.position); | |
broadPhase.MoveProxy(this.m_proxy, this.m_aabb, displacement); | |
} | |
b2FixtureDef.b2FixtureDef = function () { | |
this.filter = new b2FilterData(); | |
}; | |
b2FixtureDef.prototype.b2FixtureDef = function () { | |
this.shape = null; | |
this.userData = null; | |
this.friction = 0.2; | |
this.restitution = 0.0; | |
this.density = 0.0; | |
this.filter.categoryBits = 0x0001; | |
this.filter.maskBits = 0xFFFF; | |
this.filter.groupIndex = 0; | |
this.isSensor = false; | |
} | |
b2Island.b2Island = function () {}; | |
b2Island.prototype.b2Island = function () { | |
this.m_bodies = new Vector(); | |
this.m_contacts = new Vector(); | |
this.m_joints = new Vector(); | |
} | |
b2Island.prototype.Initialize = function (bodyCapacity, contactCapacity, jointCapacity, allocator, listener, contactSolver) { | |
if (bodyCapacity === undefined) bodyCapacity = 0; | |
if (contactCapacity === undefined) contactCapacity = 0; | |
if (jointCapacity === undefined) jointCapacity = 0; | |
var i = 0; | |
this.m_bodyCapacity = bodyCapacity; | |
this.m_contactCapacity = contactCapacity; | |
this.m_jointCapacity = jointCapacity; | |
this.m_bodyCount = 0; | |
this.m_contactCount = 0; | |
this.m_jointCount = 0; | |
this.m_allocator = allocator; | |
this.m_listener = listener; | |
this.m_contactSolver = contactSolver; | |
for (i = this.m_bodies.length; | |
i < bodyCapacity; i++) | |
this.m_bodies[i] = null; | |
for (i = this.m_contacts.length; | |
i < contactCapacity; i++) | |
this.m_contacts[i] = null; | |
for (i = this.m_joints.length; | |
i < jointCapacity; i++) | |
this.m_joints[i] = null; | |
} | |
b2Island.prototype.Clear = function () { | |
this.m_bodyCount = 0; | |
this.m_contactCount = 0; | |
this.m_jointCount = 0; | |
} | |
b2Island.prototype.Solve = function (step, gravity, allowSleep) { | |
var i = 0; | |
var j = 0; | |
var b; | |
var joint; | |
for (i = 0; | |
i < this.m_bodyCount; ++i) { | |
b = this.m_bodies[i]; | |
if (b.GetType() != b2Body.b2_dynamicBody) continue; | |
b.m_linearVelocity.x += step.dt * (gravity.x + b.m_invMass * b.m_force.x); | |
b.m_linearVelocity.y += step.dt * (gravity.y + b.m_invMass * b.m_force.y); | |
b.m_angularVelocity += step.dt * b.m_invI * b.m_torque; | |
b.m_linearVelocity.Multiply(b2Math.Clamp(1.0 - step.dt * b.m_linearDamping, 0.0, 1.0)); | |
b.m_angularVelocity *= b2Math.Clamp(1.0 - step.dt * b.m_angularDamping, 0.0, 1.0); | |
} | |
this.m_contactSolver.Initialize(step, this.m_contacts, this.m_contactCount, this.m_allocator); | |
var contactSolver = this.m_contactSolver; | |
contactSolver.InitVelocityConstraints(step); | |
for (i = 0; | |
i < this.m_jointCount; ++i) { | |
joint = this.m_joints[i]; | |
joint.InitVelocityConstraints(step); | |
} | |
for (i = 0; | |
i < step.velocityIterations; ++i) { | |
for (j = 0; | |
j < this.m_jointCount; ++j) { | |
joint = this.m_joints[j]; | |
joint.SolveVelocityConstraints(step); | |
} | |
contactSolver.SolveVelocityConstraints(); | |
} | |
for (i = 0; | |
i < this.m_jointCount; ++i) { | |
joint = this.m_joints[i]; | |
joint.FinalizeVelocityConstraints(); | |
} | |
contactSolver.FinalizeVelocityConstraints(); | |
for (i = 0; | |
i < this.m_bodyCount; ++i) { | |
b = this.m_bodies[i]; | |
if (b.GetType() == b2Body.b2_staticBody) continue; | |
var translationX = step.dt * b.m_linearVelocity.x; | |
var translationY = step.dt * b.m_linearVelocity.y; | |
if ((translationX * translationX + translationY * translationY) > b2Settings.b2_maxTranslationSquared) { | |
b.m_linearVelocity.Normalize(); | |
b.m_linearVelocity.x *= b2Settings.b2_maxTranslation * step.inv_dt; | |
b.m_linearVelocity.y *= b2Settings.b2_maxTranslation * step.inv_dt; | |
} | |
var rotation = step.dt * b.m_angularVelocity; | |
if (rotation * rotation > b2Settings.b2_maxRotationSquared) { | |
if (b.m_angularVelocity < 0.0) { | |
b.m_angularVelocity = (-b2Settings.b2_maxRotation * step.inv_dt); | |
} | |
else { | |
b.m_angularVelocity = b2Settings.b2_maxRotation * step.inv_dt; | |
} | |
} | |
b.m_sweep.c0.SetV(b.m_sweep.c); | |
b.m_sweep.a0 = b.m_sweep.a; | |
b.m_sweep.c.x += step.dt * b.m_linearVelocity.x; | |
b.m_sweep.c.y += step.dt * b.m_linearVelocity.y; | |
b.m_sweep.a += step.dt * b.m_angularVelocity; | |
b.SynchronizeTransform(); | |
} | |
for (i = 0; | |
i < step.positionIterations; ++i) { | |
var contactsOkay = contactSolver.SolvePositionConstraints(b2Settings.b2_contactBaumgarte); | |
var jointsOkay = true; | |
for (j = 0; | |
j < this.m_jointCount; ++j) { | |
joint = this.m_joints[j]; | |
var jointOkay = joint.SolvePositionConstraints(b2Settings.b2_contactBaumgarte); | |
jointsOkay = jointsOkay && jointOkay; | |
} | |
if (contactsOkay && jointsOkay) { | |
break; | |
} | |
} | |
this.Report(contactSolver.m_constraints); | |
if (allowSleep) { | |
var minSleepTime = Number.MAX_VALUE; | |
var linTolSqr = b2Settings.b2_linearSleepTolerance * b2Settings.b2_linearSleepTolerance; | |
var angTolSqr = b2Settings.b2_angularSleepTolerance * b2Settings.b2_angularSleepTolerance; | |
for (i = 0; | |
i < this.m_bodyCount; ++i) { | |
b = this.m_bodies[i]; | |
if (b.GetType() == b2Body.b2_staticBody) { | |
continue; | |
} | |
if ((b.m_flags & b2Body.e_allowSleepFlag) == 0) { | |
b.m_sleepTime = 0.0; | |
minSleepTime = 0.0; | |
} | |
if ((b.m_flags & b2Body.e_allowSleepFlag) == 0 || b.m_angularVelocity * b.m_angularVelocity > angTolSqr || b2Math.Dot(b.m_linearVelocity, b.m_linearVelocity) > linTolSqr) { | |
b.m_sleepTime = 0.0; | |
minSleepTime = 0.0; | |
} | |
else { | |
b.m_sleepTime += step.dt; | |
minSleepTime = b2Math.Min(minSleepTime, b.m_sleepTime); | |
} | |
} | |
if (minSleepTime >= b2Settings.b2_timeToSleep) { | |
for (i = 0; | |
i < this.m_bodyCount; ++i) { | |
b = this.m_bodies[i]; | |
b.SetAwake(false); | |
} | |
} | |
} | |
} | |
b2Island.prototype.SolveTOI = function (subStep) { | |
var i = 0; | |
var j = 0; | |
this.m_contactSolver.Initialize(subStep, this.m_contacts, this.m_contactCount, this.m_allocator); | |
var contactSolver = this.m_contactSolver; | |
for (i = 0; | |
i < this.m_jointCount; ++i) { | |
this.m_joints[i].InitVelocityConstraints(subStep); | |
} | |
for (i = 0; | |
i < subStep.velocityIterations; ++i) { | |
contactSolver.SolveVelocityConstraints(); | |
for (j = 0; | |
j < this.m_jointCount; ++j) { | |
this.m_joints[j].SolveVelocityConstraints(subStep); | |
} | |
} | |
for (i = 0; | |
i < this.m_bodyCount; ++i) { | |
var b = this.m_bodies[i]; | |
if (b.GetType() == b2Body.b2_staticBody) continue; | |
var translationX = subStep.dt * b.m_linearVelocity.x; | |
var translationY = subStep.dt * b.m_linearVelocity.y; | |
if ((translationX * translationX + translationY * translationY) > b2Settings.b2_maxTranslationSquared) { | |
b.m_linearVelocity.Normalize(); | |
b.m_linearVelocity.x *= b2Settings.b2_maxTranslation * subStep.inv_dt; | |
b.m_linearVelocity.y *= b2Settings.b2_maxTranslation * subStep.inv_dt; | |
} | |
var rotation = subStep.dt * b.m_angularVelocity; | |
if (rotation * rotation > b2Settings.b2_maxRotationSquared) { | |
if (b.m_angularVelocity < 0.0) { | |
b.m_angularVelocity = (-b2Settings.b2_maxRotation * subStep.inv_dt); | |
} | |
else { | |
b.m_angularVelocity = b2Settings.b2_maxRotation * subStep.inv_dt; | |
} | |
} | |
b.m_sweep.c0.SetV(b.m_sweep.c); | |
b.m_sweep.a0 = b.m_sweep.a; | |
b.m_sweep.c.x += subStep.dt * b.m_linearVelocity.x; | |
b.m_sweep.c.y += subStep.dt * b.m_linearVelocity.y; | |
b.m_sweep.a += subStep.dt * b.m_angularVelocity; | |
b.SynchronizeTransform(); | |
} | |
var k_toiBaumgarte = 0.75; | |
for (i = 0; | |
i < subStep.positionIterations; ++i) { | |
var contactsOkay = contactSolver.SolvePositionConstraints(k_toiBaumgarte); | |
var jointsOkay = true; | |
for (j = 0; | |
j < this.m_jointCount; ++j) { | |
var jointOkay = this.m_joints[j].SolvePositionConstraints(b2Settings.b2_contactBaumgarte); | |
jointsOkay = jointsOkay && jointOkay; | |
} | |
if (contactsOkay && jointsOkay) { | |
break; | |
} | |
} | |
this.Report(contactSolver.m_constraints); | |
} | |
b2Island.prototype.Report = function (constraints) { | |
if (this.m_listener == null) { | |
return; | |
} | |
for (var i = 0; i < this.m_contactCount; ++i) { | |
var c = this.m_contacts[i]; | |
var cc = constraints[i]; | |
for (var j = 0; j < cc.pointCount; ++j) { | |
b2Island.s_impulse.normalImpulses[j] = cc.points[j].normalImpulse; | |
b2Island.s_impulse.tangentImpulses[j] = cc.points[j].tangentImpulse; | |
} | |
this.m_listener.PostSolve(c, b2Island.s_impulse); | |
} | |
} | |
b2Island.prototype.AddBody = function (body) { | |
body.m_islandIndex = this.m_bodyCount; | |
this.m_bodies[this.m_bodyCount++] = body; | |
} | |
b2Island.prototype.AddContact = function (contact) { | |
this.m_contacts[this.m_contactCount++] = contact; | |
} | |
b2Island.prototype.AddJoint = function (joint) { | |
this.m_joints[this.m_jointCount++] = joint; | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Dynamics.b2Island.s_impulse = new b2ContactImpulse(); | |
}); | |
b2TimeStep.b2TimeStep = function () {}; | |
b2TimeStep.prototype.Set = function (step) { | |
this.dt = step.dt; | |
this.inv_dt = step.inv_dt; | |
this.positionIterations = step.positionIterations; | |
this.velocityIterations = step.velocityIterations; | |
this.warmStarting = step.warmStarting; | |
} | |
b2World.b2World = function () { | |
this.s_stack = new Vector(); | |
this.m_contactManager = new b2ContactManager(); | |
this.m_contactSolver = new b2ContactSolver(); | |
this.m_island = new b2Island(); | |
}; | |
b2World.prototype.b2World = function (gravity, doSleep) { | |
this.m_destructionListener = null; | |
this.m_debugDraw = null; | |
this.m_bodyList = null; | |
this.m_contactList = null; | |
this.m_jointList = null; | |
this.m_controllerList = null; | |
this.m_bodyCount = 0; | |
this.m_contactCount = 0; | |
this.m_jointCount = 0; | |
this.m_controllerCount = 0; | |
b2World.m_warmStarting = true; | |
b2World.m_continuousPhysics = true; | |
this.m_allowSleep = doSleep; | |
this.m_gravity = gravity; | |
this.m_inv_dt0 = 0.0; | |
this.m_contactManager.m_world = this; | |
var bd = new b2BodyDef(); | |
this.m_groundBody = this.CreateBody(bd); | |
} | |
b2World.prototype.SetDestructionListener = function (listener) { | |
this.m_destructionListener = listener; | |
} | |
b2World.prototype.SetContactFilter = function (filter) { | |
this.m_contactManager.m_contactFilter = filter; | |
} | |
b2World.prototype.SetContactListener = function (listener) { | |
this.m_contactManager.m_contactListener = listener; | |
} | |
b2World.prototype.SetDebugDraw = function (debugDraw) { | |
this.m_debugDraw = debugDraw; | |
} | |
b2World.prototype.SetBroadPhase = function (broadPhase) { | |
var oldBroadPhase = this.m_contactManager.m_broadPhase; | |
this.m_contactManager.m_broadPhase = broadPhase; | |
for (var b = this.m_bodyList; b; b = b.m_next) { | |
for (var f = b.m_fixtureList; f; f = f.m_next) { | |
f.m_proxy = broadPhase.CreateProxy(oldBroadPhase.GetFatAABB(f.m_proxy), f); | |
} | |
} | |
} | |
b2World.prototype.Validate = function () { | |
this.m_contactManager.m_broadPhase.Validate(); | |
} | |
b2World.prototype.GetProxyCount = function () { | |
return this.m_contactManager.m_broadPhase.GetProxyCount(); | |
} | |
b2World.prototype.CreateBody = function (def) { | |
if (this.IsLocked() == true) { | |
return null; | |
} | |
var b = new b2Body(def, this); | |
b.m_prev = null; | |
b.m_next = this.m_bodyList; | |
if (this.m_bodyList) { | |
this.m_bodyList.m_prev = b; | |
} | |
this.m_bodyList = b; | |
++this.m_bodyCount; | |
return b; | |
} | |
b2World.prototype.DestroyBody = function (b) { | |
if (this.IsLocked() == true) { | |
return; | |
} | |
var jn = b.m_jointList; | |
while (jn) { | |
var jn0 = jn; | |
jn = jn.next; | |
if (this.m_destructionListener) { | |
this.m_destructionListener.SayGoodbyeJoint(jn0.joint); | |
} | |
this.DestroyJoint(jn0.joint); | |
} | |
var coe = b.m_controllerList; | |
while (coe) { | |
var coe0 = coe; | |
coe = coe.nextController; | |
coe0.controller.RemoveBody(b); | |
} | |
var ce = b.m_contactList; | |
while (ce) { | |
var ce0 = ce; | |
ce = ce.next; | |
this.m_contactManager.Destroy(ce0.contact); | |
} | |
b.m_contactList = null; | |
var f = b.m_fixtureList; | |
while (f) { | |
var f0 = f; | |
f = f.m_next; | |
if (this.m_destructionListener) { | |
this.m_destructionListener.SayGoodbyeFixture(f0); | |
} | |
f0.DestroyProxy(this.m_contactManager.m_broadPhase); | |
f0.Destroy(); | |
} | |
b.m_fixtureList = null; | |
b.m_fixtureCount = 0; | |
if (b.m_prev) { | |
b.m_prev.m_next = b.m_next; | |
} | |
if (b.m_next) { | |
b.m_next.m_prev = b.m_prev; | |
} | |
if (b == this.m_bodyList) { | |
this.m_bodyList = b.m_next; | |
}--this.m_bodyCount; | |
} | |
b2World.prototype.CreateJoint = function (def) { | |
var j = b2Joint.Create(def, null); | |
j.m_prev = null; | |
j.m_next = this.m_jointList; | |
if (this.m_jointList) { | |
this.m_jointList.m_prev = j; | |
} | |
this.m_jointList = j; | |
++this.m_jointCount; | |
j.m_edgeA.joint = j; | |
j.m_edgeA.other = j.m_bodyB; | |
j.m_edgeA.prev = null; | |
j.m_edgeA.next = j.m_bodyA.m_jointList; | |
if (j.m_bodyA.m_jointList) j.m_bodyA.m_jointList.prev = j.m_edgeA; | |
j.m_bodyA.m_jointList = j.m_edgeA; | |
j.m_edgeB.joint = j; | |
j.m_edgeB.other = j.m_bodyA; | |
j.m_edgeB.prev = null; | |
j.m_edgeB.next = j.m_bodyB.m_jointList; | |
if (j.m_bodyB.m_jointList) j.m_bodyB.m_jointList.prev = j.m_edgeB; | |
j.m_bodyB.m_jointList = j.m_edgeB; | |
var bodyA = def.bodyA; | |
var bodyB = def.bodyB; | |
if (def.collideConnected == false) { | |
var edge = bodyB.GetContactList(); | |
while (edge) { | |
if (edge.other == bodyA) { | |
edge.contact.FlagForFiltering(); | |
} | |
edge = edge.next; | |
} | |
} | |
return j; | |
} | |
b2World.prototype.DestroyJoint = function (j) { | |
var collideConnected = j.m_collideConnected; | |
if (j.m_prev) { | |
j.m_prev.m_next = j.m_next; | |
} | |
if (j.m_next) { | |
j.m_next.m_prev = j.m_prev; | |
} | |
if (j == this.m_jointList) { | |
this.m_jointList = j.m_next; | |
} | |
var bodyA = j.m_bodyA; | |
var bodyB = j.m_bodyB; | |
bodyA.SetAwake(true); | |
bodyB.SetAwake(true); | |
if (j.m_edgeA.prev) { | |
j.m_edgeA.prev.next = j.m_edgeA.next; | |
} | |
if (j.m_edgeA.next) { | |
j.m_edgeA.next.prev = j.m_edgeA.prev; | |
} | |
if (j.m_edgeA == bodyA.m_jointList) { | |
bodyA.m_jointList = j.m_edgeA.next; | |
} | |
j.m_edgeA.prev = null; | |
j.m_edgeA.next = null; | |
if (j.m_edgeB.prev) { | |
j.m_edgeB.prev.next = j.m_edgeB.next; | |
} | |
if (j.m_edgeB.next) { | |
j.m_edgeB.next.prev = j.m_edgeB.prev; | |
} | |
if (j.m_edgeB == bodyB.m_jointList) { | |
bodyB.m_jointList = j.m_edgeB.next; | |
} | |
j.m_edgeB.prev = null; | |
j.m_edgeB.next = null; | |
b2Joint.Destroy(j, null); | |
--this.m_jointCount; | |
if (collideConnected == false) { | |
var edge = bodyB.GetContactList(); | |
while (edge) { | |
if (edge.other == bodyA) { | |
edge.contact.FlagForFiltering(); | |
} | |
edge = edge.next; | |
} | |
} | |
} | |
b2World.prototype.AddController = function (c) { | |
c.m_next = this.m_controllerList; | |
c.m_prev = null; | |
this.m_controllerList = c; | |
c.m_world = this; | |
this.m_controllerCount++; | |
return c; | |
} | |
b2World.prototype.RemoveController = function (c) { | |
if (c.m_prev) c.m_prev.m_next = c.m_next; | |
if (c.m_next) c.m_next.m_prev = c.m_prev; | |
if (this.m_controllerList == c) this.m_controllerList = c.m_next; | |
this.m_controllerCount--; | |
} | |
b2World.prototype.CreateController = function (controller) { | |
if (controller.m_world != this) throw new Error("Controller can only be a member of one world"); | |
controller.m_next = this.m_controllerList; | |
controller.m_prev = null; | |
if (this.m_controllerList) this.m_controllerList.m_prev = controller; | |
this.m_controllerList = controller; | |
++this.m_controllerCount; | |
controller.m_world = this; | |
return controller; | |
} | |
b2World.prototype.DestroyController = function (controller) { | |
controller.Clear(); | |
if (controller.m_next) controller.m_next.m_prev = controller.m_prev; | |
if (controller.m_prev) controller.m_prev.m_next = controller.m_next; | |
if (controller == this.m_controllerList) this.m_controllerList = controller.m_next; | |
--this.m_controllerCount; | |
} | |
b2World.prototype.SetWarmStarting = function (flag) { | |
b2World.m_warmStarting = flag; | |
} | |
b2World.prototype.SetContinuousPhysics = function (flag) { | |
b2World.m_continuousPhysics = flag; | |
} | |
b2World.prototype.GetBodyCount = function () { | |
return this.m_bodyCount; | |
} | |
b2World.prototype.GetJointCount = function () { | |
return this.m_jointCount; | |
} | |
b2World.prototype.GetContactCount = function () { | |
return this.m_contactCount; | |
} | |
b2World.prototype.SetGravity = function (gravity) { | |
this.m_gravity = gravity; | |
} | |
b2World.prototype.GetGravity = function () { | |
return this.m_gravity; | |
} | |
b2World.prototype.GetGroundBody = function () { | |
return this.m_groundBody; | |
} | |
b2World.prototype.Step = function (dt, velocityIterations, positionIterations) { | |
if (dt === undefined) dt = 0; | |
if (velocityIterations === undefined) velocityIterations = 0; | |
if (positionIterations === undefined) positionIterations = 0; | |
if (this.m_flags & b2World.e_newFixture) { | |
this.m_contactManager.FindNewContacts(); | |
this.m_flags &= ~b2World.e_newFixture; | |
} | |
this.m_flags |= b2World.e_locked; | |
var step = b2World.s_timestep2; | |
step.dt = dt; | |
step.velocityIterations = velocityIterations; | |
step.positionIterations = positionIterations; | |
if (dt > 0.0) { | |
step.inv_dt = 1.0 / dt; | |
} | |
else { | |
step.inv_dt = 0.0; | |
} | |
step.dtRatio = this.m_inv_dt0 * dt; | |
step.warmStarting = b2World.m_warmStarting; | |
this.m_contactManager.Collide(); | |
if (step.dt > 0.0) { | |
this.Solve(step); | |
} | |
if (b2World.m_continuousPhysics && step.dt > 0.0) { | |
this.SolveTOI(step); | |
} | |
if (step.dt > 0.0) { | |
this.m_inv_dt0 = step.inv_dt; | |
} | |
this.m_flags &= ~b2World.e_locked; | |
} | |
b2World.prototype.ClearForces = function () { | |
for (var body = this.m_bodyList; body; body = body.m_next) { | |
body.m_force.SetZero(); | |
body.m_torque = 0.0; | |
} | |
} | |
b2World.prototype.DrawDebugData = function () { | |
if (this.m_debugDraw == null) { | |
return; | |
} | |
this.m_debugDraw.m_sprite.graphics.clear(); | |
var flags = this.m_debugDraw.GetFlags(); | |
var i = 0; | |
var b; | |
var f; | |
var s; | |
var j; | |
var bp; | |
var invQ = new b2Vec2; | |
var x1 = new b2Vec2; | |
var x2 = new b2Vec2; | |
var xf; | |
var b1 = new b2AABB(); | |
var b2 = new b2AABB(); | |
var vs = [new b2Vec2(), new b2Vec2(), new b2Vec2(), new b2Vec2()]; | |
var color = new b2Color(0, 0, 0); | |
if (flags & b2DebugDraw.e_shapeBit) { | |
for (b = this.m_bodyList; | |
b; b = b.m_next) { | |
xf = b.m_xf; | |
for (f = b.GetFixtureList(); | |
f; f = f.m_next) { | |
s = f.GetShape(); | |
if (b.IsActive() == false) { | |
color.Set(0.5, 0.5, 0.3); | |
this.DrawShape(s, xf, color); | |
} | |
else if (b.GetType() == b2Body.b2_staticBody) { | |
color.Set(0.5, 0.9, 0.5); | |
this.DrawShape(s, xf, color); | |
} | |
else if (b.GetType() == b2Body.b2_kinematicBody) { | |
color.Set(0.5, 0.5, 0.9); | |
this.DrawShape(s, xf, color); | |
} | |
else if (b.IsAwake() == false) { | |
color.Set(0.6, 0.6, 0.6); | |
this.DrawShape(s, xf, color); | |
} | |
else { | |
color.Set(0.9, 0.7, 0.7); | |
this.DrawShape(s, xf, color); | |
} | |
} | |
} | |
} | |
if (flags & b2DebugDraw.e_jointBit) { | |
for (j = this.m_jointList; | |
j; j = j.m_next) { | |
this.DrawJoint(j); | |
} | |
} | |
if (flags & b2DebugDraw.e_controllerBit) { | |
for (var c = this.m_controllerList; c; c = c.m_next) { | |
c.Draw(this.m_debugDraw); | |
} | |
} | |
if (flags & b2DebugDraw.e_pairBit) { | |
color.Set(0.3, 0.9, 0.9); | |
for (var contact = this.m_contactManager.m_contactList; contact; contact = contact.GetNext()) { | |
var fixtureA = contact.GetFixtureA(); | |
var fixtureB = contact.GetFixtureB(); | |
var cA = fixtureA.GetAABB().GetCenter(); | |
var cB = fixtureB.GetAABB().GetCenter(); | |
this.m_debugDraw.DrawSegment(cA, cB, color); | |
} | |
} | |
if (flags & b2DebugDraw.e_aabbBit) { | |
bp = this.m_contactManager.m_broadPhase; | |
vs = [new b2Vec2(), new b2Vec2(), new b2Vec2(), new b2Vec2()]; | |
for (b = this.m_bodyList; | |
b; b = b.GetNext()) { | |
if (b.IsActive() == false) { | |
continue; | |
} | |
for (f = b.GetFixtureList(); | |
f; f = f.GetNext()) { | |
var aabb = bp.GetFatAABB(f.m_proxy); | |
vs[0].Set(aabb.lowerBound.x, aabb.lowerBound.y); | |
vs[1].Set(aabb.upperBound.x, aabb.lowerBound.y); | |
vs[2].Set(aabb.upperBound.x, aabb.upperBound.y); | |
vs[3].Set(aabb.lowerBound.x, aabb.upperBound.y); | |
this.m_debugDraw.DrawPolygon(vs, 4, color); | |
} | |
} | |
} | |
if (flags & b2DebugDraw.e_centerOfMassBit) { | |
for (b = this.m_bodyList; | |
b; b = b.m_next) { | |
xf = b2World.s_xf; | |
xf.R = b.m_xf.R; | |
xf.position = b.GetWorldCenter(); | |
this.m_debugDraw.DrawTransform(xf); | |
} | |
} | |
} | |
b2World.prototype.QueryAABB = function (callback, aabb) { | |
var __this = this; | |
var broadPhase = __this.m_contactManager.m_broadPhase; | |
function WorldQueryWrapper(proxy) { | |
return callback(broadPhase.GetUserData(proxy)); | |
}; | |
broadPhase.Query(WorldQueryWrapper, aabb); | |
} | |
b2World.prototype.QueryShape = function (callback, shape, transform) { | |
var __this = this; | |
if (transform === undefined) transform = null; | |
if (transform == null) { | |
transform = new b2Transform(); | |
transform.SetIdentity(); | |
} | |
var broadPhase = __this.m_contactManager.m_broadPhase; | |
function WorldQueryWrapper(proxy) { | |
var fixture = (broadPhase.GetUserData(proxy) instanceof b2Fixture ? broadPhase.GetUserData(proxy) : null); | |
if (b2Shape.TestOverlap(shape, transform, fixture.GetShape(), fixture.GetBody().GetTransform())) return callback(fixture); | |
return true; | |
}; | |
var aabb = new b2AABB(); | |
shape.ComputeAABB(aabb, transform); | |
broadPhase.Query(WorldQueryWrapper, aabb); | |
} | |
b2World.prototype.QueryPoint = function (callback, p) { | |
var __this = this; | |
var broadPhase = __this.m_contactManager.m_broadPhase; | |
function WorldQueryWrapper(proxy) { | |
var fixture = (broadPhase.GetUserData(proxy) instanceof b2Fixture ? broadPhase.GetUserData(proxy) : null); | |
if (fixture.TestPoint(p)) return callback(fixture); | |
return true; | |
}; | |
var aabb = new b2AABB(); | |
aabb.lowerBound.Set(p.x - b2Settings.b2_linearSlop, p.y - b2Settings.b2_linearSlop); | |
aabb.upperBound.Set(p.x + b2Settings.b2_linearSlop, p.y + b2Settings.b2_linearSlop); | |
broadPhase.Query(WorldQueryWrapper, aabb); | |
} | |
b2World.prototype.RayCast = function (callback, point1, point2) { | |
var __this = this; | |
var broadPhase = __this.m_contactManager.m_broadPhase; | |
var output = new b2RayCastOutput; | |
function RayCastWrapper(input, proxy) { | |
var userData = broadPhase.GetUserData(proxy); | |
var fixture = (userData instanceof b2Fixture ? userData : null); | |
var hit = fixture.RayCast(output, input); | |
if (hit) { | |
var fraction = output.fraction; | |
var point = new b2Vec2((1.0 - fraction) * point1.x + fraction * point2.x, (1.0 - fraction) * point1.y + fraction * point2.y); | |
return callback(fixture, point, output.normal, fraction); | |
} | |
return input.maxFraction; | |
}; | |
var input = new b2RayCastInput(point1, point2); | |
broadPhase.RayCast(RayCastWrapper, input); | |
} | |
b2World.prototype.RayCastOne = function (point1, point2) { | |
var __this = this; | |
var result; | |
function RayCastOneWrapper(fixture, point, normal, fraction) { | |
if (fraction === undefined) fraction = 0; | |
result = fixture; | |
return fraction; | |
}; | |
__this.RayCast(RayCastOneWrapper, point1, point2); | |
return result; | |
} | |
b2World.prototype.RayCastAll = function (point1, point2) { | |
var __this = this; | |
var result = new Vector(); | |
function RayCastAllWrapper(fixture, point, normal, fraction) { | |
if (fraction === undefined) fraction = 0; | |
result[result.length] = fixture; | |
return 1; | |
}; | |
__this.RayCast(RayCastAllWrapper, point1, point2); | |
return result; | |
} | |
b2World.prototype.GetBodyList = function () { | |
return this.m_bodyList; | |
} | |
b2World.prototype.GetJointList = function () { | |
return this.m_jointList; | |
} | |
b2World.prototype.GetContactList = function () { | |
return this.m_contactList; | |
} | |
b2World.prototype.IsLocked = function () { | |
return (this.m_flags & b2World.e_locked) > 0; | |
} | |
b2World.prototype.Solve = function (step) { | |
var b; | |
for (var controller = this.m_controllerList; controller; controller = controller.m_next) { | |
controller.Step(step); | |
} | |
var island = this.m_island; | |
island.Initialize(this.m_bodyCount, this.m_contactCount, this.m_jointCount, null, this.m_contactManager.m_contactListener, this.m_contactSolver); | |
for (b = this.m_bodyList; | |
b; b = b.m_next) { | |
b.m_flags &= ~b2Body.e_islandFlag; | |
} | |
for (var c = this.m_contactList; c; c = c.m_next) { | |
c.m_flags &= ~b2Contact.e_islandFlag; | |
} | |
for (var j = this.m_jointList; j; j = j.m_next) { | |
j.m_islandFlag = false; | |
} | |
var stackSize = parseInt(this.m_bodyCount); | |
var stack = this.s_stack; | |
for (var seed = this.m_bodyList; seed; seed = seed.m_next) { | |
if (seed.m_flags & b2Body.e_islandFlag) { | |
continue; | |
} | |
if (seed.IsAwake() == false || seed.IsActive() == false) { | |
continue; | |
} | |
if (seed.GetType() == b2Body.b2_staticBody) { | |
continue; | |
} | |
island.Clear(); | |
var stackCount = 0; | |
stack[stackCount++] = seed; | |
seed.m_flags |= b2Body.e_islandFlag; | |
while (stackCount > 0) { | |
b = stack[--stackCount]; | |
island.AddBody(b); | |
if (b.IsAwake() == false) { | |
b.SetAwake(true); | |
} | |
if (b.GetType() == b2Body.b2_staticBody) { | |
continue; | |
} | |
var other; | |
for (var ce = b.m_contactList; ce; ce = ce.next) { | |
if (ce.contact.m_flags & b2Contact.e_islandFlag) { | |
continue; | |
} | |
if (ce.contact.IsSensor() == true || ce.contact.IsEnabled() == false || ce.contact.IsTouching() == false) { | |
continue; | |
} | |
island.AddContact(ce.contact); | |
ce.contact.m_flags |= b2Contact.e_islandFlag; | |
other = ce.other; | |
if (other.m_flags & b2Body.e_islandFlag) { | |
continue; | |
} | |
stack[stackCount++] = other; | |
other.m_flags |= b2Body.e_islandFlag; | |
} | |
for (var jn = b.m_jointList; jn; jn = jn.next) { | |
if (jn.joint.m_islandFlag == true) { | |
continue; | |
} | |
other = jn.other; | |
if (other.IsActive() == false) { | |
continue; | |
} | |
island.AddJoint(jn.joint); | |
jn.joint.m_islandFlag = true; | |
if (other.m_flags & b2Body.e_islandFlag) { | |
continue; | |
} | |
stack[stackCount++] = other; | |
other.m_flags |= b2Body.e_islandFlag; | |
} | |
} | |
island.Solve(step, this.m_gravity, this.m_allowSleep); | |
for (var i = 0; i < island.m_bodyCount; ++i) { | |
b = island.m_bodies[i]; | |
if (b.GetType() == b2Body.b2_staticBody) { | |
b.m_flags &= ~b2Body.e_islandFlag; | |
} | |
} | |
} | |
for (i = 0; | |
i < stack.length; ++i) { | |
if (!stack[i]) break; | |
stack[i] = null; | |
} | |
for (b = this.m_bodyList; | |
b; b = b.m_next) { | |
if (b.IsAwake() == false || b.IsActive() == false) { | |
continue; | |
} | |
if (b.GetType() == b2Body.b2_staticBody) { | |
continue; | |
} | |
b.SynchronizeFixtures(); | |
} | |
this.m_contactManager.FindNewContacts(); | |
} | |
b2World.prototype.SolveTOI = function (step) { | |
var b; | |
var fA; | |
var fB; | |
var bA; | |
var bB; | |
var cEdge; | |
var j; | |
var island = this.m_island; | |
island.Initialize(this.m_bodyCount, b2Settings.b2_maxTOIContactsPerIsland, b2Settings.b2_maxTOIJointsPerIsland, null, this.m_contactManager.m_contactListener, this.m_contactSolver); | |
var queue = b2World.s_queue; | |
for (b = this.m_bodyList; | |
b; b = b.m_next) { | |
b.m_flags &= ~b2Body.e_islandFlag; | |
b.m_sweep.t0 = 0.0; | |
} | |
var c; | |
for (c = this.m_contactList; | |
c; c = c.m_next) { | |
c.m_flags &= ~ (b2Contact.e_toiFlag | b2Contact.e_islandFlag); | |
} | |
for (j = this.m_jointList; | |
j; j = j.m_next) { | |
j.m_islandFlag = false; | |
} | |
for (;;) { | |
var minContact = null; | |
var minTOI = 1.0; | |
for (c = this.m_contactList; | |
c; c = c.m_next) { | |
if (c.IsSensor() == true || c.IsEnabled() == false || c.IsContinuous() == false) { | |
continue; | |
} | |
var toi = 1.0; | |
if (c.m_flags & b2Contact.e_toiFlag) { | |
toi = c.m_toi; | |
} | |
else { | |
fA = c.m_fixtureA; | |
fB = c.m_fixtureB; | |
bA = fA.m_body; | |
bB = fB.m_body; | |
if ((bA.GetType() != b2Body.b2_dynamicBody || bA.IsAwake() == false) && (bB.GetType() != b2Body.b2_dynamicBody || bB.IsAwake() == false)) { | |
continue; | |
} | |
var t0 = bA.m_sweep.t0; | |
if (bA.m_sweep.t0 < bB.m_sweep.t0) { | |
t0 = bB.m_sweep.t0; | |
bA.m_sweep.Advance(t0); | |
} | |
else if (bB.m_sweep.t0 < bA.m_sweep.t0) { | |
t0 = bA.m_sweep.t0; | |
bB.m_sweep.Advance(t0); | |
} | |
toi = c.ComputeTOI(bA.m_sweep, bB.m_sweep); | |
b2Settings.b2Assert(0.0 <= toi && toi <= 1.0); | |
if (toi > 0.0 && toi < 1.0) { | |
toi = (1.0 - toi) * t0 + toi; | |
if (toi > 1) toi = 1; | |
} | |
c.m_toi = toi; | |
c.m_flags |= b2Contact.e_toiFlag; | |
} | |
if (Number.MIN_VALUE < toi && toi < minTOI) { | |
minContact = c; | |
minTOI = toi; | |
} | |
} | |
if (minContact == null || 1.0 - 100.0 * Number.MIN_VALUE < minTOI) { | |
break; | |
} | |
fA = minContact.m_fixtureA; | |
fB = minContact.m_fixtureB; | |
bA = fA.m_body; | |
bB = fB.m_body; | |
b2World.s_backupA.Set(bA.m_sweep); | |
b2World.s_backupB.Set(bB.m_sweep); | |
bA.Advance(minTOI); | |
bB.Advance(minTOI); | |
minContact.Update(this.m_contactManager.m_contactListener); | |
minContact.m_flags &= ~b2Contact.e_toiFlag; | |
if (minContact.IsSensor() == true || minContact.IsEnabled() == false) { | |
bA.m_sweep.Set(b2World.s_backupA); | |
bB.m_sweep.Set(b2World.s_backupB); | |
bA.SynchronizeTransform(); | |
bB.SynchronizeTransform(); | |
continue; | |
} | |
if (minContact.IsTouching() == false) { | |
continue; | |
} | |
var seed = bA; | |
if (seed.GetType() != b2Body.b2_dynamicBody) { | |
seed = bB; | |
} | |
island.Clear(); | |
var queueStart = 0; | |
var queueSize = 0; | |
queue[queueStart + queueSize++] = seed; | |
seed.m_flags |= b2Body.e_islandFlag; | |
while (queueSize > 0) { | |
b = queue[queueStart++]; | |
--queueSize; | |
island.AddBody(b); | |
if (b.IsAwake() == false) { | |
b.SetAwake(true); | |
} | |
if (b.GetType() != b2Body.b2_dynamicBody) { | |
continue; | |
} | |
for (cEdge = b.m_contactList; | |
cEdge; cEdge = cEdge.next) { | |
if (island.m_contactCount == island.m_contactCapacity) { | |
break; | |
} | |
if (cEdge.contact.m_flags & b2Contact.e_islandFlag) { | |
continue; | |
} | |
if (cEdge.contact.IsSensor() == true || cEdge.contact.IsEnabled() == false || cEdge.contact.IsTouching() == false) { | |
continue; | |
} | |
island.AddContact(cEdge.contact); | |
cEdge.contact.m_flags |= b2Contact.e_islandFlag; | |
var other = cEdge.other; | |
if (other.m_flags & b2Body.e_islandFlag) { | |
continue; | |
} | |
if (other.GetType() != b2Body.b2_staticBody) { | |
other.Advance(minTOI); | |
other.SetAwake(true); | |
} | |
queue[queueStart + queueSize] = other; | |
++queueSize; | |
other.m_flags |= b2Body.e_islandFlag; | |
} | |
for (var jEdge = b.m_jointList; jEdge; jEdge = jEdge.next) { | |
if (island.m_jointCount == island.m_jointCapacity) continue; | |
if (jEdge.joint.m_islandFlag == true) continue; | |
other = jEdge.other; | |
if (other.IsActive() == false) { | |
continue; | |
} | |
island.AddJoint(jEdge.joint); | |
jEdge.joint.m_islandFlag = true; | |
if (other.m_flags & b2Body.e_islandFlag) continue; | |
if (other.GetType() != b2Body.b2_staticBody) { | |
other.Advance(minTOI); | |
other.SetAwake(true); | |
} | |
queue[queueStart + queueSize] = other; | |
++queueSize; | |
other.m_flags |= b2Body.e_islandFlag; | |
} | |
} | |
var subStep = b2World.s_timestep; | |
subStep.warmStarting = false; | |
subStep.dt = (1.0 - minTOI) * step.dt; | |
subStep.inv_dt = 1.0 / subStep.dt; | |
subStep.dtRatio = 0.0; | |
subStep.velocityIterations = step.velocityIterations; | |
subStep.positionIterations = step.positionIterations; | |
island.SolveTOI(subStep); | |
var i = 0; | |
for (i = 0; | |
i < island.m_bodyCount; ++i) { | |
b = island.m_bodies[i]; | |
b.m_flags &= ~b2Body.e_islandFlag; | |
if (b.IsAwake() == false) { | |
continue; | |
} | |
if (b.GetType() != b2Body.b2_dynamicBody) { | |
continue; | |
} | |
b.SynchronizeFixtures(); | |
for (cEdge = b.m_contactList; | |
cEdge; cEdge = cEdge.next) { | |
cEdge.contact.m_flags &= ~b2Contact.e_toiFlag; | |
} | |
} | |
for (i = 0; | |
i < island.m_contactCount; ++i) { | |
c = island.m_contacts[i]; | |
c.m_flags &= ~ (b2Contact.e_toiFlag | b2Contact.e_islandFlag); | |
} | |
for (i = 0; | |
i < island.m_jointCount; ++i) { | |
j = island.m_joints[i]; | |
j.m_islandFlag = false; | |
} | |
this.m_contactManager.FindNewContacts(); | |
} | |
} | |
b2World.prototype.DrawJoint = function (joint) { | |
var b1 = joint.GetBodyA(); | |
var b2 = joint.GetBodyB(); | |
var xf1 = b1.m_xf; | |
var xf2 = b2.m_xf; | |
var x1 = xf1.position; | |
var x2 = xf2.position; | |
var p1 = joint.GetAnchorA(); | |
var p2 = joint.GetAnchorB(); | |
var color = b2World.s_jointColor; | |
switch (joint.m_type) { | |
case b2Joint.e_distanceJoint: | |
this.m_debugDraw.DrawSegment(p1, p2, color); | |
break; | |
case b2Joint.e_pulleyJoint: | |
{ | |
var pulley = ((joint instanceof b2PulleyJoint ? joint : null)); | |
var s1 = pulley.GetGroundAnchorA(); | |
var s2 = pulley.GetGroundAnchorB(); | |
this.m_debugDraw.DrawSegment(s1, p1, color); | |
this.m_debugDraw.DrawSegment(s2, p2, color); | |
this.m_debugDraw.DrawSegment(s1, s2, color); | |
} | |
break; | |
case b2Joint.e_mouseJoint: | |
this.m_debugDraw.DrawSegment(p1, p2, color); | |
break; | |
default: | |
if (b1 != this.m_groundBody) this.m_debugDraw.DrawSegment(x1, p1, color); | |
this.m_debugDraw.DrawSegment(p1, p2, color); | |
if (b2 != this.m_groundBody) this.m_debugDraw.DrawSegment(x2, p2, color); | |
} | |
} | |
b2World.prototype.DrawShape = function (shape, xf, color) { | |
switch (shape.m_type) { | |
case b2Shape.e_circleShape: | |
{ | |
var circle = ((shape instanceof b2CircleShape ? shape : null)); | |
var center = b2Math.MulX(xf, circle.m_p); | |
var radius = circle.m_radius; | |
var axis = xf.R.col1; | |
this.m_debugDraw.DrawSolidCircle(center, radius, axis, color); | |
} | |
break; | |
case b2Shape.e_polygonShape: | |
{ | |
var i = 0; | |
var poly = ((shape instanceof b2PolygonShape ? shape : null)); | |
var vertexCount = parseInt(poly.GetVertexCount()); | |
var localVertices = poly.GetVertices(); | |
var vertices = new Vector(vertexCount); | |
for (i = 0; | |
i < vertexCount; ++i) { | |
vertices[i] = b2Math.MulX(xf, localVertices[i]); | |
} | |
this.m_debugDraw.DrawSolidPolygon(vertices, vertexCount, color); | |
} | |
break; | |
case b2Shape.e_edgeShape: | |
{ | |
var edge = (shape instanceof b2EdgeShape ? shape : null); | |
this.m_debugDraw.DrawSegment(b2Math.MulX(xf, edge.GetVertex1()), b2Math.MulX(xf, edge.GetVertex2()), color); | |
} | |
break; | |
} | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Dynamics.b2World.s_timestep2 = new b2TimeStep(); | |
Box2D.Dynamics.b2World.s_xf = new b2Transform(); | |
Box2D.Dynamics.b2World.s_backupA = new b2Sweep(); | |
Box2D.Dynamics.b2World.s_backupB = new b2Sweep(); | |
Box2D.Dynamics.b2World.s_timestep = new b2TimeStep(); | |
Box2D.Dynamics.b2World.s_queue = new Vector(); | |
Box2D.Dynamics.b2World.s_jointColor = new b2Color(0.5, 0.8, 0.8); | |
Box2D.Dynamics.b2World.e_newFixture = 0x0001; | |
Box2D.Dynamics.b2World.e_locked = 0x0002; | |
}); | |
})(); | |
(function () { | |
var b2CircleShape = Box2D.Collision.Shapes.b2CircleShape, | |
b2EdgeChainDef = Box2D.Collision.Shapes.b2EdgeChainDef, | |
b2EdgeShape = Box2D.Collision.Shapes.b2EdgeShape, | |
b2MassData = Box2D.Collision.Shapes.b2MassData, | |
b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape, | |
b2Shape = Box2D.Collision.Shapes.b2Shape, | |
b2CircleContact = Box2D.Dynamics.Contacts.b2CircleContact, | |
b2Contact = Box2D.Dynamics.Contacts.b2Contact, | |
b2ContactConstraint = Box2D.Dynamics.Contacts.b2ContactConstraint, | |
b2ContactConstraintPoint = Box2D.Dynamics.Contacts.b2ContactConstraintPoint, | |
b2ContactEdge = Box2D.Dynamics.Contacts.b2ContactEdge, | |
b2ContactFactory = Box2D.Dynamics.Contacts.b2ContactFactory, | |
b2ContactRegister = Box2D.Dynamics.Contacts.b2ContactRegister, | |
b2ContactResult = Box2D.Dynamics.Contacts.b2ContactResult, | |
b2ContactSolver = Box2D.Dynamics.Contacts.b2ContactSolver, | |
b2EdgeAndCircleContact = Box2D.Dynamics.Contacts.b2EdgeAndCircleContact, | |
b2NullContact = Box2D.Dynamics.Contacts.b2NullContact, | |
b2PolyAndCircleContact = Box2D.Dynamics.Contacts.b2PolyAndCircleContact, | |
b2PolyAndEdgeContact = Box2D.Dynamics.Contacts.b2PolyAndEdgeContact, | |
b2PolygonContact = Box2D.Dynamics.Contacts.b2PolygonContact, | |
b2PositionSolverManifold = Box2D.Dynamics.Contacts.b2PositionSolverManifold, | |
b2Body = Box2D.Dynamics.b2Body, | |
b2BodyDef = Box2D.Dynamics.b2BodyDef, | |
b2ContactFilter = Box2D.Dynamics.b2ContactFilter, | |
b2ContactImpulse = Box2D.Dynamics.b2ContactImpulse, | |
b2ContactListener = Box2D.Dynamics.b2ContactListener, | |
b2ContactManager = Box2D.Dynamics.b2ContactManager, | |
b2DebugDraw = Box2D.Dynamics.b2DebugDraw, | |
b2DestructionListener = Box2D.Dynamics.b2DestructionListener, | |
b2FilterData = Box2D.Dynamics.b2FilterData, | |
b2Fixture = Box2D.Dynamics.b2Fixture, | |
b2FixtureDef = Box2D.Dynamics.b2FixtureDef, | |
b2Island = Box2D.Dynamics.b2Island, | |
b2TimeStep = Box2D.Dynamics.b2TimeStep, | |
b2World = Box2D.Dynamics.b2World, | |
b2Color = Box2D.Common.b2Color, | |
b2internal = Box2D.Common.b2internal, | |
b2Settings = Box2D.Common.b2Settings, | |
b2Mat22 = Box2D.Common.Math.b2Mat22, | |
b2Mat33 = Box2D.Common.Math.b2Mat33, | |
b2Math = Box2D.Common.Math.b2Math, | |
b2Sweep = Box2D.Common.Math.b2Sweep, | |
b2Transform = Box2D.Common.Math.b2Transform, | |
b2Vec2 = Box2D.Common.Math.b2Vec2, | |
b2Vec3 = Box2D.Common.Math.b2Vec3, | |
b2AABB = Box2D.Collision.b2AABB, | |
b2Bound = Box2D.Collision.b2Bound, | |
b2BoundValues = Box2D.Collision.b2BoundValues, | |
b2Collision = Box2D.Collision.b2Collision, | |
b2ContactID = Box2D.Collision.b2ContactID, | |
b2ContactPoint = Box2D.Collision.b2ContactPoint, | |
b2Distance = Box2D.Collision.b2Distance, | |
b2DistanceInput = Box2D.Collision.b2DistanceInput, | |
b2DistanceOutput = Box2D.Collision.b2DistanceOutput, | |
b2DistanceProxy = Box2D.Collision.b2DistanceProxy, | |
b2DynamicTree = Box2D.Collision.b2DynamicTree, | |
b2DynamicTreeBroadPhase = Box2D.Collision.b2DynamicTreeBroadPhase, | |
b2DynamicTreeNode = Box2D.Collision.b2DynamicTreeNode, | |
b2DynamicTreePair = Box2D.Collision.b2DynamicTreePair, | |
b2Manifold = Box2D.Collision.b2Manifold, | |
b2ManifoldPoint = Box2D.Collision.b2ManifoldPoint, | |
b2Point = Box2D.Collision.b2Point, | |
b2RayCastInput = Box2D.Collision.b2RayCastInput, | |
b2RayCastOutput = Box2D.Collision.b2RayCastOutput, | |
b2Segment = Box2D.Collision.b2Segment, | |
b2SeparationFunction = Box2D.Collision.b2SeparationFunction, | |
b2Simplex = Box2D.Collision.b2Simplex, | |
b2SimplexCache = Box2D.Collision.b2SimplexCache, | |
b2SimplexVertex = Box2D.Collision.b2SimplexVertex, | |
b2TimeOfImpact = Box2D.Collision.b2TimeOfImpact, | |
b2TOIInput = Box2D.Collision.b2TOIInput, | |
b2WorldManifold = Box2D.Collision.b2WorldManifold, | |
ClipVertex = Box2D.Collision.ClipVertex, | |
Features = Box2D.Collision.Features, | |
IBroadPhase = Box2D.Collision.IBroadPhase; | |
Box2D.inherit(b2CircleContact, Box2D.Dynamics.Contacts.b2Contact); | |
b2CircleContact.prototype.__super = Box2D.Dynamics.Contacts.b2Contact.prototype; | |
b2CircleContact.b2CircleContact = function () { | |
Box2D.Dynamics.Contacts.b2Contact.b2Contact.apply(this, arguments); | |
}; | |
b2CircleContact.Create = function (allocator) { | |
return new b2CircleContact(); | |
} | |
b2CircleContact.Destroy = function (contact, allocator) {} | |
b2CircleContact.prototype.Reset = function (fixtureA, fixtureB) { | |
this.__super.Reset.call(this, fixtureA, fixtureB); | |
} | |
b2CircleContact.prototype.Evaluate = function () { | |
var bA = this.m_fixtureA.GetBody(); | |
var bB = this.m_fixtureB.GetBody(); | |
b2Collision.CollideCircles(this.m_manifold, (this.m_fixtureA.GetShape() instanceof b2CircleShape ? this.m_fixtureA.GetShape() : null), bA.m_xf, (this.m_fixtureB.GetShape() instanceof b2CircleShape ? this.m_fixtureB.GetShape() : null), bB.m_xf); | |
} | |
b2Contact.b2Contact = function () { | |
this.m_nodeA = new b2ContactEdge(); | |
this.m_nodeB = new b2ContactEdge(); | |
this.m_manifold = new b2Manifold(); | |
this.m_oldManifold = new b2Manifold(); | |
}; | |
b2Contact.prototype.GetManifold = function () { | |
return this.m_manifold; | |
} | |
b2Contact.prototype.GetWorldManifold = function (worldManifold) { | |
var bodyA = this.m_fixtureA.GetBody(); | |
var bodyB = this.m_fixtureB.GetBody(); | |
var shapeA = this.m_fixtureA.GetShape(); | |
var shapeB = this.m_fixtureB.GetShape(); | |
worldManifold.Initialize(this.m_manifold, bodyA.GetTransform(), shapeA.m_radius, bodyB.GetTransform(), shapeB.m_radius); | |
} | |
b2Contact.prototype.IsTouching = function () { | |
return (this.m_flags & b2Contact.e_touchingFlag) == b2Contact.e_touchingFlag; | |
} | |
b2Contact.prototype.IsContinuous = function () { | |
return (this.m_flags & b2Contact.e_continuousFlag) == b2Contact.e_continuousFlag; | |
} | |
b2Contact.prototype.SetSensor = function (sensor) { | |
if (sensor) { | |
this.m_flags |= b2Contact.e_sensorFlag; | |
} | |
else { | |
this.m_flags &= ~b2Contact.e_sensorFlag; | |
} | |
} | |
b2Contact.prototype.IsSensor = function () { | |
return (this.m_flags & b2Contact.e_sensorFlag) == b2Contact.e_sensorFlag; | |
} | |
b2Contact.prototype.SetEnabled = function (flag) { | |
if (flag) { | |
this.m_flags |= b2Contact.e_enabledFlag; | |
} | |
else { | |
this.m_flags &= ~b2Contact.e_enabledFlag; | |
} | |
} | |
b2Contact.prototype.IsEnabled = function () { | |
return (this.m_flags & b2Contact.e_enabledFlag) == b2Contact.e_enabledFlag; | |
} | |
b2Contact.prototype.GetNext = function () { | |
return this.m_next; | |
} | |
b2Contact.prototype.GetFixtureA = function () { | |
return this.m_fixtureA; | |
} | |
b2Contact.prototype.GetFixtureB = function () { | |
return this.m_fixtureB; | |
} | |
b2Contact.prototype.FlagForFiltering = function () { | |
this.m_flags |= b2Contact.e_filterFlag; | |
} | |
b2Contact.prototype.b2Contact = function () {} | |
b2Contact.prototype.Reset = function (fixtureA, fixtureB) { | |
if (fixtureA === undefined) fixtureA = null; | |
if (fixtureB === undefined) fixtureB = null; | |
this.m_flags = b2Contact.e_enabledFlag; | |
if (!fixtureA || !fixtureB) { | |
this.m_fixtureA = null; | |
this.m_fixtureB = null; | |
return; | |
} | |
if (fixtureA.IsSensor() || fixtureB.IsSensor()) { | |
this.m_flags |= b2Contact.e_sensorFlag; | |
} | |
var bodyA = fixtureA.GetBody(); | |
var bodyB = fixtureB.GetBody(); | |
if (bodyA.GetType() != b2Body.b2_dynamicBody || bodyA.IsBullet() || bodyB.GetType() != b2Body.b2_dynamicBody || bodyB.IsBullet()) { | |
this.m_flags |= b2Contact.e_continuousFlag; | |
} | |
this.m_fixtureA = fixtureA; | |
this.m_fixtureB = fixtureB; | |
this.m_manifold.m_pointCount = 0; | |
this.m_prev = null; | |
this.m_next = null; | |
this.m_nodeA.contact = null; | |
this.m_nodeA.prev = null; | |
this.m_nodeA.next = null; | |
this.m_nodeA.other = null; | |
this.m_nodeB.contact = null; | |
this.m_nodeB.prev = null; | |
this.m_nodeB.next = null; | |
this.m_nodeB.other = null; | |
} | |
b2Contact.prototype.Update = function (listener) { | |
var tManifold = this.m_oldManifold; | |
this.m_oldManifold = this.m_manifold; | |
this.m_manifold = tManifold; | |
this.m_flags |= b2Contact.e_enabledFlag; | |
var touching = false; | |
var wasTouching = (this.m_flags & b2Contact.e_touchingFlag) == b2Contact.e_touchingFlag; | |
var bodyA = this.m_fixtureA.m_body; | |
var bodyB = this.m_fixtureB.m_body; | |
var aabbOverlap = this.m_fixtureA.m_aabb.TestOverlap(this.m_fixtureB.m_aabb); | |
if (this.m_flags & b2Contact.e_sensorFlag) { | |
if (aabbOverlap) { | |
var shapeA = this.m_fixtureA.GetShape(); | |
var shapeB = this.m_fixtureB.GetShape(); | |
var xfA = bodyA.GetTransform(); | |
var xfB = bodyB.GetTransform(); | |
touching = b2Shape.TestOverlap(shapeA, xfA, shapeB, xfB); | |
} | |
this.m_manifold.m_pointCount = 0; | |
} | |
else { | |
if (bodyA.GetType() != b2Body.b2_dynamicBody || bodyA.IsBullet() || bodyB.GetType() != b2Body.b2_dynamicBody || bodyB.IsBullet()) { | |
this.m_flags |= b2Contact.e_continuousFlag; | |
} | |
else { | |
this.m_flags &= ~b2Contact.e_continuousFlag; | |
} | |
if (aabbOverlap) { | |
this.Evaluate(); | |
touching = this.m_manifold.m_pointCount > 0; | |
for (var i = 0; i < this.m_manifold.m_pointCount; ++i) { | |
var mp2 = this.m_manifold.m_points[i]; | |
mp2.m_normalImpulse = 0.0; | |
mp2.m_tangentImpulse = 0.0; | |
var id2 = mp2.m_id; | |
for (var j = 0; j < this.m_oldManifold.m_pointCount; ++j) { | |
var mp1 = this.m_oldManifold.m_points[j]; | |
if (mp1.m_id.key == id2.key) { | |
mp2.m_normalImpulse = mp1.m_normalImpulse; | |
mp2.m_tangentImpulse = mp1.m_tangentImpulse; | |
break; | |
} | |
} | |
} | |
} | |
else { | |
this.m_manifold.m_pointCount = 0; | |
} | |
if (touching != wasTouching) { | |
bodyA.SetAwake(true); | |
bodyB.SetAwake(true); | |
} | |
} | |
if (touching) { | |
this.m_flags |= b2Contact.e_touchingFlag; | |
} | |
else { | |
this.m_flags &= ~b2Contact.e_touchingFlag; | |
} | |
if (wasTouching == false && touching == true) { | |
listener.BeginContact(this); | |
} | |
if (wasTouching == true && touching == false) { | |
listener.EndContact(this); | |
} | |
if ((this.m_flags & b2Contact.e_sensorFlag) == 0) { | |
listener.PreSolve(this, this.m_oldManifold); | |
} | |
} | |
b2Contact.prototype.Evaluate = function () {} | |
b2Contact.prototype.ComputeTOI = function (sweepA, sweepB) { | |
b2Contact.s_input.proxyA.Set(this.m_fixtureA.GetShape()); | |
b2Contact.s_input.proxyB.Set(this.m_fixtureB.GetShape()); | |
b2Contact.s_input.sweepA = sweepA; | |
b2Contact.s_input.sweepB = sweepB; | |
b2Contact.s_input.tolerance = b2Settings.b2_linearSlop; | |
return b2TimeOfImpact.TimeOfImpact(b2Contact.s_input); | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Dynamics.Contacts.b2Contact.e_sensorFlag = 0x0001; | |
Box2D.Dynamics.Contacts.b2Contact.e_continuousFlag = 0x0002; | |
Box2D.Dynamics.Contacts.b2Contact.e_islandFlag = 0x0004; | |
Box2D.Dynamics.Contacts.b2Contact.e_toiFlag = 0x0008; | |
Box2D.Dynamics.Contacts.b2Contact.e_touchingFlag = 0x0010; | |
Box2D.Dynamics.Contacts.b2Contact.e_enabledFlag = 0x0020; | |
Box2D.Dynamics.Contacts.b2Contact.e_filterFlag = 0x0040; | |
Box2D.Dynamics.Contacts.b2Contact.s_input = new b2TOIInput(); | |
}); | |
b2ContactConstraint.b2ContactConstraint = function () { | |
this.localPlaneNormal = new b2Vec2(); | |
this.localPoint = new b2Vec2(); | |
this.normal = new b2Vec2(); | |
this.normalMass = new b2Mat22(); | |
this.K = new b2Mat22(); | |
}; | |
b2ContactConstraint.prototype.b2ContactConstraint = function () { | |
this.points = new Vector(b2Settings.b2_maxManifoldPoints); | |
for (var i = 0; i < b2Settings.b2_maxManifoldPoints; i++) { | |
this.points[i] = new b2ContactConstraintPoint(); | |
} | |
} | |
b2ContactConstraintPoint.b2ContactConstraintPoint = function () { | |
this.localPoint = new b2Vec2(); | |
this.rA = new b2Vec2(); | |
this.rB = new b2Vec2(); | |
}; | |
b2ContactEdge.b2ContactEdge = function () {}; | |
b2ContactFactory.b2ContactFactory = function () {}; | |
b2ContactFactory.prototype.b2ContactFactory = function (allocator) { | |
this.m_allocator = allocator; | |
this.InitializeRegisters(); | |
} | |
b2ContactFactory.prototype.AddType = function (createFcn, destroyFcn, type1, type2) { | |
if (type1 === undefined) type1 = 0; | |
if (type2 === undefined) type2 = 0; | |
this.m_registers[type1][type2].createFcn = createFcn; | |
this.m_registers[type1][type2].destroyFcn = destroyFcn; | |
this.m_registers[type1][type2].primary = true; | |
if (type1 != type2) { | |
this.m_registers[type2][type1].createFcn = createFcn; | |
this.m_registers[type2][type1].destroyFcn = destroyFcn; | |
this.m_registers[type2][type1].primary = false; | |
} | |
} | |
b2ContactFactory.prototype.InitializeRegisters = function () { | |
this.m_registers = new Vector(b2Shape.e_shapeTypeCount); | |
for (var i = 0; i < b2Shape.e_shapeTypeCount; i++) { | |
this.m_registers[i] = new Vector(b2Shape.e_shapeTypeCount); | |
for (var j = 0; j < b2Shape.e_shapeTypeCount; j++) { | |
this.m_registers[i][j] = new b2ContactRegister(); | |
} | |
} | |
this.AddType(b2CircleContact.Create, b2CircleContact.Destroy, b2Shape.e_circleShape, b2Shape.e_circleShape); | |
this.AddType(b2PolyAndCircleContact.Create, b2PolyAndCircleContact.Destroy, b2Shape.e_polygonShape, b2Shape.e_circleShape); | |
this.AddType(b2PolygonContact.Create, b2PolygonContact.Destroy, b2Shape.e_polygonShape, b2Shape.e_polygonShape); | |
this.AddType(b2EdgeAndCircleContact.Create, b2EdgeAndCircleContact.Destroy, b2Shape.e_edgeShape, b2Shape.e_circleShape); | |
this.AddType(b2PolyAndEdgeContact.Create, b2PolyAndEdgeContact.Destroy, b2Shape.e_polygonShape, b2Shape.e_edgeShape); | |
} | |
b2ContactFactory.prototype.Create = function (fixtureA, fixtureB) { | |
var type1 = parseInt(fixtureA.GetType()); | |
var type2 = parseInt(fixtureB.GetType()); | |
var reg = this.m_registers[type1][type2]; | |
var c; | |
if (reg.pool) { | |
c = reg.pool; | |
reg.pool = c.m_next; | |
reg.poolCount--; | |
c.Reset(fixtureA, fixtureB); | |
return c; | |
} | |
var createFcn = reg.createFcn; | |
if (createFcn != null) { | |
if (reg.primary) { | |
c = createFcn(this.m_allocator); | |
c.Reset(fixtureA, fixtureB); | |
return c; | |
} | |
else { | |
c = createFcn(this.m_allocator); | |
c.Reset(fixtureB, fixtureA); | |
return c; | |
} | |
} | |
else { | |
return null; | |
} | |
} | |
b2ContactFactory.prototype.Destroy = function (contact) { | |
if (contact.m_manifold.m_pointCount > 0) { | |
contact.m_fixtureA.m_body.SetAwake(true); | |
contact.m_fixtureB.m_body.SetAwake(true); | |
} | |
var type1 = parseInt(contact.m_fixtureA.GetType()); | |
var type2 = parseInt(contact.m_fixtureB.GetType()); | |
var reg = this.m_registers[type1][type2]; | |
if (true) { | |
reg.poolCount++; | |
contact.m_next = reg.pool; | |
reg.pool = contact; | |
} | |
var destroyFcn = reg.destroyFcn; | |
destroyFcn(contact, this.m_allocator); | |
} | |
b2ContactRegister.b2ContactRegister = function () {}; | |
b2ContactResult.b2ContactResult = function () { | |
this.position = new b2Vec2(); | |
this.normal = new b2Vec2(); | |
this.id = new b2ContactID(); | |
}; | |
b2ContactSolver.b2ContactSolver = function () { | |
this.m_step = new b2TimeStep(); | |
this.m_constraints = new Vector(); | |
}; | |
b2ContactSolver.prototype.b2ContactSolver = function () {} | |
b2ContactSolver.prototype.Initialize = function (step, contacts, contactCount, allocator) { | |
if (contactCount === undefined) contactCount = 0; | |
var contact; | |
this.m_step.Set(step); | |
this.m_allocator = allocator; | |
var i = 0; | |
var tVec; | |
var tMat; | |
this.m_constraintCount = contactCount; | |
while (this.m_constraints.length < this.m_constraintCount) { | |
this.m_constraints[this.m_constraints.length] = new b2ContactConstraint(); | |
} | |
for (i = 0; | |
i < contactCount; ++i) { | |
contact = contacts[i]; | |
var fixtureA = contact.m_fixtureA; | |
var fixtureB = contact.m_fixtureB; | |
var shapeA = fixtureA.m_shape; | |
var shapeB = fixtureB.m_shape; | |
var radiusA = shapeA.m_radius; | |
var radiusB = shapeB.m_radius; | |
var bodyA = fixtureA.m_body; | |
var bodyB = fixtureB.m_body; | |
var manifold = contact.GetManifold(); | |
var friction = b2Settings.b2MixFriction(fixtureA.GetFriction(), fixtureB.GetFriction()); | |
var restitution = b2Settings.b2MixRestitution(fixtureA.GetRestitution(), fixtureB.GetRestitution()); | |
var vAX = bodyA.m_linearVelocity.x; | |
var vAY = bodyA.m_linearVelocity.y; | |
var vBX = bodyB.m_linearVelocity.x; | |
var vBY = bodyB.m_linearVelocity.y; | |
var wA = bodyA.m_angularVelocity; | |
var wB = bodyB.m_angularVelocity; | |
b2Settings.b2Assert(manifold.m_pointCount > 0); | |
b2ContactSolver.s_worldManifold.Initialize(manifold, bodyA.m_xf, radiusA, bodyB.m_xf, radiusB); | |
var normalX = b2ContactSolver.s_worldManifold.m_normal.x; | |
var normalY = b2ContactSolver.s_worldManifold.m_normal.y; | |
var cc = this.m_constraints[i]; | |
cc.bodyA = bodyA; | |
cc.bodyB = bodyB; | |
cc.manifold = manifold; | |
cc.normal.x = normalX; | |
cc.normal.y = normalY; | |
cc.pointCount = manifold.m_pointCount; | |
cc.friction = friction; | |
cc.restitution = restitution; | |
cc.localPlaneNormal.x = manifold.m_localPlaneNormal.x; | |
cc.localPlaneNormal.y = manifold.m_localPlaneNormal.y; | |
cc.localPoint.x = manifold.m_localPoint.x; | |
cc.localPoint.y = manifold.m_localPoint.y; | |
cc.radius = radiusA + radiusB; | |
cc.type = manifold.m_type; | |
for (var k = 0; k < cc.pointCount; ++k) { | |
var cp = manifold.m_points[k]; | |
var ccp = cc.points[k]; | |
ccp.normalImpulse = cp.m_normalImpulse; | |
ccp.tangentImpulse = cp.m_tangentImpulse; | |
ccp.localPoint.SetV(cp.m_localPoint); | |
var rAX = ccp.rA.x = b2ContactSolver.s_worldManifold.m_points[k].x - bodyA.m_sweep.c.x; | |
var rAY = ccp.rA.y = b2ContactSolver.s_worldManifold.m_points[k].y - bodyA.m_sweep.c.y; | |
var rBX = ccp.rB.x = b2ContactSolver.s_worldManifold.m_points[k].x - bodyB.m_sweep.c.x; | |
var rBY = ccp.rB.y = b2ContactSolver.s_worldManifold.m_points[k].y - bodyB.m_sweep.c.y; | |
var rnA = rAX * normalY - rAY * normalX; | |
var rnB = rBX * normalY - rBY * normalX; | |
rnA *= rnA; | |
rnB *= rnB; | |
var kNormal = bodyA.m_invMass + bodyB.m_invMass + bodyA.m_invI * rnA + bodyB.m_invI * rnB; | |
ccp.normalMass = 1.0 / kNormal; | |
var kEqualized = bodyA.m_mass * bodyA.m_invMass + bodyB.m_mass * bodyB.m_invMass; | |
kEqualized += bodyA.m_mass * bodyA.m_invI * rnA + bodyB.m_mass * bodyB.m_invI * rnB; | |
ccp.equalizedMass = 1.0 / kEqualized; | |
var tangentX = normalY; | |
var tangentY = (-normalX); | |
var rtA = rAX * tangentY - rAY * tangentX; | |
var rtB = rBX * tangentY - rBY * tangentX; | |
rtA *= rtA; | |
rtB *= rtB; | |
var kTangent = bodyA.m_invMass + bodyB.m_invMass + bodyA.m_invI * rtA + bodyB.m_invI * rtB; | |
ccp.tangentMass = 1.0 / kTangent; | |
ccp.velocityBias = 0.0; | |
var tX = vBX + ((-wB * rBY)) - vAX - ((-wA * rAY)); | |
var tY = vBY + (wB * rBX) - vAY - (wA * rAX); | |
var vRel = cc.normal.x * tX + cc.normal.y * tY; | |
if (vRel < (-b2Settings.b2_velocityThreshold)) { | |
ccp.velocityBias += (-cc.restitution * vRel); | |
} | |
} | |
if (cc.pointCount == 2) { | |
var ccp1 = cc.points[0]; | |
var ccp2 = cc.points[1]; | |
var invMassA = bodyA.m_invMass; | |
var invIA = bodyA.m_invI; | |
var invMassB = bodyB.m_invMass; | |
var invIB = bodyB.m_invI; | |
var rn1A = ccp1.rA.x * normalY - ccp1.rA.y * normalX; | |
var rn1B = ccp1.rB.x * normalY - ccp1.rB.y * normalX; | |
var rn2A = ccp2.rA.x * normalY - ccp2.rA.y * normalX; | |
var rn2B = ccp2.rB.x * normalY - ccp2.rB.y * normalX; | |
var k11 = invMassA + invMassB + invIA * rn1A * rn1A + invIB * rn1B * rn1B; | |
var k22 = invMassA + invMassB + invIA * rn2A * rn2A + invIB * rn2B * rn2B; | |
var k12 = invMassA + invMassB + invIA * rn1A * rn2A + invIB * rn1B * rn2B; | |
var k_maxConditionNumber = 100.0; | |
if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12)) { | |
cc.K.col1.Set(k11, k12); | |
cc.K.col2.Set(k12, k22); | |
cc.K.GetInverse(cc.normalMass); | |
} | |
else { | |
cc.pointCount = 1; | |
} | |
} | |
} | |
} | |
b2ContactSolver.prototype.InitVelocityConstraints = function (step) { | |
var tVec; | |
var tVec2; | |
var tMat; | |
for (var i = 0; i < this.m_constraintCount; ++i) { | |
var c = this.m_constraints[i]; | |
var bodyA = c.bodyA; | |
var bodyB = c.bodyB; | |
var invMassA = bodyA.m_invMass; | |
var invIA = bodyA.m_invI; | |
var invMassB = bodyB.m_invMass; | |
var invIB = bodyB.m_invI; | |
var normalX = c.normal.x; | |
var normalY = c.normal.y; | |
var tangentX = normalY; | |
var tangentY = (-normalX); | |
var tX = 0; | |
var j = 0; | |
var tCount = 0; | |
if (step.warmStarting) { | |
tCount = c.pointCount; | |
for (j = 0; | |
j < tCount; ++j) { | |
var ccp = c.points[j]; | |
ccp.normalImpulse *= step.dtRatio; | |
ccp.tangentImpulse *= step.dtRatio; | |
var PX = ccp.normalImpulse * normalX + ccp.tangentImpulse * tangentX; | |
var PY = ccp.normalImpulse * normalY + ccp.tangentImpulse * tangentY; | |
bodyA.m_angularVelocity -= invIA * (ccp.rA.x * PY - ccp.rA.y * PX); | |
bodyA.m_linearVelocity.x -= invMassA * PX; | |
bodyA.m_linearVelocity.y -= invMassA * PY; | |
bodyB.m_angularVelocity += invIB * (ccp.rB.x * PY - ccp.rB.y * PX); | |
bodyB.m_linearVelocity.x += invMassB * PX; | |
bodyB.m_linearVelocity.y += invMassB * PY; | |
} | |
} | |
else { | |
tCount = c.pointCount; | |
for (j = 0; | |
j < tCount; ++j) { | |
var ccp2 = c.points[j]; | |
ccp2.normalImpulse = 0.0; | |
ccp2.tangentImpulse = 0.0; | |
} | |
} | |
} | |
} | |
b2ContactSolver.prototype.SolveVelocityConstraints = function () { | |
var j = 0; | |
var ccp; | |
var rAX = 0; | |
var rAY = 0; | |
var rBX = 0; | |
var rBY = 0; | |
var dvX = 0; | |
var dvY = 0; | |
var vn = 0; | |
var vt = 0; | |
var lambda = 0; | |
var maxFriction = 0; | |
var newImpulse = 0; | |
var PX = 0; | |
var PY = 0; | |
var dX = 0; | |
var dY = 0; | |
var P1X = 0; | |
var P1Y = 0; | |
var P2X = 0; | |
var P2Y = 0; | |
var tMat; | |
var tVec; | |
for (var i = 0; i < this.m_constraintCount; ++i) { | |
var c = this.m_constraints[i]; | |
var bodyA = c.bodyA; | |
var bodyB = c.bodyB; | |
var wA = bodyA.m_angularVelocity; | |
var wB = bodyB.m_angularVelocity; | |
var vA = bodyA.m_linearVelocity; | |
var vB = bodyB.m_linearVelocity; | |
var invMassA = bodyA.m_invMass; | |
var invIA = bodyA.m_invI; | |
var invMassB = bodyB.m_invMass; | |
var invIB = bodyB.m_invI; | |
var normalX = c.normal.x; | |
var normalY = c.normal.y; | |
var tangentX = normalY; | |
var tangentY = (-normalX); | |
var friction = c.friction; | |
var tX = 0; | |
for (j = 0; | |
j < c.pointCount; j++) { | |
ccp = c.points[j]; | |
dvX = vB.x - wB * ccp.rB.y - vA.x + wA * ccp.rA.y; | |
dvY = vB.y + wB * ccp.rB.x - vA.y - wA * ccp.rA.x; | |
vt = dvX * tangentX + dvY * tangentY; | |
lambda = ccp.tangentMass * (-vt); | |
maxFriction = friction * ccp.normalImpulse; | |
newImpulse = b2Math.Clamp(ccp.tangentImpulse + lambda, (-maxFriction), maxFriction); | |
lambda = newImpulse - ccp.tangentImpulse; | |
PX = lambda * tangentX; | |
PY = lambda * tangentY; | |
vA.x -= invMassA * PX; | |
vA.y -= invMassA * PY; | |
wA -= invIA * (ccp.rA.x * PY - ccp.rA.y * PX); | |
vB.x += invMassB * PX; | |
vB.y += invMassB * PY; | |
wB += invIB * (ccp.rB.x * PY - ccp.rB.y * PX); | |
ccp.tangentImpulse = newImpulse; | |
} | |
var tCount = parseInt(c.pointCount); | |
if (c.pointCount == 1) { | |
ccp = c.points[0]; | |
dvX = vB.x + ((-wB * ccp.rB.y)) - vA.x - ((-wA * ccp.rA.y)); | |
dvY = vB.y + (wB * ccp.rB.x) - vA.y - (wA * ccp.rA.x); | |
vn = dvX * normalX + dvY * normalY; | |
lambda = (-ccp.normalMass * (vn - ccp.velocityBias)); | |
newImpulse = ccp.normalImpulse + lambda; | |
newImpulse = newImpulse > 0 ? newImpulse : 0.0; | |
lambda = newImpulse - ccp.normalImpulse; | |
PX = lambda * normalX; | |
PY = lambda * normalY; | |
vA.x -= invMassA * PX; | |
vA.y -= invMassA * PY; | |
wA -= invIA * (ccp.rA.x * PY - ccp.rA.y * PX); | |
vB.x += invMassB * PX; | |
vB.y += invMassB * PY; | |
wB += invIB * (ccp.rB.x * PY - ccp.rB.y * PX); | |
ccp.normalImpulse = newImpulse; | |
} | |
else { | |
var cp1 = c.points[0]; | |
var cp2 = c.points[1]; | |
var aX = cp1.normalImpulse; | |
var aY = cp2.normalImpulse; | |
var dv1X = vB.x - wB * cp1.rB.y - vA.x + wA * cp1.rA.y; | |
var dv1Y = vB.y + wB * cp1.rB.x - vA.y - wA * cp1.rA.x; | |
var dv2X = vB.x - wB * cp2.rB.y - vA.x + wA * cp2.rA.y; | |
var dv2Y = vB.y + wB * cp2.rB.x - vA.y - wA * cp2.rA.x; | |
var vn1 = dv1X * normalX + dv1Y * normalY; | |
var vn2 = dv2X * normalX + dv2Y * normalY; | |
var bX = vn1 - cp1.velocityBias; | |
var bY = vn2 - cp2.velocityBias; | |
tMat = c.K; | |
bX -= tMat.col1.x * aX + tMat.col2.x * aY; | |
bY -= tMat.col1.y * aX + tMat.col2.y * aY; | |
var k_errorTol = 0.001; | |
for (;;) { | |
tMat = c.normalMass; | |
var xX = (-(tMat.col1.x * bX + tMat.col2.x * bY)); | |
var xY = (-(tMat.col1.y * bX + tMat.col2.y * bY)); | |
if (xX >= 0.0 && xY >= 0.0) { | |
dX = xX - aX; | |
dY = xY - aY; | |
P1X = dX * normalX; | |
P1Y = dX * normalY; | |
P2X = dY * normalX; | |
P2Y = dY * normalY; | |
vA.x -= invMassA * (P1X + P2X); | |
vA.y -= invMassA * (P1Y + P2Y); | |
wA -= invIA * (cp1.rA.x * P1Y - cp1.rA.y * P1X + cp2.rA.x * P2Y - cp2.rA.y * P2X); | |
vB.x += invMassB * (P1X + P2X); | |
vB.y += invMassB * (P1Y + P2Y); | |
wB += invIB * (cp1.rB.x * P1Y - cp1.rB.y * P1X + cp2.rB.x * P2Y - cp2.rB.y * P2X); | |
cp1.normalImpulse = xX; | |
cp2.normalImpulse = xY; | |
break; | |
} | |
xX = (-cp1.normalMass * bX); | |
xY = 0.0; | |
vn1 = 0.0; | |
vn2 = c.K.col1.y * xX + bY; | |
if (xX >= 0.0 && vn2 >= 0.0) { | |
dX = xX - aX; | |
dY = xY - aY; | |
P1X = dX * normalX; | |
P1Y = dX * normalY; | |
P2X = dY * normalX; | |
P2Y = dY * normalY; | |
vA.x -= invMassA * (P1X + P2X); | |
vA.y -= invMassA * (P1Y + P2Y); | |
wA -= invIA * (cp1.rA.x * P1Y - cp1.rA.y * P1X + cp2.rA.x * P2Y - cp2.rA.y * P2X); | |
vB.x += invMassB * (P1X + P2X); | |
vB.y += invMassB * (P1Y + P2Y); | |
wB += invIB * (cp1.rB.x * P1Y - cp1.rB.y * P1X + cp2.rB.x * P2Y - cp2.rB.y * P2X); | |
cp1.normalImpulse = xX; | |
cp2.normalImpulse = xY; | |
break; | |
} | |
xX = 0.0; | |
xY = (-cp2.normalMass * bY); | |
vn1 = c.K.col2.x * xY + bX; | |
vn2 = 0.0; | |
if (xY >= 0.0 && vn1 >= 0.0) { | |
dX = xX - aX; | |
dY = xY - aY; | |
P1X = dX * normalX; | |
P1Y = dX * normalY; | |
P2X = dY * normalX; | |
P2Y = dY * normalY; | |
vA.x -= invMassA * (P1X + P2X); | |
vA.y -= invMassA * (P1Y + P2Y); | |
wA -= invIA * (cp1.rA.x * P1Y - cp1.rA.y * P1X + cp2.rA.x * P2Y - cp2.rA.y * P2X); | |
vB.x += invMassB * (P1X + P2X); | |
vB.y += invMassB * (P1Y + P2Y); | |
wB += invIB * (cp1.rB.x * P1Y - cp1.rB.y * P1X + cp2.rB.x * P2Y - cp2.rB.y * P2X); | |
cp1.normalImpulse = xX; | |
cp2.normalImpulse = xY; | |
break; | |
} | |
xX = 0.0; | |
xY = 0.0; | |
vn1 = bX; | |
vn2 = bY; | |
if (vn1 >= 0.0 && vn2 >= 0.0) { | |
dX = xX - aX; | |
dY = xY - aY; | |
P1X = dX * normalX; | |
P1Y = dX * normalY; | |
P2X = dY * normalX; | |
P2Y = dY * normalY; | |
vA.x -= invMassA * (P1X + P2X); | |
vA.y -= invMassA * (P1Y + P2Y); | |
wA -= invIA * (cp1.rA.x * P1Y - cp1.rA.y * P1X + cp2.rA.x * P2Y - cp2.rA.y * P2X); | |
vB.x += invMassB * (P1X + P2X); | |
vB.y += invMassB * (P1Y + P2Y); | |
wB += invIB * (cp1.rB.x * P1Y - cp1.rB.y * P1X + cp2.rB.x * P2Y - cp2.rB.y * P2X); | |
cp1.normalImpulse = xX; | |
cp2.normalImpulse = xY; | |
break; | |
} | |
break; | |
} | |
} | |
bodyA.m_angularVelocity = wA; | |
bodyB.m_angularVelocity = wB; | |
} | |
} | |
b2ContactSolver.prototype.FinalizeVelocityConstraints = function () { | |
for (var i = 0; i < this.m_constraintCount; ++i) { | |
var c = this.m_constraints[i]; | |
var m = c.manifold; | |
for (var j = 0; j < c.pointCount; ++j) { | |
var point1 = m.m_points[j]; | |
var point2 = c.points[j]; | |
point1.m_normalImpulse = point2.normalImpulse; | |
point1.m_tangentImpulse = point2.tangentImpulse; | |
} | |
} | |
} | |
b2ContactSolver.prototype.SolvePositionConstraints = function (baumgarte) { | |
if (baumgarte === undefined) baumgarte = 0; | |
var minSeparation = 0.0; | |
for (var i = 0; i < this.m_constraintCount; i++) { | |
var c = this.m_constraints[i]; | |
var bodyA = c.bodyA; | |
var bodyB = c.bodyB; | |
var invMassA = bodyA.m_mass * bodyA.m_invMass; | |
var invIA = bodyA.m_mass * bodyA.m_invI; | |
var invMassB = bodyB.m_mass * bodyB.m_invMass; | |
var invIB = bodyB.m_mass * bodyB.m_invI; | |
b2ContactSolver.s_psm.Initialize(c); | |
var normal = b2ContactSolver.s_psm.m_normal; | |
for (var j = 0; j < c.pointCount; j++) { | |
var ccp = c.points[j]; | |
var point = b2ContactSolver.s_psm.m_points[j]; | |
var separation = b2ContactSolver.s_psm.m_separations[j]; | |
var rAX = point.x - bodyA.m_sweep.c.x; | |
var rAY = point.y - bodyA.m_sweep.c.y; | |
var rBX = point.x - bodyB.m_sweep.c.x; | |
var rBY = point.y - bodyB.m_sweep.c.y; | |
minSeparation = minSeparation < separation ? minSeparation : separation; | |
var C = b2Math.Clamp(baumgarte * (separation + b2Settings.b2_linearSlop), (-b2Settings.b2_maxLinearCorrection), 0.0); | |
var impulse = (-ccp.equalizedMass * C); | |
var PX = impulse * normal.x; | |
var PY = impulse * normal.y;bodyA.m_sweep.c.x -= invMassA * PX; | |
bodyA.m_sweep.c.y -= invMassA * PY; | |
bodyA.m_sweep.a -= invIA * (rAX * PY - rAY * PX); | |
bodyA.SynchronizeTransform(); | |
bodyB.m_sweep.c.x += invMassB * PX; | |
bodyB.m_sweep.c.y += invMassB * PY; | |
bodyB.m_sweep.a += invIB * (rBX * PY - rBY * PX); | |
bodyB.SynchronizeTransform(); | |
} | |
} | |
return minSeparation > (-1.5 * b2Settings.b2_linearSlop); | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Dynamics.Contacts.b2ContactSolver.s_worldManifold = new b2WorldManifold(); | |
Box2D.Dynamics.Contacts.b2ContactSolver.s_psm = new b2PositionSolverManifold(); | |
}); | |
Box2D.inherit(b2EdgeAndCircleContact, Box2D.Dynamics.Contacts.b2Contact); | |
b2EdgeAndCircleContact.prototype.__super = Box2D.Dynamics.Contacts.b2Contact.prototype; | |
b2EdgeAndCircleContact.b2EdgeAndCircleContact = function () { | |
Box2D.Dynamics.Contacts.b2Contact.b2Contact.apply(this, arguments); | |
}; | |
b2EdgeAndCircleContact.Create = function (allocator) { | |
return new b2EdgeAndCircleContact(); | |
} | |
b2EdgeAndCircleContact.Destroy = function (contact, allocator) {} | |
b2EdgeAndCircleContact.prototype.Reset = function (fixtureA, fixtureB) { | |
this.__super.Reset.call(this, fixtureA, fixtureB); | |
} | |
b2EdgeAndCircleContact.prototype.Evaluate = function () { | |
var bA = this.m_fixtureA.GetBody(); | |
var bB = this.m_fixtureB.GetBody(); | |
this.b2CollideEdgeAndCircle(this.m_manifold, (this.m_fixtureA.GetShape() instanceof b2EdgeShape ? this.m_fixtureA.GetShape() : null), bA.m_xf, (this.m_fixtureB.GetShape() instanceof b2CircleShape ? this.m_fixtureB.GetShape() : null), bB.m_xf); | |
} | |
b2EdgeAndCircleContact.prototype.b2CollideEdgeAndCircle = function (manifold, edge, xf1, circle, xf2) {} | |
Box2D.inherit(b2NullContact, Box2D.Dynamics.Contacts.b2Contact); | |
b2NullContact.prototype.__super = Box2D.Dynamics.Contacts.b2Contact.prototype; | |
b2NullContact.b2NullContact = function () { | |
Box2D.Dynamics.Contacts.b2Contact.b2Contact.apply(this, arguments); | |
}; | |
b2NullContact.prototype.b2NullContact = function () { | |
this.__super.b2Contact.call(this); | |
} | |
b2NullContact.prototype.Evaluate = function () {} | |
Box2D.inherit(b2PolyAndCircleContact, Box2D.Dynamics.Contacts.b2Contact); | |
b2PolyAndCircleContact.prototype.__super = Box2D.Dynamics.Contacts.b2Contact.prototype; | |
b2PolyAndCircleContact.b2PolyAndCircleContact = function () { | |
Box2D.Dynamics.Contacts.b2Contact.b2Contact.apply(this, arguments); | |
}; | |
b2PolyAndCircleContact.Create = function (allocator) { | |
return new b2PolyAndCircleContact(); | |
} | |
b2PolyAndCircleContact.Destroy = function (contact, allocator) {} | |
b2PolyAndCircleContact.prototype.Reset = function (fixtureA, fixtureB) { | |
this.__super.Reset.call(this, fixtureA, fixtureB); | |
b2Settings.b2Assert(fixtureA.GetType() == b2Shape.e_polygonShape); | |
b2Settings.b2Assert(fixtureB.GetType() == b2Shape.e_circleShape); | |
} | |
b2PolyAndCircleContact.prototype.Evaluate = function () { | |
var bA = this.m_fixtureA.m_body; | |
var bB = this.m_fixtureB.m_body; | |
b2Collision.CollidePolygonAndCircle(this.m_manifold, (this.m_fixtureA.GetShape() instanceof b2PolygonShape ? this.m_fixtureA.GetShape() : null), bA.m_xf, (this.m_fixtureB.GetShape() instanceof b2CircleShape ? this.m_fixtureB.GetShape() : null), bB.m_xf); | |
} | |
Box2D.inherit(b2PolyAndEdgeContact, Box2D.Dynamics.Contacts.b2Contact); | |
b2PolyAndEdgeContact.prototype.__super = Box2D.Dynamics.Contacts.b2Contact.prototype; | |
b2PolyAndEdgeContact.b2PolyAndEdgeContact = function () { | |
Box2D.Dynamics.Contacts.b2Contact.b2Contact.apply(this, arguments); | |
}; | |
b2PolyAndEdgeContact.Create = function (allocator) { | |
return new b2PolyAndEdgeContact(); | |
} | |
b2PolyAndEdgeContact.Destroy = function (contact, allocator) {} | |
b2PolyAndEdgeContact.prototype.Reset = function (fixtureA, fixtureB) { | |
this.__super.Reset.call(this, fixtureA, fixtureB); | |
b2Settings.b2Assert(fixtureA.GetType() == b2Shape.e_polygonShape); | |
b2Settings.b2Assert(fixtureB.GetType() == b2Shape.e_edgeShape); | |
} | |
b2PolyAndEdgeContact.prototype.Evaluate = function () { | |
var bA = this.m_fixtureA.GetBody(); | |
var bB = this.m_fixtureB.GetBody(); | |
this.b2CollidePolyAndEdge(this.m_manifold, (this.m_fixtureA.GetShape() instanceof b2PolygonShape ? this.m_fixtureA.GetShape() : null), bA.m_xf, (this.m_fixtureB.GetShape() instanceof b2EdgeShape ? this.m_fixtureB.GetShape() : null), bB.m_xf); | |
} | |
b2PolyAndEdgeContact.prototype.b2CollidePolyAndEdge = function (manifold, polygon, xf1, edge, xf2) {} | |
Box2D.inherit(b2PolygonContact, Box2D.Dynamics.Contacts.b2Contact); | |
b2PolygonContact.prototype.__super = Box2D.Dynamics.Contacts.b2Contact.prototype; | |
b2PolygonContact.b2PolygonContact = function () { | |
Box2D.Dynamics.Contacts.b2Contact.b2Contact.apply(this, arguments); | |
}; | |
b2PolygonContact.Create = function (allocator) { | |
return new b2PolygonContact(); | |
} | |
b2PolygonContact.Destroy = function (contact, allocator) {} | |
b2PolygonContact.prototype.Reset = function (fixtureA, fixtureB) { | |
this.__super.Reset.call(this, fixtureA, fixtureB); | |
} | |
b2PolygonContact.prototype.Evaluate = function () { | |
var bA = this.m_fixtureA.GetBody(); | |
var bB = this.m_fixtureB.GetBody(); | |
b2Collision.CollidePolygons(this.m_manifold, (this.m_fixtureA.GetShape() instanceof b2PolygonShape ? this.m_fixtureA.GetShape() : null), bA.m_xf, (this.m_fixtureB.GetShape() instanceof b2PolygonShape ? this.m_fixtureB.GetShape() : null), bB.m_xf); | |
} | |
b2PositionSolverManifold.b2PositionSolverManifold = function () {}; | |
b2PositionSolverManifold.prototype.b2PositionSolverManifold = function () { | |
this.m_normal = new b2Vec2(); | |
this.m_separations = new Vector_a2j_Number(b2Settings.b2_maxManifoldPoints); | |
this.m_points = new Vector(b2Settings.b2_maxManifoldPoints); | |
for (var i = 0; i < b2Settings.b2_maxManifoldPoints; i++) { | |
this.m_points[i] = new b2Vec2(); | |
} | |
} | |
b2PositionSolverManifold.prototype.Initialize = function (cc) { | |
b2Settings.b2Assert(cc.pointCount > 0); | |
var i = 0; | |
var clipPointX = 0; | |
var clipPointY = 0; | |
var tMat; | |
var tVec; | |
var planePointX = 0; | |
var planePointY = 0; | |
switch (cc.type) { | |
case b2Manifold.e_circles: | |
{ | |
tMat = cc.bodyA.m_xf.R; | |
tVec = cc.localPoint; | |
var pointAX = cc.bodyA.m_xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
var pointAY = cc.bodyA.m_xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
tMat = cc.bodyB.m_xf.R; | |
tVec = cc.points[0].localPoint; | |
var pointBX = cc.bodyB.m_xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
var pointBY = cc.bodyB.m_xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
var dX = pointBX - pointAX; | |
var dY = pointBY - pointAY; | |
var d2 = dX * dX + dY * dY; | |
if (d2 > Number.MIN_VALUE * Number.MIN_VALUE) { | |
var d = Math.sqrt(d2); | |
this.m_normal.x = dX / d; | |
this.m_normal.y = dY / d; | |
} | |
else { | |
this.m_normal.x = 1.0; | |
this.m_normal.y = 0.0; | |
} | |
this.m_points[0].x = 0.5 * (pointAX + pointBX); | |
this.m_points[0].y = 0.5 * (pointAY + pointBY); | |
this.m_separations[0] = dX * this.m_normal.x + dY * this.m_normal.y - cc.radius; | |
} | |
break; | |
case b2Manifold.e_faceA: | |
{ | |
tMat = cc.bodyA.m_xf.R; | |
tVec = cc.localPlaneNormal; | |
this.m_normal.x = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; | |
this.m_normal.y = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; | |
tMat = cc.bodyA.m_xf.R; | |
tVec = cc.localPoint; | |
planePointX = cc.bodyA.m_xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
planePointY = cc.bodyA.m_xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
tMat = cc.bodyB.m_xf.R; | |
for (i = 0; | |
i < cc.pointCount; ++i) { | |
tVec = cc.points[i].localPoint; | |
clipPointX = cc.bodyB.m_xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
clipPointY = cc.bodyB.m_xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
this.m_separations[i] = (clipPointX - planePointX) * this.m_normal.x + (clipPointY - planePointY) * this.m_normal.y - cc.radius; | |
this.m_points[i].x = clipPointX; | |
this.m_points[i].y = clipPointY; | |
} | |
} | |
break; | |
case b2Manifold.e_faceB: | |
{ | |
tMat = cc.bodyB.m_xf.R; | |
tVec = cc.localPlaneNormal; | |
this.m_normal.x = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; | |
this.m_normal.y = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; | |
tMat = cc.bodyB.m_xf.R; | |
tVec = cc.localPoint; | |
planePointX = cc.bodyB.m_xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
planePointY = cc.bodyB.m_xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
tMat = cc.bodyA.m_xf.R; | |
for (i = 0; | |
i < cc.pointCount; ++i) { | |
tVec = cc.points[i].localPoint; | |
clipPointX = cc.bodyA.m_xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); | |
clipPointY = cc.bodyA.m_xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); | |
this.m_separations[i] = (clipPointX - planePointX) * this.m_normal.x + (clipPointY - planePointY) * this.m_normal.y - cc.radius; | |
this.m_points[i].Set(clipPointX, clipPointY); | |
} | |
this.m_normal.x *= (-1); | |
this.m_normal.y *= (-1); | |
} | |
break; | |
} | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Dynamics.Contacts.b2PositionSolverManifold.circlePointA = new b2Vec2(); | |
Box2D.Dynamics.Contacts.b2PositionSolverManifold.circlePointB = new b2Vec2(); | |
}); | |
})(); | |
(function () { | |
var b2Body = Box2D.Dynamics.b2Body, | |
b2BodyDef = Box2D.Dynamics.b2BodyDef, | |
b2ContactFilter = Box2D.Dynamics.b2ContactFilter, | |
b2ContactImpulse = Box2D.Dynamics.b2ContactImpulse, | |
b2ContactListener = Box2D.Dynamics.b2ContactListener, | |
b2ContactManager = Box2D.Dynamics.b2ContactManager, | |
b2DebugDraw = Box2D.Dynamics.b2DebugDraw, | |
b2DestructionListener = Box2D.Dynamics.b2DestructionListener, | |
b2FilterData = Box2D.Dynamics.b2FilterData, | |
b2Fixture = Box2D.Dynamics.b2Fixture, | |
b2FixtureDef = Box2D.Dynamics.b2FixtureDef, | |
b2Island = Box2D.Dynamics.b2Island, | |
b2TimeStep = Box2D.Dynamics.b2TimeStep, | |
b2World = Box2D.Dynamics.b2World, | |
b2Mat22 = Box2D.Common.Math.b2Mat22, | |
b2Mat33 = Box2D.Common.Math.b2Mat33, | |
b2Math = Box2D.Common.Math.b2Math, | |
b2Sweep = Box2D.Common.Math.b2Sweep, | |
b2Transform = Box2D.Common.Math.b2Transform, | |
b2Vec2 = Box2D.Common.Math.b2Vec2, | |
b2Vec3 = Box2D.Common.Math.b2Vec3, | |
b2Color = Box2D.Common.b2Color, | |
b2internal = Box2D.Common.b2internal, | |
b2Settings = Box2D.Common.b2Settings, | |
b2CircleShape = Box2D.Collision.Shapes.b2CircleShape, | |
b2EdgeChainDef = Box2D.Collision.Shapes.b2EdgeChainDef, | |
b2EdgeShape = Box2D.Collision.Shapes.b2EdgeShape, | |
b2MassData = Box2D.Collision.Shapes.b2MassData, | |
b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape, | |
b2Shape = Box2D.Collision.Shapes.b2Shape, | |
b2BuoyancyController = Box2D.Dynamics.Controllers.b2BuoyancyController, | |
b2ConstantAccelController = Box2D.Dynamics.Controllers.b2ConstantAccelController, | |
b2ConstantForceController = Box2D.Dynamics.Controllers.b2ConstantForceController, | |
b2Controller = Box2D.Dynamics.Controllers.b2Controller, | |
b2ControllerEdge = Box2D.Dynamics.Controllers.b2ControllerEdge, | |
b2GravityController = Box2D.Dynamics.Controllers.b2GravityController, | |
b2TensorDampingController = Box2D.Dynamics.Controllers.b2TensorDampingController; | |
Box2D.inherit(b2BuoyancyController, Box2D.Dynamics.Controllers.b2Controller); | |
b2BuoyancyController.prototype.__super = Box2D.Dynamics.Controllers.b2Controller.prototype; | |
b2BuoyancyController.b2BuoyancyController = function () { | |
Box2D.Dynamics.Controllers.b2Controller.b2Controller.apply(this, arguments); | |
this.normal = new b2Vec2(0, (-1)); | |
this.offset = 0; | |
this.density = 0; | |
this.velocity = new b2Vec2(0, 0); | |
this.linearDrag = 2; | |
this.angularDrag = 1; | |
this.useDensity = false; | |
this.useWorldGravity = true; | |
this.gravity = null; | |
}; | |
b2BuoyancyController.prototype.Step = function (step) { | |
if (!this.m_bodyList) return; | |
if (this.useWorldGravity) { | |
this.gravity = this.GetWorld().GetGravity().Copy(); | |
} | |
for (var i = this.m_bodyList; i; i = i.nextBody) { | |
var body = i.body; | |
if (body.IsAwake() == false) { | |
continue; | |
} | |
var areac = new b2Vec2(); | |
var massc = new b2Vec2(); | |
var area = 0.0; | |
var mass = 0.0; | |
for (var fixture = body.GetFixtureList(); fixture; fixture = fixture.GetNext()) { | |
var sc = new b2Vec2(); | |
var sarea = fixture.GetShape().ComputeSubmergedArea(this.normal, this.offset, body.GetTransform(), sc); | |
area += sarea; | |
areac.x += sarea * sc.x; | |
areac.y += sarea * sc.y; | |
var shapeDensity = 0; | |
if (this.useDensity) { | |
shapeDensity = 1; | |
} | |
else { | |
shapeDensity = 1; | |
} | |
mass += sarea * shapeDensity; | |
massc.x += sarea * sc.x * shapeDensity; | |
massc.y += sarea * sc.y * shapeDensity; | |
} | |
areac.x /= area; | |
areac.y /= area; | |
massc.x /= mass; | |
massc.y /= mass; | |
if (area < Number.MIN_VALUE) continue; | |
var buoyancyForce = this.gravity.GetNegative(); | |
buoyancyForce.Multiply(this.density * area); | |
body.ApplyForce(buoyancyForce, massc); | |
var dragForce = body.GetLinearVelocityFromWorldPoint(areac); | |
dragForce.Subtract(this.velocity); | |
dragForce.Multiply((-this.linearDrag * area)); | |
body.ApplyForce(dragForce, areac); | |
body.ApplyTorque((-body.GetInertia() / body.GetMass() * area * body.GetAngularVelocity() * this.angularDrag)); | |
} | |
} | |
b2BuoyancyController.prototype.Draw = function (debugDraw) { | |
var r = 1000; | |
var p1 = new b2Vec2(); | |
var p2 = new b2Vec2(); | |
p1.x = this.normal.x * this.offset + this.normal.y * r; | |
p1.y = this.normal.y * this.offset - this.normal.x * r; | |
p2.x = this.normal.x * this.offset - this.normal.y * r; | |
p2.y = this.normal.y * this.offset + this.normal.x * r; | |
var color = new b2Color(0, 0, 1); | |
debugDraw.DrawSegment(p1, p2, color); | |
} | |
Box2D.inherit(b2ConstantAccelController, Box2D.Dynamics.Controllers.b2Controller); | |
b2ConstantAccelController.prototype.__super = Box2D.Dynamics.Controllers.b2Controller.prototype; | |
b2ConstantAccelController.b2ConstantAccelController = function () { | |
Box2D.Dynamics.Controllers.b2Controller.b2Controller.apply(this, arguments); | |
this.A = new b2Vec2(0, 0); | |
}; | |
b2ConstantAccelController.prototype.Step = function (step) { | |
var smallA = new b2Vec2(this.A.x * step.dt, this.A.y * step.dt); | |
for (var i = this.m_bodyList; i; i = i.nextBody) { | |
var body = i.body; | |
if (!body.IsAwake()) continue; | |
body.SetLinearVelocity(new b2Vec2(body.GetLinearVelocity().x + smallA.x, body.GetLinearVelocity().y + smallA.y)); | |
} | |
} | |
Box2D.inherit(b2ConstantForceController, Box2D.Dynamics.Controllers.b2Controller); | |
b2ConstantForceController.prototype.__super = Box2D.Dynamics.Controllers.b2Controller.prototype; | |
b2ConstantForceController.b2ConstantForceController = function () { | |
Box2D.Dynamics.Controllers.b2Controller.b2Controller.apply(this, arguments); | |
this.F = new b2Vec2(0, 0); | |
}; | |
b2ConstantForceController.prototype.Step = function (step) { | |
for (var i = this.m_bodyList; i; i = i.nextBody) { | |
var body = i.body; | |
if (!body.IsAwake()) continue; | |
body.ApplyForce(this.F, body.GetWorldCenter()); | |
} | |
} | |
b2Controller.b2Controller = function () {}; | |
b2Controller.prototype.Step = function (step) {} | |
b2Controller.prototype.Draw = function (debugDraw) {} | |
b2Controller.prototype.AddBody = function (body) { | |
var edge = new b2ControllerEdge(); | |
edge.controller = this; | |
edge.body = body; | |
edge.nextBody = this.m_bodyList; | |
edge.prevBody = null; | |
this.m_bodyList = edge; | |
if (edge.nextBody) edge.nextBody.prevBody = edge; | |
this.m_bodyCount++; | |
edge.nextController = body.m_controllerList; | |
edge.prevController = null; | |
body.m_controllerList = edge; | |
if (edge.nextController) edge.nextController.prevController = edge; | |
body.m_controllerCount++; | |
} | |
b2Controller.prototype.RemoveBody = function (body) { | |
var edge = body.m_controllerList; | |
while (edge && edge.controller != this) | |
edge = edge.nextController; | |
if (edge.prevBody) edge.prevBody.nextBody = edge.nextBody; | |
if (edge.nextBody) edge.nextBody.prevBody = edge.prevBody; | |
if (edge.nextController) edge.nextController.prevController = edge.prevController; | |
if (edge.prevController) edge.prevController.nextController = edge.nextController; | |
if (this.m_bodyList == edge) this.m_bodyList = edge.nextBody; | |
if (body.m_controllerList == edge) body.m_controllerList = edge.nextController; | |
body.m_controllerCount--; | |
this.m_bodyCount--; | |
} | |
b2Controller.prototype.Clear = function () { | |
while (this.m_bodyList) | |
this.RemoveBody(this.m_bodyList.body); | |
} | |
b2Controller.prototype.GetNext = function () { | |
return this.m_next; | |
} | |
b2Controller.prototype.GetWorld = function () { | |
return this.m_world; | |
} | |
b2Controller.prototype.GetBodyList = function () { | |
return this.m_bodyList; | |
} | |
b2ControllerEdge.b2ControllerEdge = function () {}; | |
Box2D.inherit(b2GravityController, Box2D.Dynamics.Controllers.b2Controller); | |
b2GravityController.prototype.__super = Box2D.Dynamics.Controllers.b2Controller.prototype; | |
b2GravityController.b2GravityController = function () { | |
Box2D.Dynamics.Controllers.b2Controller.b2Controller.apply(this, arguments); | |
this.G = 1; | |
this.invSqr = true; | |
}; | |
b2GravityController.prototype.Step = function (step) { | |
var i = null; | |
var body1 = null; | |
var p1 = null; | |
var mass1 = 0; | |
var j = null; | |
var body2 = null; | |
var p2 = null; | |
var dx = 0; | |
var dy = 0; | |
var r2 = 0; | |
var f = null; | |
if (this.invSqr) { | |
for (i = this.m_bodyList; | |
i; i = i.nextBody) { | |
body1 = i.body; | |
p1 = body1.GetWorldCenter(); | |
mass1 = body1.GetMass(); | |
for (j = this.m_bodyList; | |
j != i; j = j.nextBody) { | |
body2 = j.body; | |
p2 = body2.GetWorldCenter(); | |
dx = p2.x - p1.x; | |
dy = p2.y - p1.y; | |
r2 = dx * dx + dy * dy; | |
if (r2 < Number.MIN_VALUE) continue; | |
f = new b2Vec2(dx, dy); | |
f.Multiply(this.G / r2 / Math.sqrt(r2) * mass1 * body2.GetMass()); | |
if (body1.IsAwake()) body1.ApplyForce(f, p1); | |
f.Multiply((-1)); | |
if (body2.IsAwake()) body2.ApplyForce(f, p2); | |
} | |
} | |
} | |
else { | |
for (i = this.m_bodyList; | |
i; i = i.nextBody) { | |
body1 = i.body; | |
p1 = body1.GetWorldCenter(); | |
mass1 = body1.GetMass(); | |
for (j = this.m_bodyList; | |
j != i; j = j.nextBody) { | |
body2 = j.body; | |
p2 = body2.GetWorldCenter(); | |
dx = p2.x - p1.x; | |
dy = p2.y - p1.y; | |
r2 = dx * dx + dy * dy; | |
if (r2 < Number.MIN_VALUE) continue; | |
f = new b2Vec2(dx, dy); | |
f.Multiply(this.G / r2 * mass1 * body2.GetMass()); | |
if (body1.IsAwake()) body1.ApplyForce(f, p1); | |
f.Multiply((-1)); | |
if (body2.IsAwake()) body2.ApplyForce(f, p2); | |
} | |
} | |
} | |
} | |
Box2D.inherit(b2TensorDampingController, Box2D.Dynamics.Controllers.b2Controller); | |
b2TensorDampingController.prototype.__super = Box2D.Dynamics.Controllers.b2Controller.prototype; | |
b2TensorDampingController.b2TensorDampingController = function () { | |
Box2D.Dynamics.Controllers.b2Controller.b2Controller.apply(this, arguments); | |
this.T = new b2Mat22(); | |
this.maxTimestep = 0; | |
}; | |
b2TensorDampingController.prototype.SetAxisAligned = function (xDamping, yDamping) { | |
if (xDamping === undefined) xDamping = 0; | |
if (yDamping === undefined) yDamping = 0; | |
this.T.col1.x = (-xDamping); | |
this.T.col1.y = 0; | |
this.T.col2.x = 0; | |
this.T.col2.y = (-yDamping); | |
if (xDamping > 0 || yDamping > 0) { | |
this.maxTimestep = 1 / Math.max(xDamping, yDamping); | |
} | |
else { | |
this.maxTimestep = 0; | |
} | |
} | |
b2TensorDampingController.prototype.Step = function (step) { | |
var timestep = step.dt; | |
if (timestep <= Number.MIN_VALUE) return; | |
if (timestep > this.maxTimestep && this.maxTimestep > 0) timestep = this.maxTimestep; | |
for (var i = this.m_bodyList; i; i = i.nextBody) { | |
var body = i.body; | |
if (!body.IsAwake()) { | |
continue; | |
} | |
var damping = body.GetWorldVector(b2Math.MulMV(this.T, body.GetLocalVector(body.GetLinearVelocity()))); | |
body.SetLinearVelocity(new b2Vec2(body.GetLinearVelocity().x + damping.x * timestep, body.GetLinearVelocity().y + damping.y * timestep)); | |
} | |
} | |
})(); | |
(function () { | |
var b2Color = Box2D.Common.b2Color, | |
b2internal = Box2D.Common.b2internal, | |
b2Settings = Box2D.Common.b2Settings, | |
b2Mat22 = Box2D.Common.Math.b2Mat22, | |
b2Mat33 = Box2D.Common.Math.b2Mat33, | |
b2Math = Box2D.Common.Math.b2Math, | |
b2Sweep = Box2D.Common.Math.b2Sweep, | |
b2Transform = Box2D.Common.Math.b2Transform, | |
b2Vec2 = Box2D.Common.Math.b2Vec2, | |
b2Vec3 = Box2D.Common.Math.b2Vec3, | |
b2DistanceJoint = Box2D.Dynamics.Joints.b2DistanceJoint, | |
b2DistanceJointDef = Box2D.Dynamics.Joints.b2DistanceJointDef, | |
b2FrictionJoint = Box2D.Dynamics.Joints.b2FrictionJoint, | |
b2FrictionJointDef = Box2D.Dynamics.Joints.b2FrictionJointDef, | |
b2GearJoint = Box2D.Dynamics.Joints.b2GearJoint, | |
b2GearJointDef = Box2D.Dynamics.Joints.b2GearJointDef, | |
b2Jacobian = Box2D.Dynamics.Joints.b2Jacobian, | |
b2Joint = Box2D.Dynamics.Joints.b2Joint, | |
b2JointDef = Box2D.Dynamics.Joints.b2JointDef, | |
b2JointEdge = Box2D.Dynamics.Joints.b2JointEdge, | |
b2LineJoint = Box2D.Dynamics.Joints.b2LineJoint, | |
b2LineJointDef = Box2D.Dynamics.Joints.b2LineJointDef, | |
b2MouseJoint = Box2D.Dynamics.Joints.b2MouseJoint, | |
b2MouseJointDef = Box2D.Dynamics.Joints.b2MouseJointDef, | |
b2PrismaticJoint = Box2D.Dynamics.Joints.b2PrismaticJoint, | |
b2PrismaticJointDef = Box2D.Dynamics.Joints.b2PrismaticJointDef, | |
b2PulleyJoint = Box2D.Dynamics.Joints.b2PulleyJoint, | |
b2PulleyJointDef = Box2D.Dynamics.Joints.b2PulleyJointDef, | |
b2RevoluteJoint = Box2D.Dynamics.Joints.b2RevoluteJoint, | |
b2RevoluteJointDef = Box2D.Dynamics.Joints.b2RevoluteJointDef, | |
b2WeldJoint = Box2D.Dynamics.Joints.b2WeldJoint, | |
b2WeldJointDef = Box2D.Dynamics.Joints.b2WeldJointDef, | |
b2Body = Box2D.Dynamics.b2Body, | |
b2BodyDef = Box2D.Dynamics.b2BodyDef, | |
b2ContactFilter = Box2D.Dynamics.b2ContactFilter, | |
b2ContactImpulse = Box2D.Dynamics.b2ContactImpulse, | |
b2ContactListener = Box2D.Dynamics.b2ContactListener, | |
b2ContactManager = Box2D.Dynamics.b2ContactManager, | |
b2DebugDraw = Box2D.Dynamics.b2DebugDraw, | |
b2DestructionListener = Box2D.Dynamics.b2DestructionListener, | |
b2FilterData = Box2D.Dynamics.b2FilterData, | |
b2Fixture = Box2D.Dynamics.b2Fixture, | |
b2FixtureDef = Box2D.Dynamics.b2FixtureDef, | |
b2Island = Box2D.Dynamics.b2Island, | |
b2TimeStep = Box2D.Dynamics.b2TimeStep, | |
b2World = Box2D.Dynamics.b2World; | |
Box2D.inherit(b2DistanceJoint, Box2D.Dynamics.Joints.b2Joint); | |
b2DistanceJoint.prototype.__super = Box2D.Dynamics.Joints.b2Joint.prototype; | |
b2DistanceJoint.b2DistanceJoint = function () { | |
Box2D.Dynamics.Joints.b2Joint.b2Joint.apply(this, arguments); | |
this.m_localAnchor1 = new b2Vec2(); | |
this.m_localAnchor2 = new b2Vec2(); | |
this.m_u = new b2Vec2(); | |
}; | |
b2DistanceJoint.prototype.GetAnchorA = function () { | |
return this.m_bodyA.GetWorldPoint(this.m_localAnchor1); | |
} | |
b2DistanceJoint.prototype.GetAnchorB = function () { | |
return this.m_bodyB.GetWorldPoint(this.m_localAnchor2); | |
} | |
b2DistanceJoint.prototype.GetReactionForce = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
return new b2Vec2(inv_dt * this.m_impulse * this.m_u.x, inv_dt * this.m_impulse * this.m_u.y); | |
} | |
b2DistanceJoint.prototype.GetReactionTorque = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
return 0.0; | |
} | |
b2DistanceJoint.prototype.GetLength = function () { | |
return this.m_length; | |
} | |
b2DistanceJoint.prototype.SetLength = function (length) { | |
if (length === undefined) length = 0; | |
this.m_length = length; | |
} | |
b2DistanceJoint.prototype.GetFrequency = function () { | |
return this.m_frequencyHz; | |
} | |
b2DistanceJoint.prototype.SetFrequency = function (hz) { | |
if (hz === undefined) hz = 0; | |
this.m_frequencyHz = hz; | |
} | |
b2DistanceJoint.prototype.GetDampingRatio = function () { | |
return this.m_dampingRatio; | |
} | |
b2DistanceJoint.prototype.SetDampingRatio = function (ratio) { | |
if (ratio === undefined) ratio = 0; | |
this.m_dampingRatio = ratio; | |
} | |
b2DistanceJoint.prototype.b2DistanceJoint = function (def) { | |
this.__super.b2Joint.call(this, def); | |
var tMat; | |
var tX = 0; | |
var tY = 0; | |
this.m_localAnchor1.SetV(def.localAnchorA); | |
this.m_localAnchor2.SetV(def.localAnchorB); | |
this.m_length = def.length; | |
this.m_frequencyHz = def.frequencyHz; | |
this.m_dampingRatio = def.dampingRatio; | |
this.m_impulse = 0.0; | |
this.m_gamma = 0.0; | |
this.m_bias = 0.0; | |
} | |
b2DistanceJoint.prototype.InitVelocityConstraints = function (step) { | |
var tMat; | |
var tX = 0; | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
tMat = bA.m_xf.R; | |
var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; | |
var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); | |
r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); | |
r1X = tX; | |
tMat = bB.m_xf.R; | |
var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; | |
var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); | |
r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); | |
r2X = tX; | |
this.m_u.x = bB.m_sweep.c.x + r2X - bA.m_sweep.c.x - r1X; | |
this.m_u.y = bB.m_sweep.c.y + r2Y - bA.m_sweep.c.y - r1Y; | |
var length = Math.sqrt(this.m_u.x * this.m_u.x + this.m_u.y * this.m_u.y); | |
if (length > b2Settings.b2_linearSlop) { | |
this.m_u.Multiply(1.0 / length); | |
} | |
else { | |
this.m_u.SetZero(); | |
} | |
var cr1u = (r1X * this.m_u.y - r1Y * this.m_u.x); | |
var cr2u = (r2X * this.m_u.y - r2Y * this.m_u.x); | |
var invMass = bA.m_invMass + bA.m_invI * cr1u * cr1u + bB.m_invMass + bB.m_invI * cr2u * cr2u; | |
this.m_mass = invMass != 0.0 ? 1.0 / invMass : 0.0; | |
if (this.m_frequencyHz > 0.0) { | |
var C = length - this.m_length; | |
var omega = 2.0 * Math.PI * this.m_frequencyHz; | |
var d = 2.0 * this.m_mass * this.m_dampingRatio * omega; | |
var k = this.m_mass * omega * omega; | |
this.m_gamma = step.dt * (d + step.dt * k); | |
this.m_gamma = this.m_gamma != 0.0 ? 1 / this.m_gamma : 0.0; | |
this.m_bias = C * step.dt * k * this.m_gamma; | |
this.m_mass = invMass + this.m_gamma; | |
this.m_mass = this.m_mass != 0.0 ? 1.0 / this.m_mass : 0.0; | |
} | |
if (step.warmStarting) { | |
this.m_impulse *= step.dtRatio; | |
var PX = this.m_impulse * this.m_u.x; | |
var PY = this.m_impulse * this.m_u.y; | |
bA.m_linearVelocity.x -= bA.m_invMass * PX; | |
bA.m_linearVelocity.y -= bA.m_invMass * PY; | |
bA.m_angularVelocity -= bA.m_invI * (r1X * PY - r1Y * PX); | |
bB.m_linearVelocity.x += bB.m_invMass * PX; | |
bB.m_linearVelocity.y += bB.m_invMass * PY; | |
bB.m_angularVelocity += bB.m_invI * (r2X * PY - r2Y * PX); | |
} | |
else { | |
this.m_impulse = 0.0; | |
} | |
} | |
b2DistanceJoint.prototype.SolveVelocityConstraints = function (step) { | |
var tMat; | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
tMat = bA.m_xf.R; | |
var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; | |
var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; | |
var tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); | |
r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); | |
r1X = tX; | |
tMat = bB.m_xf.R; | |
var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; | |
var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); | |
r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); | |
r2X = tX; | |
var v1X = bA.m_linearVelocity.x + ((-bA.m_angularVelocity * r1Y)); | |
var v1Y = bA.m_linearVelocity.y + (bA.m_angularVelocity * r1X); | |
var v2X = bB.m_linearVelocity.x + ((-bB.m_angularVelocity * r2Y)); | |
var v2Y = bB.m_linearVelocity.y + (bB.m_angularVelocity * r2X); | |
var Cdot = (this.m_u.x * (v2X - v1X) + this.m_u.y * (v2Y - v1Y)); | |
var impulse = (-this.m_mass * (Cdot + this.m_bias + this.m_gamma * this.m_impulse)); | |
this.m_impulse += impulse; | |
var PX = impulse * this.m_u.x; | |
var PY = impulse * this.m_u.y; | |
bA.m_linearVelocity.x -= bA.m_invMass * PX; | |
bA.m_linearVelocity.y -= bA.m_invMass * PY; | |
bA.m_angularVelocity -= bA.m_invI * (r1X * PY - r1Y * PX); | |
bB.m_linearVelocity.x += bB.m_invMass * PX; | |
bB.m_linearVelocity.y += bB.m_invMass * PY; | |
bB.m_angularVelocity += bB.m_invI * (r2X * PY - r2Y * PX); | |
} | |
b2DistanceJoint.prototype.SolvePositionConstraints = function (baumgarte) { | |
if (baumgarte === undefined) baumgarte = 0; | |
var tMat; | |
if (this.m_frequencyHz > 0.0) { | |
return true; | |
} | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
tMat = bA.m_xf.R; | |
var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; | |
var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; | |
var tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); | |
r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); | |
r1X = tX; | |
tMat = bB.m_xf.R; | |
var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; | |
var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); | |
r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); | |
r2X = tX; | |
var dX = bB.m_sweep.c.x + r2X - bA.m_sweep.c.x - r1X; | |
var dY = bB.m_sweep.c.y + r2Y - bA.m_sweep.c.y - r1Y; | |
var length = Math.sqrt(dX * dX + dY * dY); | |
dX /= length; | |
dY /= length; | |
var C = length - this.m_length; | |
C = b2Math.Clamp(C, (-b2Settings.b2_maxLinearCorrection), b2Settings.b2_maxLinearCorrection); | |
var impulse = (-this.m_mass * C); | |
this.m_u.Set(dX, dY); | |
var PX = impulse * this.m_u.x; | |
var PY = impulse * this.m_u.y; | |
bA.m_sweep.c.x -= bA.m_invMass * PX; | |
bA.m_sweep.c.y -= bA.m_invMass * PY; | |
bA.m_sweep.a -= bA.m_invI * (r1X * PY - r1Y * PX); | |
bB.m_sweep.c.x += bB.m_invMass * PX; | |
bB.m_sweep.c.y += bB.m_invMass * PY; | |
bB.m_sweep.a += bB.m_invI * (r2X * PY - r2Y * PX); | |
bA.SynchronizeTransform(); | |
bB.SynchronizeTransform(); | |
return b2Math.Abs(C) < b2Settings.b2_linearSlop; | |
} | |
Box2D.inherit(b2DistanceJointDef, Box2D.Dynamics.Joints.b2JointDef); | |
b2DistanceJointDef.prototype.__super = Box2D.Dynamics.Joints.b2JointDef.prototype; | |
b2DistanceJointDef.b2DistanceJointDef = function () { | |
Box2D.Dynamics.Joints.b2JointDef.b2JointDef.apply(this, arguments); | |
this.localAnchorA = new b2Vec2(); | |
this.localAnchorB = new b2Vec2(); | |
}; | |
b2DistanceJointDef.prototype.b2DistanceJointDef = function () { | |
this.__super.b2JointDef.call(this); | |
this.type = b2Joint.e_distanceJoint; | |
this.length = 1.0; | |
this.frequencyHz = 0.0; | |
this.dampingRatio = 0.0; | |
} | |
b2DistanceJointDef.prototype.Initialize = function (bA, bB, anchorA, anchorB) { | |
this.bodyA = bA; | |
this.bodyB = bB; | |
this.localAnchorA.SetV(this.bodyA.GetLocalPoint(anchorA)); | |
this.localAnchorB.SetV(this.bodyB.GetLocalPoint(anchorB)); | |
var dX = anchorB.x - anchorA.x; | |
var dY = anchorB.y - anchorA.y; | |
this.length = Math.sqrt(dX * dX + dY * dY); | |
this.frequencyHz = 0.0; | |
this.dampingRatio = 0.0; | |
} | |
Box2D.inherit(b2FrictionJoint, Box2D.Dynamics.Joints.b2Joint); | |
b2FrictionJoint.prototype.__super = Box2D.Dynamics.Joints.b2Joint.prototype; | |
b2FrictionJoint.b2FrictionJoint = function () { | |
Box2D.Dynamics.Joints.b2Joint.b2Joint.apply(this, arguments); | |
this.m_localAnchorA = new b2Vec2(); | |
this.m_localAnchorB = new b2Vec2(); | |
this.m_linearMass = new b2Mat22(); | |
this.m_linearImpulse = new b2Vec2(); | |
}; | |
b2FrictionJoint.prototype.GetAnchorA = function () { | |
return this.m_bodyA.GetWorldPoint(this.m_localAnchorA); | |
} | |
b2FrictionJoint.prototype.GetAnchorB = function () { | |
return this.m_bodyB.GetWorldPoint(this.m_localAnchorB); | |
} | |
b2FrictionJoint.prototype.GetReactionForce = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
return new b2Vec2(inv_dt * this.m_linearImpulse.x, inv_dt * this.m_linearImpulse.y); | |
} | |
b2FrictionJoint.prototype.GetReactionTorque = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
return inv_dt * this.m_angularImpulse; | |
} | |
b2FrictionJoint.prototype.SetMaxForce = function (force) { | |
if (force === undefined) force = 0; | |
this.m_maxForce = force; | |
} | |
b2FrictionJoint.prototype.GetMaxForce = function () { | |
return this.m_maxForce; | |
} | |
b2FrictionJoint.prototype.SetMaxTorque = function (torque) { | |
if (torque === undefined) torque = 0; | |
this.m_maxTorque = torque; | |
} | |
b2FrictionJoint.prototype.GetMaxTorque = function () { | |
return this.m_maxTorque; | |
} | |
b2FrictionJoint.prototype.b2FrictionJoint = function (def) { | |
this.__super.b2Joint.call(this, def); | |
this.m_localAnchorA.SetV(def.localAnchorA); | |
this.m_localAnchorB.SetV(def.localAnchorB); | |
this.m_linearMass.SetZero(); | |
this.m_angularMass = 0.0; | |
this.m_linearImpulse.SetZero(); | |
this.m_angularImpulse = 0.0; | |
this.m_maxForce = def.maxForce; | |
this.m_maxTorque = def.maxTorque; | |
} | |
b2FrictionJoint.prototype.InitVelocityConstraints = function (step) { | |
var tMat; | |
var tX = 0; | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
tMat = bA.m_xf.R; | |
var rAX = this.m_localAnchorA.x - bA.m_sweep.localCenter.x; | |
var rAY = this.m_localAnchorA.y - bA.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * rAX + tMat.col2.x * rAY); | |
rAY = (tMat.col1.y * rAX + tMat.col2.y * rAY); | |
rAX = tX; | |
tMat = bB.m_xf.R; | |
var rBX = this.m_localAnchorB.x - bB.m_sweep.localCenter.x; | |
var rBY = this.m_localAnchorB.y - bB.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * rBX + tMat.col2.x * rBY); | |
rBY = (tMat.col1.y * rBX + tMat.col2.y * rBY); | |
rBX = tX; | |
var mA = bA.m_invMass; | |
var mB = bB.m_invMass; | |
var iA = bA.m_invI; | |
var iB = bB.m_invI; | |
var K = new b2Mat22(); | |
K.col1.x = mA + mB; | |
K.col2.x = 0.0; | |
K.col1.y = 0.0; | |
K.col2.y = mA + mB; | |
K.col1.x += iA * rAY * rAY; | |
K.col2.x += (-iA * rAX * rAY); | |
K.col1.y += (-iA * rAX * rAY); | |
K.col2.y += iA * rAX * rAX; | |
K.col1.x += iB * rBY * rBY; | |
K.col2.x += (-iB * rBX * rBY); | |
K.col1.y += (-iB * rBX * rBY); | |
K.col2.y += iB * rBX * rBX; | |
K.GetInverse(this.m_linearMass); | |
this.m_angularMass = iA + iB; | |
if (this.m_angularMass > 0.0) { | |
this.m_angularMass = 1.0 / this.m_angularMass; | |
} | |
if (step.warmStarting) { | |
this.m_linearImpulse.x *= step.dtRatio; | |
this.m_linearImpulse.y *= step.dtRatio; | |
this.m_angularImpulse *= step.dtRatio; | |
var P = this.m_linearImpulse; | |
bA.m_linearVelocity.x -= mA * P.x; | |
bA.m_linearVelocity.y -= mA * P.y; | |
bA.m_angularVelocity -= iA * (rAX * P.y - rAY * P.x + this.m_angularImpulse); | |
bB.m_linearVelocity.x += mB * P.x; | |
bB.m_linearVelocity.y += mB * P.y; | |
bB.m_angularVelocity += iB * (rBX * P.y - rBY * P.x + this.m_angularImpulse); | |
} | |
else { | |
this.m_linearImpulse.SetZero(); | |
this.m_angularImpulse = 0.0; | |
} | |
} | |
b2FrictionJoint.prototype.SolveVelocityConstraints = function (step) { | |
var tMat; | |
var tX = 0; | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var vA = bA.m_linearVelocity; | |
var wA = bA.m_angularVelocity; | |
var vB = bB.m_linearVelocity; | |
var wB = bB.m_angularVelocity; | |
var mA = bA.m_invMass; | |
var mB = bB.m_invMass; | |
var iA = bA.m_invI; | |
var iB = bB.m_invI; | |
tMat = bA.m_xf.R; | |
var rAX = this.m_localAnchorA.x - bA.m_sweep.localCenter.x; | |
var rAY = this.m_localAnchorA.y - bA.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * rAX + tMat.col2.x * rAY); | |
rAY = (tMat.col1.y * rAX + tMat.col2.y * rAY); | |
rAX = tX; | |
tMat = bB.m_xf.R; | |
var rBX = this.m_localAnchorB.x - bB.m_sweep.localCenter.x; | |
var rBY = this.m_localAnchorB.y - bB.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * rBX + tMat.col2.x * rBY); | |
rBY = (tMat.col1.y * rBX + tMat.col2.y * rBY); | |
rBX = tX; | |
var maxImpulse = 0; { | |
var Cdot = wB - wA; | |
var impulse = (-this.m_angularMass * Cdot); | |
var oldImpulse = this.m_angularImpulse; | |
maxImpulse = step.dt * this.m_maxTorque; | |
this.m_angularImpulse = b2Math.Clamp(this.m_angularImpulse + impulse, (-maxImpulse), maxImpulse); | |
impulse = this.m_angularImpulse - oldImpulse; | |
wA -= iA * impulse; | |
wB += iB * impulse; | |
} { | |
var CdotX = vB.x - wB * rBY - vA.x + wA * rAY; | |
var CdotY = vB.y + wB * rBX - vA.y - wA * rAX; | |
var impulseV = b2Math.MulMV(this.m_linearMass, new b2Vec2((-CdotX), (-CdotY))); | |
var oldImpulseV = this.m_linearImpulse.Copy(); | |
this.m_linearImpulse.Add(impulseV); | |
maxImpulse = step.dt * this.m_maxForce; | |
if (this.m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse) { | |
this.m_linearImpulse.Normalize(); | |
this.m_linearImpulse.Multiply(maxImpulse); | |
} | |
impulseV = b2Math.SubtractVV(this.m_linearImpulse, oldImpulseV); | |
vA.x -= mA * impulseV.x; | |
vA.y -= mA * impulseV.y; | |
wA -= iA * (rAX * impulseV.y - rAY * impulseV.x); | |
vB.x += mB * impulseV.x; | |
vB.y += mB * impulseV.y; | |
wB += iB * (rBX * impulseV.y - rBY * impulseV.x); | |
} | |
bA.m_angularVelocity = wA; | |
bB.m_angularVelocity = wB; | |
} | |
b2FrictionJoint.prototype.SolvePositionConstraints = function (baumgarte) { | |
if (baumgarte === undefined) baumgarte = 0; | |
return true; | |
} | |
Box2D.inherit(b2FrictionJointDef, Box2D.Dynamics.Joints.b2JointDef); | |
b2FrictionJointDef.prototype.__super = Box2D.Dynamics.Joints.b2JointDef.prototype; | |
b2FrictionJointDef.b2FrictionJointDef = function () { | |
Box2D.Dynamics.Joints.b2JointDef.b2JointDef.apply(this, arguments); | |
this.localAnchorA = new b2Vec2(); | |
this.localAnchorB = new b2Vec2(); | |
}; | |
b2FrictionJointDef.prototype.b2FrictionJointDef = function () { | |
this.__super.b2JointDef.call(this); | |
this.type = b2Joint.e_frictionJoint; | |
this.maxForce = 0.0; | |
this.maxTorque = 0.0; | |
} | |
b2FrictionJointDef.prototype.Initialize = function (bA, bB, anchor) { | |
this.bodyA = bA; | |
this.bodyB = bB; | |
this.localAnchorA.SetV(this.bodyA.GetLocalPoint(anchor)); | |
this.localAnchorB.SetV(this.bodyB.GetLocalPoint(anchor)); | |
} | |
Box2D.inherit(b2GearJoint, Box2D.Dynamics.Joints.b2Joint); | |
b2GearJoint.prototype.__super = Box2D.Dynamics.Joints.b2Joint.prototype; | |
b2GearJoint.b2GearJoint = function () { | |
Box2D.Dynamics.Joints.b2Joint.b2Joint.apply(this, arguments); | |
this.m_groundAnchor1 = new b2Vec2(); | |
this.m_groundAnchor2 = new b2Vec2(); | |
this.m_localAnchor1 = new b2Vec2(); | |
this.m_localAnchor2 = new b2Vec2(); | |
this.m_J = new b2Jacobian(); | |
}; | |
b2GearJoint.prototype.GetAnchorA = function () { | |
return this.m_bodyA.GetWorldPoint(this.m_localAnchor1); | |
} | |
b2GearJoint.prototype.GetAnchorB = function () { | |
return this.m_bodyB.GetWorldPoint(this.m_localAnchor2); | |
} | |
b2GearJoint.prototype.GetReactionForce = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
return new b2Vec2(inv_dt * this.m_impulse * this.m_J.linearB.x, inv_dt * this.m_impulse * this.m_J.linearB.y); | |
} | |
b2GearJoint.prototype.GetReactionTorque = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
var tMat = this.m_bodyB.m_xf.R; | |
var rX = this.m_localAnchor1.x - this.m_bodyB.m_sweep.localCenter.x; | |
var rY = this.m_localAnchor1.y - this.m_bodyB.m_sweep.localCenter.y; | |
var tX = tMat.col1.x * rX + tMat.col2.x * rY; | |
rY = tMat.col1.y * rX + tMat.col2.y * rY; | |
rX = tX; | |
var PX = this.m_impulse * this.m_J.linearB.x; | |
var PY = this.m_impulse * this.m_J.linearB.y; | |
return inv_dt * (this.m_impulse * this.m_J.angularB - rX * PY + rY * PX); | |
} | |
b2GearJoint.prototype.GetRatio = function () { | |
return this.m_ratio; | |
} | |
b2GearJoint.prototype.SetRatio = function (ratio) { | |
if (ratio === undefined) ratio = 0; | |
this.m_ratio = ratio; | |
} | |
b2GearJoint.prototype.b2GearJoint = function (def) { | |
this.__super.b2Joint.call(this, def); | |
var type1 = parseInt(def.joint1.m_type); | |
var type2 = parseInt(def.joint2.m_type); | |
this.m_revolute1 = null; | |
this.m_prismatic1 = null; | |
this.m_revolute2 = null; | |
this.m_prismatic2 = null; | |
var coordinate1 = 0; | |
var coordinate2 = 0; | |
this.m_ground1 = def.joint1.GetBodyA(); | |
this.m_bodyA = def.joint1.GetBodyB(); | |
if (type1 == b2Joint.e_revoluteJoint) { | |
this.m_revolute1 = (def.joint1 instanceof b2RevoluteJoint ? def.joint1 : null); | |
this.m_groundAnchor1.SetV(this.m_revolute1.m_localAnchor1); | |
this.m_localAnchor1.SetV(this.m_revolute1.m_localAnchor2); | |
coordinate1 = this.m_revolute1.GetJointAngle(); | |
} | |
else { | |
this.m_prismatic1 = (def.joint1 instanceof b2PrismaticJoint ? def.joint1 : null); | |
this.m_groundAnchor1.SetV(this.m_prismatic1.m_localAnchor1); | |
this.m_localAnchor1.SetV(this.m_prismatic1.m_localAnchor2); | |
coordinate1 = this.m_prismatic1.GetJointTranslation(); | |
} | |
this.m_ground2 = def.joint2.GetBodyA(); | |
this.m_bodyB = def.joint2.GetBodyB(); | |
if (type2 == b2Joint.e_revoluteJoint) { | |
this.m_revolute2 = (def.joint2 instanceof b2RevoluteJoint ? def.joint2 : null); | |
this.m_groundAnchor2.SetV(this.m_revolute2.m_localAnchor1); | |
this.m_localAnchor2.SetV(this.m_revolute2.m_localAnchor2); | |
coordinate2 = this.m_revolute2.GetJointAngle(); | |
} | |
else { | |
this.m_prismatic2 = (def.joint2 instanceof b2PrismaticJoint ? def.joint2 : null); | |
this.m_groundAnchor2.SetV(this.m_prismatic2.m_localAnchor1); | |
this.m_localAnchor2.SetV(this.m_prismatic2.m_localAnchor2); | |
coordinate2 = this.m_prismatic2.GetJointTranslation(); | |
} | |
this.m_ratio = def.ratio; | |
this.m_constant = coordinate1 + this.m_ratio * coordinate2; | |
this.m_impulse = 0.0; | |
} | |
b2GearJoint.prototype.InitVelocityConstraints = function (step) { | |
var g1 = this.m_ground1; | |
var g2 = this.m_ground2; | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var ugX = 0; | |
var ugY = 0; | |
var rX = 0; | |
var rY = 0; | |
var tMat; | |
var tVec; | |
var crug = 0; | |
var tX = 0; | |
var K = 0.0; | |
this.m_J.SetZero(); | |
if (this.m_revolute1) { | |
this.m_J.angularA = (-1.0); | |
K += bA.m_invI; | |
} | |
else { | |
tMat = g1.m_xf.R; | |
tVec = this.m_prismatic1.m_localXAxis1; | |
ugX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; | |
ugY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; | |
tMat = bA.m_xf.R; | |
rX = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; | |
rY = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; | |
tX = tMat.col1.x * rX + tMat.col2.x * rY; | |
rY = tMat.col1.y * rX + tMat.col2.y * rY; | |
rX = tX; | |
crug = rX * ugY - rY * ugX; | |
this.m_J.linearA.Set((-ugX), (-ugY)); | |
this.m_J.angularA = (-crug); | |
K += bA.m_invMass + bA.m_invI * crug * crug; | |
} | |
if (this.m_revolute2) { | |
this.m_J.angularB = (-this.m_ratio); | |
K += this.m_ratio * this.m_ratio * bB.m_invI; | |
} | |
else { | |
tMat = g2.m_xf.R; | |
tVec = this.m_prismatic2.m_localXAxis1; | |
ugX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; | |
ugY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; | |
tMat = bB.m_xf.R; | |
rX = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; | |
rY = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; | |
tX = tMat.col1.x * rX + tMat.col2.x * rY; | |
rY = tMat.col1.y * rX + tMat.col2.y * rY; | |
rX = tX; | |
crug = rX * ugY - rY * ugX; | |
this.m_J.linearB.Set((-this.m_ratio * ugX), (-this.m_ratio * ugY)); | |
this.m_J.angularB = (-this.m_ratio * crug); | |
K += this.m_ratio * this.m_ratio * (bB.m_invMass + bB.m_invI * crug * crug); | |
} | |
this.m_mass = K > 0.0 ? 1.0 / K : 0.0; | |
if (step.warmStarting) { | |
bA.m_linearVelocity.x += bA.m_invMass * this.m_impulse * this.m_J.linearA.x; | |
bA.m_linearVelocity.y += bA.m_invMass * this.m_impulse * this.m_J.linearA.y; | |
bA.m_angularVelocity += bA.m_invI * this.m_impulse * this.m_J.angularA; | |
bB.m_linearVelocity.x += bB.m_invMass * this.m_impulse * this.m_J.linearB.x; | |
bB.m_linearVelocity.y += bB.m_invMass * this.m_impulse * this.m_J.linearB.y; | |
bB.m_angularVelocity += bB.m_invI * this.m_impulse * this.m_J.angularB; | |
} | |
else { | |
this.m_impulse = 0.0; | |
} | |
} | |
b2GearJoint.prototype.SolveVelocityConstraints = function (step) { | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var Cdot = this.m_J.Compute(bA.m_linearVelocity, bA.m_angularVelocity, bB.m_linearVelocity, bB.m_angularVelocity); | |
var impulse = (-this.m_mass * Cdot); | |
this.m_impulse += impulse; | |
bA.m_linearVelocity.x += bA.m_invMass * impulse * this.m_J.linearA.x; | |
bA.m_linearVelocity.y += bA.m_invMass * impulse * this.m_J.linearA.y; | |
bA.m_angularVelocity += bA.m_invI * impulse * this.m_J.angularA; | |
bB.m_linearVelocity.x += bB.m_invMass * impulse * this.m_J.linearB.x; | |
bB.m_linearVelocity.y += bB.m_invMass * impulse * this.m_J.linearB.y; | |
bB.m_angularVelocity += bB.m_invI * impulse * this.m_J.angularB; | |
} | |
b2GearJoint.prototype.SolvePositionConstraints = function (baumgarte) { | |
if (baumgarte === undefined) baumgarte = 0; | |
var linearError = 0.0; | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var coordinate1 = 0; | |
var coordinate2 = 0; | |
if (this.m_revolute1) { | |
coordinate1 = this.m_revolute1.GetJointAngle(); | |
} | |
else { | |
coordinate1 = this.m_prismatic1.GetJointTranslation(); | |
} | |
if (this.m_revolute2) { | |
coordinate2 = this.m_revolute2.GetJointAngle(); | |
} | |
else { | |
coordinate2 = this.m_prismatic2.GetJointTranslation(); | |
} | |
var C = this.m_constant - (coordinate1 + this.m_ratio * coordinate2); | |
var impulse = (-this.m_mass * C); | |
bA.m_sweep.c.x += bA.m_invMass * impulse * this.m_J.linearA.x; | |
bA.m_sweep.c.y += bA.m_invMass * impulse * this.m_J.linearA.y; | |
bA.m_sweep.a += bA.m_invI * impulse * this.m_J.angularA; | |
bB.m_sweep.c.x += bB.m_invMass * impulse * this.m_J.linearB.x; | |
bB.m_sweep.c.y += bB.m_invMass * impulse * this.m_J.linearB.y; | |
bB.m_sweep.a += bB.m_invI * impulse * this.m_J.angularB; | |
bA.SynchronizeTransform(); | |
bB.SynchronizeTransform(); | |
return linearError < b2Settings.b2_linearSlop; | |
} | |
Box2D.inherit(b2GearJointDef, Box2D.Dynamics.Joints.b2JointDef); | |
b2GearJointDef.prototype.__super = Box2D.Dynamics.Joints.b2JointDef.prototype; | |
b2GearJointDef.b2GearJointDef = function () { | |
Box2D.Dynamics.Joints.b2JointDef.b2JointDef.apply(this, arguments); | |
}; | |
b2GearJointDef.prototype.b2GearJointDef = function () { | |
this.__super.b2JointDef.call(this); | |
this.type = b2Joint.e_gearJoint; | |
this.joint1 = null; | |
this.joint2 = null; | |
this.ratio = 1.0; | |
} | |
b2Jacobian.b2Jacobian = function () { | |
this.linearA = new b2Vec2(); | |
this.linearB = new b2Vec2(); | |
}; | |
b2Jacobian.prototype.SetZero = function () { | |
this.linearA.SetZero(); | |
this.angularA = 0.0; | |
this.linearB.SetZero(); | |
this.angularB = 0.0; | |
} | |
b2Jacobian.prototype.Set = function (x1, a1, x2, a2) { | |
if (a1 === undefined) a1 = 0; | |
if (a2 === undefined) a2 = 0; | |
this.linearA.SetV(x1); | |
this.angularA = a1; | |
this.linearB.SetV(x2); | |
this.angularB = a2; | |
} | |
b2Jacobian.prototype.Compute = function (x1, a1, x2, a2) { | |
if (a1 === undefined) a1 = 0; | |
if (a2 === undefined) a2 = 0; | |
return (this.linearA.x * x1.x + this.linearA.y * x1.y) + this.angularA * a1 + (this.linearB.x * x2.x + this.linearB.y * x2.y) + this.angularB * a2; | |
} | |
b2Joint.b2Joint = function () { | |
this.m_edgeA = new b2JointEdge(); | |
this.m_edgeB = new b2JointEdge(); | |
this.m_localCenterA = new b2Vec2(); | |
this.m_localCenterB = new b2Vec2(); | |
}; | |
b2Joint.prototype.GetType = function () { | |
return this.m_type; | |
} | |
b2Joint.prototype.GetAnchorA = function () { | |
return null; | |
} | |
b2Joint.prototype.GetAnchorB = function () { | |
return null; | |
} | |
b2Joint.prototype.GetReactionForce = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
return null; | |
} | |
b2Joint.prototype.GetReactionTorque = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
return 0.0; | |
} | |
b2Joint.prototype.GetBodyA = function () { | |
return this.m_bodyA; | |
} | |
b2Joint.prototype.GetBodyB = function () { | |
return this.m_bodyB; | |
} | |
b2Joint.prototype.GetNext = function () { | |
return this.m_next; | |
} | |
b2Joint.prototype.GetUserData = function () { | |
return this.m_userData; | |
} | |
b2Joint.prototype.SetUserData = function (data) { | |
this.m_userData = data; | |
} | |
b2Joint.prototype.IsActive = function () { | |
return this.m_bodyA.IsActive() && this.m_bodyB.IsActive(); | |
} | |
b2Joint.Create = function (def, allocator) { | |
var joint = null; | |
switch (def.type) { | |
case b2Joint.e_distanceJoint: | |
{ | |
joint = new b2DistanceJoint((def instanceof b2DistanceJointDef ? def : null)); | |
} | |
break; | |
case b2Joint.e_mouseJoint: | |
{ | |
joint = new b2MouseJoint((def instanceof b2MouseJointDef ? def : null)); | |
} | |
break; | |
case b2Joint.e_prismaticJoint: | |
{ | |
joint = new b2PrismaticJoint((def instanceof b2PrismaticJointDef ? def : null)); | |
} | |
break; | |
case b2Joint.e_revoluteJoint: | |
{ | |
joint = new b2RevoluteJoint((def instanceof b2RevoluteJointDef ? def : null)); | |
} | |
break; | |
case b2Joint.e_pulleyJoint: | |
{ | |
joint = new b2PulleyJoint((def instanceof b2PulleyJointDef ? def : null)); | |
} | |
break; | |
case b2Joint.e_gearJoint: | |
{ | |
joint = new b2GearJoint((def instanceof b2GearJointDef ? def : null)); | |
} | |
break; | |
case b2Joint.e_lineJoint: | |
{ | |
joint = new b2LineJoint((def instanceof b2LineJointDef ? def : null)); | |
} | |
break; | |
case b2Joint.e_weldJoint: | |
{ | |
joint = new b2WeldJoint((def instanceof b2WeldJointDef ? def : null)); | |
} | |
break; | |
case b2Joint.e_frictionJoint: | |
{ | |
joint = new b2FrictionJoint((def instanceof b2FrictionJointDef ? def : null)); | |
} | |
break; | |
default: | |
break; | |
} | |
return joint; | |
} | |
b2Joint.Destroy = function (joint, allocator) {} | |
b2Joint.prototype.b2Joint = function (def) { | |
b2Settings.b2Assert(def.bodyA != def.bodyB); | |
this.m_type = def.type; | |
this.m_prev = null; | |
this.m_next = null; | |
this.m_bodyA = def.bodyA; | |
this.m_bodyB = def.bodyB; | |
this.m_collideConnected = def.collideConnected; | |
this.m_islandFlag = false; | |
this.m_userData = def.userData; | |
} | |
b2Joint.prototype.InitVelocityConstraints = function (step) {} | |
b2Joint.prototype.SolveVelocityConstraints = function (step) {} | |
b2Joint.prototype.FinalizeVelocityConstraints = function () {} | |
b2Joint.prototype.SolvePositionConstraints = function (baumgarte) { | |
if (baumgarte === undefined) baumgarte = 0; | |
return false; | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Dynamics.Joints.b2Joint.e_unknownJoint = 0; | |
Box2D.Dynamics.Joints.b2Joint.e_revoluteJoint = 1; | |
Box2D.Dynamics.Joints.b2Joint.e_prismaticJoint = 2; | |
Box2D.Dynamics.Joints.b2Joint.e_distanceJoint = 3; | |
Box2D.Dynamics.Joints.b2Joint.e_pulleyJoint = 4; | |
Box2D.Dynamics.Joints.b2Joint.e_mouseJoint = 5; | |
Box2D.Dynamics.Joints.b2Joint.e_gearJoint = 6; | |
Box2D.Dynamics.Joints.b2Joint.e_lineJoint = 7; | |
Box2D.Dynamics.Joints.b2Joint.e_weldJoint = 8; | |
Box2D.Dynamics.Joints.b2Joint.e_frictionJoint = 9; | |
Box2D.Dynamics.Joints.b2Joint.e_inactiveLimit = 0; | |
Box2D.Dynamics.Joints.b2Joint.e_atLowerLimit = 1; | |
Box2D.Dynamics.Joints.b2Joint.e_atUpperLimit = 2; | |
Box2D.Dynamics.Joints.b2Joint.e_equalLimits = 3; | |
}); | |
b2JointDef.b2JointDef = function () {}; | |
b2JointDef.prototype.b2JointDef = function () { | |
this.type = b2Joint.e_unknownJoint; | |
this.userData = null; | |
this.bodyA = null; | |
this.bodyB = null; | |
this.collideConnected = false; | |
} | |
b2JointEdge.b2JointEdge = function () {}; | |
Box2D.inherit(b2LineJoint, Box2D.Dynamics.Joints.b2Joint); | |
b2LineJoint.prototype.__super = Box2D.Dynamics.Joints.b2Joint.prototype; | |
b2LineJoint.b2LineJoint = function () { | |
Box2D.Dynamics.Joints.b2Joint.b2Joint.apply(this, arguments); | |
this.m_localAnchor1 = new b2Vec2(); | |
this.m_localAnchor2 = new b2Vec2(); | |
this.m_localXAxis1 = new b2Vec2(); | |
this.m_localYAxis1 = new b2Vec2(); | |
this.m_axis = new b2Vec2(); | |
this.m_perp = new b2Vec2(); | |
this.m_K = new b2Mat22(); | |
this.m_impulse = new b2Vec2(); | |
}; | |
b2LineJoint.prototype.GetAnchorA = function () { | |
return this.m_bodyA.GetWorldPoint(this.m_localAnchor1); | |
} | |
b2LineJoint.prototype.GetAnchorB = function () { | |
return this.m_bodyB.GetWorldPoint(this.m_localAnchor2); | |
} | |
b2LineJoint.prototype.GetReactionForce = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
return new b2Vec2(inv_dt * (this.m_impulse.x * this.m_perp.x + (this.m_motorImpulse + this.m_impulse.y) * this.m_axis.x), inv_dt * (this.m_impulse.x * this.m_perp.y + (this.m_motorImpulse + this.m_impulse.y) * this.m_axis.y)); | |
} | |
b2LineJoint.prototype.GetReactionTorque = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
return inv_dt * this.m_impulse.y; | |
} | |
b2LineJoint.prototype.GetJointTranslation = function () { | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var tMat; | |
var p1 = bA.GetWorldPoint(this.m_localAnchor1); | |
var p2 = bB.GetWorldPoint(this.m_localAnchor2); | |
var dX = p2.x - p1.x; | |
var dY = p2.y - p1.y; | |
var axis = bA.GetWorldVector(this.m_localXAxis1); | |
var translation = axis.x * dX + axis.y * dY; | |
return translation; | |
} | |
b2LineJoint.prototype.GetJointSpeed = function () { | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var tMat; | |
tMat = bA.m_xf.R; | |
var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; | |
var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; | |
var tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); | |
r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); | |
r1X = tX; | |
tMat = bB.m_xf.R; | |
var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; | |
var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); | |
r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); | |
r2X = tX; | |
var p1X = bA.m_sweep.c.x + r1X; | |
var p1Y = bA.m_sweep.c.y + r1Y; | |
var p2X = bB.m_sweep.c.x + r2X; | |
var p2Y = bB.m_sweep.c.y + r2Y; | |
var dX = p2X - p1X; | |
var dY = p2Y - p1Y; | |
var axis = bA.GetWorldVector(this.m_localXAxis1); | |
var v1 = bA.m_linearVelocity; | |
var v2 = bB.m_linearVelocity; | |
var w1 = bA.m_angularVelocity; | |
var w2 = bB.m_angularVelocity; | |
var speed = (dX * ((-w1 * axis.y)) + dY * (w1 * axis.x)) + (axis.x * (((v2.x + ((-w2 * r2Y))) - v1.x) - ((-w1 * r1Y))) + axis.y * (((v2.y + (w2 * r2X)) - v1.y) - (w1 * r1X))); | |
return speed; | |
} | |
b2LineJoint.prototype.IsLimitEnabled = function () { | |
return this.m_enableLimit; | |
} | |
b2LineJoint.prototype.EnableLimit = function (flag) { | |
this.m_bodyA.SetAwake(true); | |
this.m_bodyB.SetAwake(true); | |
this.m_enableLimit = flag; | |
} | |
b2LineJoint.prototype.GetLowerLimit = function () { | |
return this.m_lowerTranslation; | |
} | |
b2LineJoint.prototype.GetUpperLimit = function () { | |
return this.m_upperTranslation; | |
} | |
b2LineJoint.prototype.SetLimits = function (lower, upper) { | |
if (lower === undefined) lower = 0; | |
if (upper === undefined) upper = 0; | |
this.m_bodyA.SetAwake(true); | |
this.m_bodyB.SetAwake(true); | |
this.m_lowerTranslation = lower; | |
this.m_upperTranslation = upper; | |
} | |
b2LineJoint.prototype.IsMotorEnabled = function () { | |
return this.m_enableMotor; | |
} | |
b2LineJoint.prototype.EnableMotor = function (flag) { | |
this.m_bodyA.SetAwake(true); | |
this.m_bodyB.SetAwake(true); | |
this.m_enableMotor = flag; | |
} | |
b2LineJoint.prototype.SetMotorSpeed = function (speed) { | |
if (speed === undefined) speed = 0; | |
this.m_bodyA.SetAwake(true); | |
this.m_bodyB.SetAwake(true); | |
this.m_motorSpeed = speed; | |
} | |
b2LineJoint.prototype.GetMotorSpeed = function () { | |
return this.m_motorSpeed; | |
} | |
b2LineJoint.prototype.SetMaxMotorForce = function (force) { | |
if (force === undefined) force = 0; | |
this.m_bodyA.SetAwake(true); | |
this.m_bodyB.SetAwake(true); | |
this.m_maxMotorForce = force; | |
} | |
b2LineJoint.prototype.GetMaxMotorForce = function () { | |
return this.m_maxMotorForce; | |
} | |
b2LineJoint.prototype.GetMotorForce = function () { | |
return this.m_motorImpulse; | |
} | |
b2LineJoint.prototype.b2LineJoint = function (def) { | |
this.__super.b2Joint.call(this, def); | |
var tMat; | |
var tX = 0; | |
var tY = 0; | |
this.m_localAnchor1.SetV(def.localAnchorA); | |
this.m_localAnchor2.SetV(def.localAnchorB); | |
this.m_localXAxis1.SetV(def.localAxisA); | |
this.m_localYAxis1.x = (-this.m_localXAxis1.y); | |
this.m_localYAxis1.y = this.m_localXAxis1.x; | |
this.m_impulse.SetZero(); | |
this.m_motorMass = 0.0; | |
this.m_motorImpulse = 0.0; | |
this.m_lowerTranslation = def.lowerTranslation; | |
this.m_upperTranslation = def.upperTranslation; | |
this.m_maxMotorForce = def.maxMotorForce; | |
this.m_motorSpeed = def.motorSpeed; | |
this.m_enableLimit = def.enableLimit; | |
this.m_enableMotor = def.enableMotor; | |
this.m_limitState = b2Joint.e_inactiveLimit; | |
this.m_axis.SetZero(); | |
this.m_perp.SetZero(); | |
} | |
b2LineJoint.prototype.InitVelocityConstraints = function (step) { | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var tMat; | |
var tX = 0; | |
this.m_localCenterA.SetV(bA.GetLocalCenter()); | |
this.m_localCenterB.SetV(bB.GetLocalCenter()); | |
var xf1 = bA.GetTransform(); | |
var xf2 = bB.GetTransform(); | |
tMat = bA.m_xf.R; | |
var r1X = this.m_localAnchor1.x - this.m_localCenterA.x; | |
var r1Y = this.m_localAnchor1.y - this.m_localCenterA.y; | |
tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); | |
r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); | |
r1X = tX; | |
tMat = bB.m_xf.R; | |
var r2X = this.m_localAnchor2.x - this.m_localCenterB.x; | |
var r2Y = this.m_localAnchor2.y - this.m_localCenterB.y; | |
tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); | |
r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); | |
r2X = tX; | |
var dX = bB.m_sweep.c.x + r2X - bA.m_sweep.c.x - r1X; | |
var dY = bB.m_sweep.c.y + r2Y - bA.m_sweep.c.y - r1Y; | |
this.m_invMassA = bA.m_invMass; | |
this.m_invMassB = bB.m_invMass; | |
this.m_invIA = bA.m_invI; | |
this.m_invIB = bB.m_invI; { | |
this.m_axis.SetV(b2Math.MulMV(xf1.R, this.m_localXAxis1)); | |
this.m_a1 = (dX + r1X) * this.m_axis.y - (dY + r1Y) * this.m_axis.x; | |
this.m_a2 = r2X * this.m_axis.y - r2Y * this.m_axis.x; | |
this.m_motorMass = this.m_invMassA + this.m_invMassB + this.m_invIA * this.m_a1 * this.m_a1 + this.m_invIB * this.m_a2 * this.m_a2; | |
this.m_motorMass = this.m_motorMass > Number.MIN_VALUE ? 1.0 / this.m_motorMass : 0.0; | |
} { | |
this.m_perp.SetV(b2Math.MulMV(xf1.R, this.m_localYAxis1)); | |
this.m_s1 = (dX + r1X) * this.m_perp.y - (dY + r1Y) * this.m_perp.x; | |
this.m_s2 = r2X * this.m_perp.y - r2Y * this.m_perp.x; | |
var m1 = this.m_invMassA; | |
var m2 = this.m_invMassB; | |
var i1 = this.m_invIA; | |
var i2 = this.m_invIB; | |
this.m_K.col1.x = m1 + m2 + i1 * this.m_s1 * this.m_s1 + i2 * this.m_s2 * this.m_s2; | |
this.m_K.col1.y = i1 * this.m_s1 * this.m_a1 + i2 * this.m_s2 * this.m_a2; | |
this.m_K.col2.x = this.m_K.col1.y; | |
this.m_K.col2.y = m1 + m2 + i1 * this.m_a1 * this.m_a1 + i2 * this.m_a2 * this.m_a2; | |
} | |
if (this.m_enableLimit) { | |
var jointTransition = this.m_axis.x * dX + this.m_axis.y * dY; | |
if (b2Math.Abs(this.m_upperTranslation - this.m_lowerTranslation) < 2.0 * b2Settings.b2_linearSlop) { | |
this.m_limitState = b2Joint.e_equalLimits; | |
} | |
else if (jointTransition <= this.m_lowerTranslation) { | |
if (this.m_limitState != b2Joint.e_atLowerLimit) { | |
this.m_limitState = b2Joint.e_atLowerLimit; | |
this.m_impulse.y = 0.0; | |
} | |
} | |
else if (jointTransition >= this.m_upperTranslation) { | |
if (this.m_limitState != b2Joint.e_atUpperLimit) { | |
this.m_limitState = b2Joint.e_atUpperLimit; | |
this.m_impulse.y = 0.0; | |
} | |
} | |
else { | |
this.m_limitState = b2Joint.e_inactiveLimit; | |
this.m_impulse.y = 0.0; | |
} | |
} | |
else { | |
this.m_limitState = b2Joint.e_inactiveLimit; | |
} | |
if (this.m_enableMotor == false) { | |
this.m_motorImpulse = 0.0; | |
} | |
if (step.warmStarting) { | |
this.m_impulse.x *= step.dtRatio; | |
this.m_impulse.y *= step.dtRatio; | |
this.m_motorImpulse *= step.dtRatio; | |
var PX = this.m_impulse.x * this.m_perp.x + (this.m_motorImpulse + this.m_impulse.y) * this.m_axis.x; | |
var PY = this.m_impulse.x * this.m_perp.y + (this.m_motorImpulse + this.m_impulse.y) * this.m_axis.y; | |
var L1 = this.m_impulse.x * this.m_s1 + (this.m_motorImpulse + this.m_impulse.y) * this.m_a1; | |
var L2 = this.m_impulse.x * this.m_s2 + (this.m_motorImpulse + this.m_impulse.y) * this.m_a2; | |
bA.m_linearVelocity.x -= this.m_invMassA * PX; | |
bA.m_linearVelocity.y -= this.m_invMassA * PY; | |
bA.m_angularVelocity -= this.m_invIA * L1; | |
bB.m_linearVelocity.x += this.m_invMassB * PX; | |
bB.m_linearVelocity.y += this.m_invMassB * PY; | |
bB.m_angularVelocity += this.m_invIB * L2; | |
} | |
else { | |
this.m_impulse.SetZero(); | |
this.m_motorImpulse = 0.0; | |
} | |
} | |
b2LineJoint.prototype.SolveVelocityConstraints = function (step) { | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var v1 = bA.m_linearVelocity; | |
var w1 = bA.m_angularVelocity; | |
var v2 = bB.m_linearVelocity; | |
var w2 = bB.m_angularVelocity; | |
var PX = 0; | |
var PY = 0; | |
var L1 = 0; | |
var L2 = 0; | |
if (this.m_enableMotor && this.m_limitState != b2Joint.e_equalLimits) { | |
var Cdot = this.m_axis.x * (v2.x - v1.x) + this.m_axis.y * (v2.y - v1.y) + this.m_a2 * w2 - this.m_a1 * w1; | |
var impulse = this.m_motorMass * (this.m_motorSpeed - Cdot); | |
var oldImpulse = this.m_motorImpulse; | |
var maxImpulse = step.dt * this.m_maxMotorForce; | |
this.m_motorImpulse = b2Math.Clamp(this.m_motorImpulse + impulse, (-maxImpulse), maxImpulse); | |
impulse = this.m_motorImpulse - oldImpulse; | |
PX = impulse * this.m_axis.x; | |
PY = impulse * this.m_axis.y; | |
L1 = impulse * this.m_a1; | |
L2 = impulse * this.m_a2; | |
v1.x -= this.m_invMassA * PX; | |
v1.y -= this.m_invMassA * PY; | |
w1 -= this.m_invIA * L1; | |
v2.x += this.m_invMassB * PX; | |
v2.y += this.m_invMassB * PY; | |
w2 += this.m_invIB * L2; | |
} | |
var Cdot1 = this.m_perp.x * (v2.x - v1.x) + this.m_perp.y * (v2.y - v1.y) + this.m_s2 * w2 - this.m_s1 * w1; | |
if (this.m_enableLimit && this.m_limitState != b2Joint.e_inactiveLimit) { | |
var Cdot2 = this.m_axis.x * (v2.x - v1.x) + this.m_axis.y * (v2.y - v1.y) + this.m_a2 * w2 - this.m_a1 * w1; | |
var f1 = this.m_impulse.Copy(); | |
var df = this.m_K.Solve(new b2Vec2(), (-Cdot1), (-Cdot2)); | |
this.m_impulse.Add(df); | |
if (this.m_limitState == b2Joint.e_atLowerLimit) { | |
this.m_impulse.y = b2Math.Max(this.m_impulse.y, 0.0); | |
} | |
else if (this.m_limitState == b2Joint.e_atUpperLimit) { | |
this.m_impulse.y = b2Math.Min(this.m_impulse.y, 0.0); | |
} | |
var b = (-Cdot1) - (this.m_impulse.y - f1.y) * this.m_K.col2.x; | |
var f2r = 0; | |
if (this.m_K.col1.x != 0.0) { | |
f2r = b / this.m_K.col1.x + f1.x; | |
} | |
else { | |
f2r = f1.x; | |
} | |
this.m_impulse.x = f2r; | |
df.x = this.m_impulse.x - f1.x; | |
df.y = this.m_impulse.y - f1.y; | |
PX = df.x * this.m_perp.x + df.y * this.m_axis.x; | |
PY = df.x * this.m_perp.y + df.y * this.m_axis.y; | |
L1 = df.x * this.m_s1 + df.y * this.m_a1; | |
L2 = df.x * this.m_s2 + df.y * this.m_a2; | |
v1.x -= this.m_invMassA * PX; | |
v1.y -= this.m_invMassA * PY; | |
w1 -= this.m_invIA * L1; | |
v2.x += this.m_invMassB * PX; | |
v2.y += this.m_invMassB * PY; | |
w2 += this.m_invIB * L2; | |
} | |
else { | |
var df2 = 0; | |
if (this.m_K.col1.x != 0.0) { | |
df2 = ((-Cdot1)) / this.m_K.col1.x; | |
} | |
else { | |
df2 = 0.0; | |
} | |
this.m_impulse.x += df2; | |
PX = df2 * this.m_perp.x; | |
PY = df2 * this.m_perp.y; | |
L1 = df2 * this.m_s1; | |
L2 = df2 * this.m_s2; | |
v1.x -= this.m_invMassA * PX; | |
v1.y -= this.m_invMassA * PY; | |
w1 -= this.m_invIA * L1; | |
v2.x += this.m_invMassB * PX; | |
v2.y += this.m_invMassB * PY; | |
w2 += this.m_invIB * L2; | |
} | |
bA.m_linearVelocity.SetV(v1); | |
bA.m_angularVelocity = w1; | |
bB.m_linearVelocity.SetV(v2); | |
bB.m_angularVelocity = w2; | |
} | |
b2LineJoint.prototype.SolvePositionConstraints = function (baumgarte) { | |
if (baumgarte === undefined) baumgarte = 0; | |
var limitC = 0; | |
var oldLimitImpulse = 0; | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var c1 = bA.m_sweep.c; | |
var a1 = bA.m_sweep.a; | |
var c2 = bB.m_sweep.c; | |
var a2 = bB.m_sweep.a; | |
var tMat; | |
var tX = 0; | |
var m1 = 0; | |
var m2 = 0; | |
var i1 = 0; | |
var i2 = 0; | |
var linearError = 0.0; | |
var angularError = 0.0; | |
var active = false; | |
var C2 = 0.0; | |
var R1 = b2Mat22.FromAngle(a1); | |
var R2 = b2Mat22.FromAngle(a2); | |
tMat = R1; | |
var r1X = this.m_localAnchor1.x - this.m_localCenterA.x; | |
var r1Y = this.m_localAnchor1.y - this.m_localCenterA.y; | |
tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); | |
r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); | |
r1X = tX; | |
tMat = R2; | |
var r2X = this.m_localAnchor2.x - this.m_localCenterB.x; | |
var r2Y = this.m_localAnchor2.y - this.m_localCenterB.y; | |
tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); | |
r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); | |
r2X = tX; | |
var dX = c2.x + r2X - c1.x - r1X; | |
var dY = c2.y + r2Y - c1.y - r1Y; | |
if (this.m_enableLimit) { | |
this.m_axis = b2Math.MulMV(R1, this.m_localXAxis1); | |
this.m_a1 = (dX + r1X) * this.m_axis.y - (dY + r1Y) * this.m_axis.x; | |
this.m_a2 = r2X * this.m_axis.y - r2Y * this.m_axis.x; | |
var translation = this.m_axis.x * dX + this.m_axis.y * dY; | |
if (b2Math.Abs(this.m_upperTranslation - this.m_lowerTranslation) < 2.0 * b2Settings.b2_linearSlop) { | |
C2 = b2Math.Clamp(translation, (-b2Settings.b2_maxLinearCorrection), b2Settings.b2_maxLinearCorrection); | |
linearError = b2Math.Abs(translation); | |
active = true; | |
} | |
else if (translation <= this.m_lowerTranslation) { | |
C2 = b2Math.Clamp(translation - this.m_lowerTranslation + b2Settings.b2_linearSlop, (-b2Settings.b2_maxLinearCorrection), 0.0); | |
linearError = this.m_lowerTranslation - translation; | |
active = true; | |
} | |
else if (translation >= this.m_upperTranslation) { | |
C2 = b2Math.Clamp(translation - this.m_upperTranslation + b2Settings.b2_linearSlop, 0.0, b2Settings.b2_maxLinearCorrection); | |
linearError = translation - this.m_upperTranslation; | |
active = true; | |
} | |
} | |
this.m_perp = b2Math.MulMV(R1, this.m_localYAxis1); | |
this.m_s1 = (dX + r1X) * this.m_perp.y - (dY + r1Y) * this.m_perp.x; | |
this.m_s2 = r2X * this.m_perp.y - r2Y * this.m_perp.x; | |
var impulse = new b2Vec2(); | |
var C1 = this.m_perp.x * dX + this.m_perp.y * dY; | |
linearError = b2Math.Max(linearError, b2Math.Abs(C1)); | |
angularError = 0.0; | |
if (active) { | |
m1 = this.m_invMassA; | |
m2 = this.m_invMassB; | |
i1 = this.m_invIA; | |
i2 = this.m_invIB; | |
this.m_K.col1.x = m1 + m2 + i1 * this.m_s1 * this.m_s1 + i2 * this.m_s2 * this.m_s2; | |
this.m_K.col1.y = i1 * this.m_s1 * this.m_a1 + i2 * this.m_s2 * this.m_a2; | |
this.m_K.col2.x = this.m_K.col1.y; | |
this.m_K.col2.y = m1 + m2 + i1 * this.m_a1 * this.m_a1 + i2 * this.m_a2 * this.m_a2; | |
this.m_K.Solve(impulse, (-C1), (-C2)); | |
} | |
else { | |
m1 = this.m_invMassA; | |
m2 = this.m_invMassB; | |
i1 = this.m_invIA; | |
i2 = this.m_invIB; | |
var k11 = m1 + m2 + i1 * this.m_s1 * this.m_s1 + i2 * this.m_s2 * this.m_s2; | |
var impulse1 = 0; | |
if (k11 != 0.0) { | |
impulse1 = ((-C1)) / k11; | |
} | |
else { | |
impulse1 = 0.0; | |
} | |
impulse.x = impulse1; | |
impulse.y = 0.0; | |
} | |
var PX = impulse.x * this.m_perp.x + impulse.y * this.m_axis.x; | |
var PY = impulse.x * this.m_perp.y + impulse.y * this.m_axis.y; | |
var L1 = impulse.x * this.m_s1 + impulse.y * this.m_a1; | |
var L2 = impulse.x * this.m_s2 + impulse.y * this.m_a2; | |
c1.x -= this.m_invMassA * PX; | |
c1.y -= this.m_invMassA * PY; | |
a1 -= this.m_invIA * L1; | |
c2.x += this.m_invMassB * PX; | |
c2.y += this.m_invMassB * PY; | |
a2 += this.m_invIB * L2; | |
bA.m_sweep.a = a1; | |
bB.m_sweep.a = a2; | |
bA.SynchronizeTransform(); | |
bB.SynchronizeTransform(); | |
return linearError <= b2Settings.b2_linearSlop && angularError <= b2Settings.b2_angularSlop; | |
} | |
Box2D.inherit(b2LineJointDef, Box2D.Dynamics.Joints.b2JointDef); | |
b2LineJointDef.prototype.__super = Box2D.Dynamics.Joints.b2JointDef.prototype; | |
b2LineJointDef.b2LineJointDef = function () { | |
Box2D.Dynamics.Joints.b2JointDef.b2JointDef.apply(this, arguments); | |
this.localAnchorA = new b2Vec2(); | |
this.localAnchorB = new b2Vec2(); | |
this.localAxisA = new b2Vec2(); | |
}; | |
b2LineJointDef.prototype.b2LineJointDef = function () { | |
this.__super.b2JointDef.call(this); | |
this.type = b2Joint.e_lineJoint; | |
this.localAxisA.Set(1.0, 0.0); | |
this.enableLimit = false; | |
this.lowerTranslation = 0.0; | |
this.upperTranslation = 0.0; | |
this.enableMotor = false; | |
this.maxMotorForce = 0.0; | |
this.motorSpeed = 0.0; | |
} | |
b2LineJointDef.prototype.Initialize = function (bA, bB, anchor, axis) { | |
this.bodyA = bA; | |
this.bodyB = bB; | |
this.localAnchorA = this.bodyA.GetLocalPoint(anchor); | |
this.localAnchorB = this.bodyB.GetLocalPoint(anchor); | |
this.localAxisA = this.bodyA.GetLocalVector(axis); | |
} | |
Box2D.inherit(b2MouseJoint, Box2D.Dynamics.Joints.b2Joint); | |
b2MouseJoint.prototype.__super = Box2D.Dynamics.Joints.b2Joint.prototype; | |
b2MouseJoint.b2MouseJoint = function () { | |
Box2D.Dynamics.Joints.b2Joint.b2Joint.apply(this, arguments); | |
this.K = new b2Mat22(); | |
this.K1 = new b2Mat22(); | |
this.K2 = new b2Mat22(); | |
this.m_localAnchor = new b2Vec2(); | |
this.m_target = new b2Vec2(); | |
this.m_impulse = new b2Vec2(); | |
this.m_mass = new b2Mat22(); | |
this.m_C = new b2Vec2(); | |
}; | |
b2MouseJoint.prototype.GetAnchorA = function () { | |
return this.m_target; | |
} | |
b2MouseJoint.prototype.GetAnchorB = function () { | |
return this.m_bodyB.GetWorldPoint(this.m_localAnchor); | |
} | |
b2MouseJoint.prototype.GetReactionForce = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
return new b2Vec2(inv_dt * this.m_impulse.x, inv_dt * this.m_impulse.y); | |
} | |
b2MouseJoint.prototype.GetReactionTorque = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
return 0.0; | |
} | |
b2MouseJoint.prototype.GetTarget = function () { | |
return this.m_target; | |
} | |
b2MouseJoint.prototype.SetTarget = function (target) { | |
if (this.m_bodyB.IsAwake() == false) { | |
this.m_bodyB.SetAwake(true); | |
} | |
this.m_target = target; | |
} | |
b2MouseJoint.prototype.GetMaxForce = function () { | |
return this.m_maxForce; | |
} | |
b2MouseJoint.prototype.SetMaxForce = function (maxForce) { | |
if (maxForce === undefined) maxForce = 0; | |
this.m_maxForce = maxForce; | |
} | |
b2MouseJoint.prototype.GetFrequency = function () { | |
return this.m_frequencyHz; | |
} | |
b2MouseJoint.prototype.SetFrequency = function (hz) { | |
if (hz === undefined) hz = 0; | |
this.m_frequencyHz = hz; | |
} | |
b2MouseJoint.prototype.GetDampingRatio = function () { | |
return this.m_dampingRatio; | |
} | |
b2MouseJoint.prototype.SetDampingRatio = function (ratio) { | |
if (ratio === undefined) ratio = 0; | |
this.m_dampingRatio = ratio; | |
} | |
b2MouseJoint.prototype.b2MouseJoint = function (def) { | |
this.__super.b2Joint.call(this, def); | |
this.m_target.SetV(def.target); | |
var tX = this.m_target.x - this.m_bodyB.m_xf.position.x; | |
var tY = this.m_target.y - this.m_bodyB.m_xf.position.y; | |
var tMat = this.m_bodyB.m_xf.R; | |
this.m_localAnchor.x = (tX * tMat.col1.x + tY * tMat.col1.y); | |
this.m_localAnchor.y = (tX * tMat.col2.x + tY * tMat.col2.y); | |
this.m_maxForce = def.maxForce; | |
this.m_impulse.SetZero(); | |
this.m_frequencyHz = def.frequencyHz; | |
this.m_dampingRatio = def.dampingRatio; | |
this.m_beta = 0.0; | |
this.m_gamma = 0.0; | |
} | |
b2MouseJoint.prototype.InitVelocityConstraints = function (step) { | |
var b = this.m_bodyB; | |
var mass = b.GetMass(); | |
var omega = 2.0 * Math.PI * this.m_frequencyHz; | |
var d = 2.0 * mass * this.m_dampingRatio * omega; | |
var k = mass * omega * omega; | |
this.m_gamma = step.dt * (d + step.dt * k); | |
this.m_gamma = this.m_gamma != 0 ? 1 / this.m_gamma : 0.0; | |
this.m_beta = step.dt * k * this.m_gamma; | |
var tMat;tMat = b.m_xf.R; | |
var rX = this.m_localAnchor.x - b.m_sweep.localCenter.x; | |
var rY = this.m_localAnchor.y - b.m_sweep.localCenter.y; | |
var tX = (tMat.col1.x * rX + tMat.col2.x * rY);rY = (tMat.col1.y * rX + tMat.col2.y * rY); | |
rX = tX; | |
var invMass = b.m_invMass; | |
var invI = b.m_invI;this.K1.col1.x = invMass; | |
this.K1.col2.x = 0.0; | |
this.K1.col1.y = 0.0; | |
this.K1.col2.y = invMass; | |
this.K2.col1.x = invI * rY * rY; | |
this.K2.col2.x = (-invI * rX * rY); | |
this.K2.col1.y = (-invI * rX * rY); | |
this.K2.col2.y = invI * rX * rX; | |
this.K.SetM(this.K1); | |
this.K.AddM(this.K2); | |
this.K.col1.x += this.m_gamma; | |
this.K.col2.y += this.m_gamma; | |
this.K.GetInverse(this.m_mass); | |
this.m_C.x = b.m_sweep.c.x + rX - this.m_target.x; | |
this.m_C.y = b.m_sweep.c.y + rY - this.m_target.y; | |
b.m_angularVelocity *= 0.98; | |
this.m_impulse.x *= step.dtRatio; | |
this.m_impulse.y *= step.dtRatio; | |
b.m_linearVelocity.x += invMass * this.m_impulse.x; | |
b.m_linearVelocity.y += invMass * this.m_impulse.y; | |
b.m_angularVelocity += invI * (rX * this.m_impulse.y - rY * this.m_impulse.x); | |
} | |
b2MouseJoint.prototype.SolveVelocityConstraints = function (step) { | |
var b = this.m_bodyB; | |
var tMat; | |
var tX = 0; | |
var tY = 0; | |
tMat = b.m_xf.R; | |
var rX = this.m_localAnchor.x - b.m_sweep.localCenter.x; | |
var rY = this.m_localAnchor.y - b.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * rX + tMat.col2.x * rY); | |
rY = (tMat.col1.y * rX + tMat.col2.y * rY); | |
rX = tX; | |
var CdotX = b.m_linearVelocity.x + ((-b.m_angularVelocity * rY)); | |
var CdotY = b.m_linearVelocity.y + (b.m_angularVelocity * rX); | |
tMat = this.m_mass; | |
tX = CdotX + this.m_beta * this.m_C.x + this.m_gamma * this.m_impulse.x; | |
tY = CdotY + this.m_beta * this.m_C.y + this.m_gamma * this.m_impulse.y; | |
var impulseX = (-(tMat.col1.x * tX + tMat.col2.x * tY)); | |
var impulseY = (-(tMat.col1.y * tX + tMat.col2.y * tY)); | |
var oldImpulseX = this.m_impulse.x; | |
var oldImpulseY = this.m_impulse.y; | |
this.m_impulse.x += impulseX; | |
this.m_impulse.y += impulseY; | |
var maxImpulse = step.dt * this.m_maxForce; | |
if (this.m_impulse.LengthSquared() > maxImpulse * maxImpulse) { | |
this.m_impulse.Multiply(maxImpulse / this.m_impulse.Length()); | |
} | |
impulseX = this.m_impulse.x - oldImpulseX; | |
impulseY = this.m_impulse.y - oldImpulseY; | |
b.m_linearVelocity.x += b.m_invMass * impulseX; | |
b.m_linearVelocity.y += b.m_invMass * impulseY; | |
b.m_angularVelocity += b.m_invI * (rX * impulseY - rY * impulseX); | |
} | |
b2MouseJoint.prototype.SolvePositionConstraints = function (baumgarte) { | |
if (baumgarte === undefined) baumgarte = 0; | |
return true; | |
} | |
Box2D.inherit(b2MouseJointDef, Box2D.Dynamics.Joints.b2JointDef); | |
b2MouseJointDef.prototype.__super = Box2D.Dynamics.Joints.b2JointDef.prototype; | |
b2MouseJointDef.b2MouseJointDef = function () { | |
Box2D.Dynamics.Joints.b2JointDef.b2JointDef.apply(this, arguments); | |
this.target = new b2Vec2(); | |
}; | |
b2MouseJointDef.prototype.b2MouseJointDef = function () { | |
this.__super.b2JointDef.call(this); | |
this.type = b2Joint.e_mouseJoint; | |
this.maxForce = 0.0; | |
this.frequencyHz = 5.0; | |
this.dampingRatio = 0.7; | |
} | |
Box2D.inherit(b2PrismaticJoint, Box2D.Dynamics.Joints.b2Joint); | |
b2PrismaticJoint.prototype.__super = Box2D.Dynamics.Joints.b2Joint.prototype; | |
b2PrismaticJoint.b2PrismaticJoint = function () { | |
Box2D.Dynamics.Joints.b2Joint.b2Joint.apply(this, arguments); | |
this.m_localAnchor1 = new b2Vec2(); | |
this.m_localAnchor2 = new b2Vec2(); | |
this.m_localXAxis1 = new b2Vec2(); | |
this.m_localYAxis1 = new b2Vec2(); | |
this.m_axis = new b2Vec2(); | |
this.m_perp = new b2Vec2(); | |
this.m_K = new b2Mat33(); | |
this.m_impulse = new b2Vec3(); | |
}; | |
b2PrismaticJoint.prototype.GetAnchorA = function () { | |
return this.m_bodyA.GetWorldPoint(this.m_localAnchor1); | |
} | |
b2PrismaticJoint.prototype.GetAnchorB = function () { | |
return this.m_bodyB.GetWorldPoint(this.m_localAnchor2); | |
} | |
b2PrismaticJoint.prototype.GetReactionForce = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
return new b2Vec2(inv_dt * (this.m_impulse.x * this.m_perp.x + (this.m_motorImpulse + this.m_impulse.z) * this.m_axis.x), inv_dt * (this.m_impulse.x * this.m_perp.y + (this.m_motorImpulse + this.m_impulse.z) * this.m_axis.y)); | |
} | |
b2PrismaticJoint.prototype.GetReactionTorque = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
return inv_dt * this.m_impulse.y; | |
} | |
b2PrismaticJoint.prototype.GetJointTranslation = function () { | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var tMat; | |
var p1 = bA.GetWorldPoint(this.m_localAnchor1); | |
var p2 = bB.GetWorldPoint(this.m_localAnchor2); | |
var dX = p2.x - p1.x; | |
var dY = p2.y - p1.y; | |
var axis = bA.GetWorldVector(this.m_localXAxis1); | |
var translation = axis.x * dX + axis.y * dY; | |
return translation; | |
} | |
b2PrismaticJoint.prototype.GetJointSpeed = function () { | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var tMat; | |
tMat = bA.m_xf.R; | |
var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; | |
var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; | |
var tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); | |
r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); | |
r1X = tX; | |
tMat = bB.m_xf.R; | |
var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; | |
var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); | |
r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); | |
r2X = tX; | |
var p1X = bA.m_sweep.c.x + r1X; | |
var p1Y = bA.m_sweep.c.y + r1Y; | |
var p2X = bB.m_sweep.c.x + r2X; | |
var p2Y = bB.m_sweep.c.y + r2Y; | |
var dX = p2X - p1X; | |
var dY = p2Y - p1Y; | |
var axis = bA.GetWorldVector(this.m_localXAxis1); | |
var v1 = bA.m_linearVelocity; | |
var v2 = bB.m_linearVelocity; | |
var w1 = bA.m_angularVelocity; | |
var w2 = bB.m_angularVelocity; | |
var speed = (dX * ((-w1 * axis.y)) + dY * (w1 * axis.x)) + (axis.x * (((v2.x + ((-w2 * r2Y))) - v1.x) - ((-w1 * r1Y))) + axis.y * (((v2.y + (w2 * r2X)) - v1.y) - (w1 * r1X))); | |
return speed; | |
} | |
b2PrismaticJoint.prototype.IsLimitEnabled = function () { | |
return this.m_enableLimit; | |
} | |
b2PrismaticJoint.prototype.EnableLimit = function (flag) { | |
this.m_bodyA.SetAwake(true); | |
this.m_bodyB.SetAwake(true); | |
this.m_enableLimit = flag; | |
} | |
b2PrismaticJoint.prototype.GetLowerLimit = function () { | |
return this.m_lowerTranslation; | |
} | |
b2PrismaticJoint.prototype.GetUpperLimit = function () { | |
return this.m_upperTranslation; | |
} | |
b2PrismaticJoint.prototype.SetLimits = function (lower, upper) { | |
if (lower === undefined) lower = 0; | |
if (upper === undefined) upper = 0; | |
this.m_bodyA.SetAwake(true); | |
this.m_bodyB.SetAwake(true); | |
this.m_lowerTranslation = lower; | |
this.m_upperTranslation = upper; | |
} | |
b2PrismaticJoint.prototype.IsMotorEnabled = function () { | |
return this.m_enableMotor; | |
} | |
b2PrismaticJoint.prototype.EnableMotor = function (flag) { | |
this.m_bodyA.SetAwake(true); | |
this.m_bodyB.SetAwake(true); | |
this.m_enableMotor = flag; | |
} | |
b2PrismaticJoint.prototype.SetMotorSpeed = function (speed) { | |
if (speed === undefined) speed = 0; | |
this.m_bodyA.SetAwake(true); | |
this.m_bodyB.SetAwake(true); | |
this.m_motorSpeed = speed; | |
} | |
b2PrismaticJoint.prototype.GetMotorSpeed = function () { | |
return this.m_motorSpeed; | |
} | |
b2PrismaticJoint.prototype.SetMaxMotorForce = function (force) { | |
if (force === undefined) force = 0; | |
this.m_bodyA.SetAwake(true); | |
this.m_bodyB.SetAwake(true); | |
this.m_maxMotorForce = force; | |
} | |
b2PrismaticJoint.prototype.GetMotorForce = function () { | |
return this.m_motorImpulse; | |
} | |
b2PrismaticJoint.prototype.b2PrismaticJoint = function (def) { | |
this.__super.b2Joint.call(this, def); | |
var tMat; | |
var tX = 0; | |
var tY = 0; | |
this.m_localAnchor1.SetV(def.localAnchorA); | |
this.m_localAnchor2.SetV(def.localAnchorB); | |
this.m_localXAxis1.SetV(def.localAxisA); | |
this.m_localYAxis1.x = (-this.m_localXAxis1.y); | |
this.m_localYAxis1.y = this.m_localXAxis1.x; | |
this.m_refAngle = def.referenceAngle; | |
this.m_impulse.SetZero(); | |
this.m_motorMass = 0.0; | |
this.m_motorImpulse = 0.0; | |
this.m_lowerTranslation = def.lowerTranslation; | |
this.m_upperTranslation = def.upperTranslation; | |
this.m_maxMotorForce = def.maxMotorForce; | |
this.m_motorSpeed = def.motorSpeed; | |
this.m_enableLimit = def.enableLimit; | |
this.m_enableMotor = def.enableMotor; | |
this.m_limitState = b2Joint.e_inactiveLimit; | |
this.m_axis.SetZero(); | |
this.m_perp.SetZero(); | |
} | |
b2PrismaticJoint.prototype.InitVelocityConstraints = function (step) { | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var tMat; | |
var tX = 0; | |
this.m_localCenterA.SetV(bA.GetLocalCenter()); | |
this.m_localCenterB.SetV(bB.GetLocalCenter()); | |
var xf1 = bA.GetTransform(); | |
var xf2 = bB.GetTransform(); | |
tMat = bA.m_xf.R; | |
var r1X = this.m_localAnchor1.x - this.m_localCenterA.x; | |
var r1Y = this.m_localAnchor1.y - this.m_localCenterA.y; | |
tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); | |
r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); | |
r1X = tX; | |
tMat = bB.m_xf.R; | |
var r2X = this.m_localAnchor2.x - this.m_localCenterB.x; | |
var r2Y = this.m_localAnchor2.y - this.m_localCenterB.y; | |
tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); | |
r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); | |
r2X = tX; | |
var dX = bB.m_sweep.c.x + r2X - bA.m_sweep.c.x - r1X; | |
var dY = bB.m_sweep.c.y + r2Y - bA.m_sweep.c.y - r1Y; | |
this.m_invMassA = bA.m_invMass; | |
this.m_invMassB = bB.m_invMass; | |
this.m_invIA = bA.m_invI; | |
this.m_invIB = bB.m_invI; { | |
this.m_axis.SetV(b2Math.MulMV(xf1.R, this.m_localXAxis1)); | |
this.m_a1 = (dX + r1X) * this.m_axis.y - (dY + r1Y) * this.m_axis.x; | |
this.m_a2 = r2X * this.m_axis.y - r2Y * this.m_axis.x; | |
this.m_motorMass = this.m_invMassA + this.m_invMassB + this.m_invIA * this.m_a1 * this.m_a1 + this.m_invIB * this.m_a2 * this.m_a2; | |
if (this.m_motorMass > Number.MIN_VALUE) this.m_motorMass = 1.0 / this.m_motorMass; | |
} { | |
this.m_perp.SetV(b2Math.MulMV(xf1.R, this.m_localYAxis1)); | |
this.m_s1 = (dX + r1X) * this.m_perp.y - (dY + r1Y) * this.m_perp.x; | |
this.m_s2 = r2X * this.m_perp.y - r2Y * this.m_perp.x; | |
var m1 = this.m_invMassA; | |
var m2 = this.m_invMassB; | |
var i1 = this.m_invIA; | |
var i2 = this.m_invIB; | |
this.m_K.col1.x = m1 + m2 + i1 * this.m_s1 * this.m_s1 + i2 * this.m_s2 * this.m_s2; | |
this.m_K.col1.y = i1 * this.m_s1 + i2 * this.m_s2; | |
this.m_K.col1.z = i1 * this.m_s1 * this.m_a1 + i2 * this.m_s2 * this.m_a2; | |
this.m_K.col2.x = this.m_K.col1.y; | |
this.m_K.col2.y = i1 + i2; | |
this.m_K.col2.z = i1 * this.m_a1 + i2 * this.m_a2; | |
this.m_K.col3.x = this.m_K.col1.z; | |
this.m_K.col3.y = this.m_K.col2.z; | |
this.m_K.col3.z = m1 + m2 + i1 * this.m_a1 * this.m_a1 + i2 * this.m_a2 * this.m_a2; | |
} | |
if (this.m_enableLimit) { | |
var jointTransition = this.m_axis.x * dX + this.m_axis.y * dY; | |
if (b2Math.Abs(this.m_upperTranslation - this.m_lowerTranslation) < 2.0 * b2Settings.b2_linearSlop) { | |
this.m_limitState = b2Joint.e_equalLimits; | |
} | |
else if (jointTransition <= this.m_lowerTranslation) { | |
if (this.m_limitState != b2Joint.e_atLowerLimit) { | |
this.m_limitState = b2Joint.e_atLowerLimit; | |
this.m_impulse.z = 0.0; | |
} | |
} | |
else if (jointTransition >= this.m_upperTranslation) { | |
if (this.m_limitState != b2Joint.e_atUpperLimit) { | |
this.m_limitState = b2Joint.e_atUpperLimit; | |
this.m_impulse.z = 0.0; | |
} | |
} | |
else { | |
this.m_limitState = b2Joint.e_inactiveLimit; | |
this.m_impulse.z = 0.0; | |
} | |
} | |
else { | |
this.m_limitState = b2Joint.e_inactiveLimit; | |
} | |
if (this.m_enableMotor == false) { | |
this.m_motorImpulse = 0.0; | |
} | |
if (step.warmStarting) { | |
this.m_impulse.x *= step.dtRatio; | |
this.m_impulse.y *= step.dtRatio; | |
this.m_motorImpulse *= step.dtRatio; | |
var PX = this.m_impulse.x * this.m_perp.x + (this.m_motorImpulse + this.m_impulse.z) * this.m_axis.x; | |
var PY = this.m_impulse.x * this.m_perp.y + (this.m_motorImpulse + this.m_impulse.z) * this.m_axis.y; | |
var L1 = this.m_impulse.x * this.m_s1 + this.m_impulse.y + (this.m_motorImpulse + this.m_impulse.z) * this.m_a1; | |
var L2 = this.m_impulse.x * this.m_s2 + this.m_impulse.y + (this.m_motorImpulse + this.m_impulse.z) * this.m_a2; | |
bA.m_linearVelocity.x -= this.m_invMassA * PX; | |
bA.m_linearVelocity.y -= this.m_invMassA * PY; | |
bA.m_angularVelocity -= this.m_invIA * L1; | |
bB.m_linearVelocity.x += this.m_invMassB * PX; | |
bB.m_linearVelocity.y += this.m_invMassB * PY; | |
bB.m_angularVelocity += this.m_invIB * L2; | |
} | |
else { | |
this.m_impulse.SetZero(); | |
this.m_motorImpulse = 0.0; | |
} | |
} | |
b2PrismaticJoint.prototype.SolveVelocityConstraints = function (step) { | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var v1 = bA.m_linearVelocity; | |
var w1 = bA.m_angularVelocity; | |
var v2 = bB.m_linearVelocity; | |
var w2 = bB.m_angularVelocity; | |
var PX = 0; | |
var PY = 0; | |
var L1 = 0; | |
var L2 = 0; | |
if (this.m_enableMotor && this.m_limitState != b2Joint.e_equalLimits) { | |
var Cdot = this.m_axis.x * (v2.x - v1.x) + this.m_axis.y * (v2.y - v1.y) + this.m_a2 * w2 - this.m_a1 * w1; | |
var impulse = this.m_motorMass * (this.m_motorSpeed - Cdot); | |
var oldImpulse = this.m_motorImpulse; | |
var maxImpulse = step.dt * this.m_maxMotorForce; | |
this.m_motorImpulse = b2Math.Clamp(this.m_motorImpulse + impulse, (-maxImpulse), maxImpulse); | |
impulse = this.m_motorImpulse - oldImpulse; | |
PX = impulse * this.m_axis.x; | |
PY = impulse * this.m_axis.y; | |
L1 = impulse * this.m_a1; | |
L2 = impulse * this.m_a2; | |
v1.x -= this.m_invMassA * PX; | |
v1.y -= this.m_invMassA * PY; | |
w1 -= this.m_invIA * L1; | |
v2.x += this.m_invMassB * PX; | |
v2.y += this.m_invMassB * PY; | |
w2 += this.m_invIB * L2; | |
} | |
var Cdot1X = this.m_perp.x * (v2.x - v1.x) + this.m_perp.y * (v2.y - v1.y) + this.m_s2 * w2 - this.m_s1 * w1; | |
var Cdot1Y = w2 - w1; | |
if (this.m_enableLimit && this.m_limitState != b2Joint.e_inactiveLimit) { | |
var Cdot2 = this.m_axis.x * (v2.x - v1.x) + this.m_axis.y * (v2.y - v1.y) + this.m_a2 * w2 - this.m_a1 * w1; | |
var f1 = this.m_impulse.Copy(); | |
var df = this.m_K.Solve33(new b2Vec3(), (-Cdot1X), (-Cdot1Y), (-Cdot2)); | |
this.m_impulse.Add(df); | |
if (this.m_limitState == b2Joint.e_atLowerLimit) { | |
this.m_impulse.z = b2Math.Max(this.m_impulse.z, 0.0); | |
} | |
else if (this.m_limitState == b2Joint.e_atUpperLimit) { | |
this.m_impulse.z = b2Math.Min(this.m_impulse.z, 0.0); | |
} | |
var bX = (-Cdot1X) - (this.m_impulse.z - f1.z) * this.m_K.col3.x; | |
var bY = (-Cdot1Y) - (this.m_impulse.z - f1.z) * this.m_K.col3.y; | |
var f2r = this.m_K.Solve22(new b2Vec2(), bX, bY); | |
f2r.x += f1.x; | |
f2r.y += f1.y; | |
this.m_impulse.x = f2r.x; | |
this.m_impulse.y = f2r.y; | |
df.x = this.m_impulse.x - f1.x; | |
df.y = this.m_impulse.y - f1.y; | |
df.z = this.m_impulse.z - f1.z; | |
PX = df.x * this.m_perp.x + df.z * this.m_axis.x; | |
PY = df.x * this.m_perp.y + df.z * this.m_axis.y; | |
L1 = df.x * this.m_s1 + df.y + df.z * this.m_a1; | |
L2 = df.x * this.m_s2 + df.y + df.z * this.m_a2; | |
v1.x -= this.m_invMassA * PX; | |
v1.y -= this.m_invMassA * PY; | |
w1 -= this.m_invIA * L1; | |
v2.x += this.m_invMassB * PX; | |
v2.y += this.m_invMassB * PY; | |
w2 += this.m_invIB * L2; | |
} | |
else { | |
var df2 = this.m_K.Solve22(new b2Vec2(), (-Cdot1X), (-Cdot1Y)); | |
this.m_impulse.x += df2.x; | |
this.m_impulse.y += df2.y; | |
PX = df2.x * this.m_perp.x; | |
PY = df2.x * this.m_perp.y; | |
L1 = df2.x * this.m_s1 + df2.y; | |
L2 = df2.x * this.m_s2 + df2.y; | |
v1.x -= this.m_invMassA * PX; | |
v1.y -= this.m_invMassA * PY; | |
w1 -= this.m_invIA * L1; | |
v2.x += this.m_invMassB * PX; | |
v2.y += this.m_invMassB * PY; | |
w2 += this.m_invIB * L2; | |
} | |
bA.m_linearVelocity.SetV(v1); | |
bA.m_angularVelocity = w1; | |
bB.m_linearVelocity.SetV(v2); | |
bB.m_angularVelocity = w2; | |
} | |
b2PrismaticJoint.prototype.SolvePositionConstraints = function (baumgarte) { | |
if (baumgarte === undefined) baumgarte = 0; | |
var limitC = 0; | |
var oldLimitImpulse = 0; | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var c1 = bA.m_sweep.c; | |
var a1 = bA.m_sweep.a; | |
var c2 = bB.m_sweep.c; | |
var a2 = bB.m_sweep.a; | |
var tMat; | |
var tX = 0; | |
var m1 = 0; | |
var m2 = 0; | |
var i1 = 0; | |
var i2 = 0; | |
var linearError = 0.0; | |
var angularError = 0.0; | |
var active = false; | |
var C2 = 0.0; | |
var R1 = b2Mat22.FromAngle(a1); | |
var R2 = b2Mat22.FromAngle(a2); | |
tMat = R1; | |
var r1X = this.m_localAnchor1.x - this.m_localCenterA.x; | |
var r1Y = this.m_localAnchor1.y - this.m_localCenterA.y; | |
tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); | |
r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); | |
r1X = tX; | |
tMat = R2; | |
var r2X = this.m_localAnchor2.x - this.m_localCenterB.x; | |
var r2Y = this.m_localAnchor2.y - this.m_localCenterB.y; | |
tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); | |
r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); | |
r2X = tX; | |
var dX = c2.x + r2X - c1.x - r1X; | |
var dY = c2.y + r2Y - c1.y - r1Y; | |
if (this.m_enableLimit) { | |
this.m_axis = b2Math.MulMV(R1, this.m_localXAxis1); | |
this.m_a1 = (dX + r1X) * this.m_axis.y - (dY + r1Y) * this.m_axis.x; | |
this.m_a2 = r2X * this.m_axis.y - r2Y * this.m_axis.x; | |
var translation = this.m_axis.x * dX + this.m_axis.y * dY; | |
if (b2Math.Abs(this.m_upperTranslation - this.m_lowerTranslation) < 2.0 * b2Settings.b2_linearSlop) { | |
C2 = b2Math.Clamp(translation, (-b2Settings.b2_maxLinearCorrection), b2Settings.b2_maxLinearCorrection); | |
linearError = b2Math.Abs(translation); | |
active = true; | |
} | |
else if (translation <= this.m_lowerTranslation) { | |
C2 = b2Math.Clamp(translation - this.m_lowerTranslation + b2Settings.b2_linearSlop, (-b2Settings.b2_maxLinearCorrection), 0.0); | |
linearError = this.m_lowerTranslation - translation; | |
active = true; | |
} | |
else if (translation >= this.m_upperTranslation) { | |
C2 = b2Math.Clamp(translation - this.m_upperTranslation + b2Settings.b2_linearSlop, 0.0, b2Settings.b2_maxLinearCorrection); | |
linearError = translation - this.m_upperTranslation; | |
active = true; | |
} | |
} | |
this.m_perp = b2Math.MulMV(R1, this.m_localYAxis1); | |
this.m_s1 = (dX + r1X) * this.m_perp.y - (dY + r1Y) * this.m_perp.x; | |
this.m_s2 = r2X * this.m_perp.y - r2Y * this.m_perp.x; | |
var impulse = new b2Vec3(); | |
var C1X = this.m_perp.x * dX + this.m_perp.y * dY; | |
var C1Y = a2 - a1 - this.m_refAngle; | |
linearError = b2Math.Max(linearError, b2Math.Abs(C1X)); | |
angularError = b2Math.Abs(C1Y); | |
if (active) { | |
m1 = this.m_invMassA; | |
m2 = this.m_invMassB; | |
i1 = this.m_invIA; | |
i2 = this.m_invIB; | |
this.m_K.col1.x = m1 + m2 + i1 * this.m_s1 * this.m_s1 + i2 * this.m_s2 * this.m_s2; | |
this.m_K.col1.y = i1 * this.m_s1 + i2 * this.m_s2; | |
this.m_K.col1.z = i1 * this.m_s1 * this.m_a1 + i2 * this.m_s2 * this.m_a2; | |
this.m_K.col2.x = this.m_K.col1.y; | |
this.m_K.col2.y = i1 + i2; | |
this.m_K.col2.z = i1 * this.m_a1 + i2 * this.m_a2; | |
this.m_K.col3.x = this.m_K.col1.z; | |
this.m_K.col3.y = this.m_K.col2.z; | |
this.m_K.col3.z = m1 + m2 + i1 * this.m_a1 * this.m_a1 + i2 * this.m_a2 * this.m_a2; | |
this.m_K.Solve33(impulse, (-C1X), (-C1Y), (-C2)); | |
} | |
else { | |
m1 = this.m_invMassA; | |
m2 = this.m_invMassB; | |
i1 = this.m_invIA; | |
i2 = this.m_invIB; | |
var k11 = m1 + m2 + i1 * this.m_s1 * this.m_s1 + i2 * this.m_s2 * this.m_s2; | |
var k12 = i1 * this.m_s1 + i2 * this.m_s2; | |
var k22 = i1 + i2; | |
this.m_K.col1.Set(k11, k12, 0.0); | |
this.m_K.col2.Set(k12, k22, 0.0); | |
var impulse1 = this.m_K.Solve22(new b2Vec2(), (-C1X), (-C1Y)); | |
impulse.x = impulse1.x; | |
impulse.y = impulse1.y; | |
impulse.z = 0.0; | |
} | |
var PX = impulse.x * this.m_perp.x + impulse.z * this.m_axis.x; | |
var PY = impulse.x * this.m_perp.y + impulse.z * this.m_axis.y; | |
var L1 = impulse.x * this.m_s1 + impulse.y + impulse.z * this.m_a1; | |
var L2 = impulse.x * this.m_s2 + impulse.y + impulse.z * this.m_a2; | |
c1.x -= this.m_invMassA * PX; | |
c1.y -= this.m_invMassA * PY; | |
a1 -= this.m_invIA * L1; | |
c2.x += this.m_invMassB * PX; | |
c2.y += this.m_invMassB * PY; | |
a2 += this.m_invIB * L2; | |
bA.m_sweep.a = a1; | |
bB.m_sweep.a = a2; | |
bA.SynchronizeTransform(); | |
bB.SynchronizeTransform(); | |
return linearError <= b2Settings.b2_linearSlop && angularError <= b2Settings.b2_angularSlop; | |
} | |
Box2D.inherit(b2PrismaticJointDef, Box2D.Dynamics.Joints.b2JointDef); | |
b2PrismaticJointDef.prototype.__super = Box2D.Dynamics.Joints.b2JointDef.prototype; | |
b2PrismaticJointDef.b2PrismaticJointDef = function () { | |
Box2D.Dynamics.Joints.b2JointDef.b2JointDef.apply(this, arguments); | |
this.localAnchorA = new b2Vec2(); | |
this.localAnchorB = new b2Vec2(); | |
this.localAxisA = new b2Vec2(); | |
}; | |
b2PrismaticJointDef.prototype.b2PrismaticJointDef = function () { | |
this.__super.b2JointDef.call(this); | |
this.type = b2Joint.e_prismaticJoint; | |
this.localAxisA.Set(1.0, 0.0); | |
this.referenceAngle = 0.0; | |
this.enableLimit = false; | |
this.lowerTranslation = 0.0; | |
this.upperTranslation = 0.0; | |
this.enableMotor = false; | |
this.maxMotorForce = 0.0; | |
this.motorSpeed = 0.0; | |
} | |
b2PrismaticJointDef.prototype.Initialize = function (bA, bB, anchor, axis) { | |
this.bodyA = bA; | |
this.bodyB = bB; | |
this.localAnchorA = this.bodyA.GetLocalPoint(anchor); | |
this.localAnchorB = this.bodyB.GetLocalPoint(anchor); | |
this.localAxisA = this.bodyA.GetLocalVector(axis); | |
this.referenceAngle = this.bodyB.GetAngle() - this.bodyA.GetAngle(); | |
} | |
Box2D.inherit(b2PulleyJoint, Box2D.Dynamics.Joints.b2Joint); | |
b2PulleyJoint.prototype.__super = Box2D.Dynamics.Joints.b2Joint.prototype; | |
b2PulleyJoint.b2PulleyJoint = function () { | |
Box2D.Dynamics.Joints.b2Joint.b2Joint.apply(this, arguments); | |
this.m_groundAnchor1 = new b2Vec2(); | |
this.m_groundAnchor2 = new b2Vec2(); | |
this.m_localAnchor1 = new b2Vec2(); | |
this.m_localAnchor2 = new b2Vec2(); | |
this.m_u1 = new b2Vec2(); | |
this.m_u2 = new b2Vec2(); | |
}; | |
b2PulleyJoint.prototype.GetAnchorA = function () { | |
return this.m_bodyA.GetWorldPoint(this.m_localAnchor1); | |
} | |
b2PulleyJoint.prototype.GetAnchorB = function () { | |
return this.m_bodyB.GetWorldPoint(this.m_localAnchor2); | |
} | |
b2PulleyJoint.prototype.GetReactionForce = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
return new b2Vec2(inv_dt * this.m_impulse * this.m_u2.x, inv_dt * this.m_impulse * this.m_u2.y); | |
} | |
b2PulleyJoint.prototype.GetReactionTorque = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
return 0.0; | |
} | |
b2PulleyJoint.prototype.GetGroundAnchorA = function () { | |
var a = this.m_ground.m_xf.position.Copy(); | |
a.Add(this.m_groundAnchor1); | |
return a; | |
} | |
b2PulleyJoint.prototype.GetGroundAnchorB = function () { | |
var a = this.m_ground.m_xf.position.Copy(); | |
a.Add(this.m_groundAnchor2); | |
return a; | |
} | |
b2PulleyJoint.prototype.GetLength1 = function () { | |
var p = this.m_bodyA.GetWorldPoint(this.m_localAnchor1); | |
var sX = this.m_ground.m_xf.position.x + this.m_groundAnchor1.x; | |
var sY = this.m_ground.m_xf.position.y + this.m_groundAnchor1.y; | |
var dX = p.x - sX; | |
var dY = p.y - sY; | |
return Math.sqrt(dX * dX + dY * dY); | |
} | |
b2PulleyJoint.prototype.GetLength2 = function () { | |
var p = this.m_bodyB.GetWorldPoint(this.m_localAnchor2); | |
var sX = this.m_ground.m_xf.position.x + this.m_groundAnchor2.x; | |
var sY = this.m_ground.m_xf.position.y + this.m_groundAnchor2.y; | |
var dX = p.x - sX; | |
var dY = p.y - sY; | |
return Math.sqrt(dX * dX + dY * dY); | |
} | |
b2PulleyJoint.prototype.GetRatio = function () { | |
return this.m_ratio; | |
} | |
b2PulleyJoint.prototype.b2PulleyJoint = function (def) { | |
this.__super.b2Joint.call(this, def); | |
var tMat; | |
var tX = 0; | |
var tY = 0; | |
this.m_ground = this.m_bodyA.m_world.m_groundBody; | |
this.m_groundAnchor1.x = def.groundAnchorA.x - this.m_ground.m_xf.position.x; | |
this.m_groundAnchor1.y = def.groundAnchorA.y - this.m_ground.m_xf.position.y; | |
this.m_groundAnchor2.x = def.groundAnchorB.x - this.m_ground.m_xf.position.x; | |
this.m_groundAnchor2.y = def.groundAnchorB.y - this.m_ground.m_xf.position.y; | |
this.m_localAnchor1.SetV(def.localAnchorA); | |
this.m_localAnchor2.SetV(def.localAnchorB); | |
this.m_ratio = def.ratio; | |
this.m_constant = def.lengthA + this.m_ratio * def.lengthB; | |
this.m_maxLength1 = b2Math.Min(def.maxLengthA, this.m_constant - this.m_ratio * b2PulleyJoint.b2_minPulleyLength); | |
this.m_maxLength2 = b2Math.Min(def.maxLengthB, (this.m_constant - b2PulleyJoint.b2_minPulleyLength) / this.m_ratio); | |
this.m_impulse = 0.0; | |
this.m_limitImpulse1 = 0.0; | |
this.m_limitImpulse2 = 0.0; | |
} | |
b2PulleyJoint.prototype.InitVelocityConstraints = function (step) { | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var tMat; | |
tMat = bA.m_xf.R; | |
var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; | |
var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; | |
var tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); | |
r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); | |
r1X = tX; | |
tMat = bB.m_xf.R; | |
var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; | |
var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); | |
r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); | |
r2X = tX; | |
var p1X = bA.m_sweep.c.x + r1X; | |
var p1Y = bA.m_sweep.c.y + r1Y; | |
var p2X = bB.m_sweep.c.x + r2X; | |
var p2Y = bB.m_sweep.c.y + r2Y; | |
var s1X = this.m_ground.m_xf.position.x + this.m_groundAnchor1.x; | |
var s1Y = this.m_ground.m_xf.position.y + this.m_groundAnchor1.y; | |
var s2X = this.m_ground.m_xf.position.x + this.m_groundAnchor2.x; | |
var s2Y = this.m_ground.m_xf.position.y + this.m_groundAnchor2.y; | |
this.m_u1.Set(p1X - s1X, p1Y - s1Y); | |
this.m_u2.Set(p2X - s2X, p2Y - s2Y); | |
var length1 = this.m_u1.Length(); | |
var length2 = this.m_u2.Length(); | |
if (length1 > b2Settings.b2_linearSlop) { | |
this.m_u1.Multiply(1.0 / length1); | |
} | |
else { | |
this.m_u1.SetZero(); | |
} | |
if (length2 > b2Settings.b2_linearSlop) { | |
this.m_u2.Multiply(1.0 / length2); | |
} | |
else { | |
this.m_u2.SetZero(); | |
} | |
var C = this.m_constant - length1 - this.m_ratio * length2; | |
if (C > 0.0) { | |
this.m_state = b2Joint.e_inactiveLimit; | |
this.m_impulse = 0.0; | |
} | |
else { | |
this.m_state = b2Joint.e_atUpperLimit; | |
} | |
if (length1 < this.m_maxLength1) { | |
this.m_limitState1 = b2Joint.e_inactiveLimit; | |
this.m_limitImpulse1 = 0.0; | |
} | |
else { | |
this.m_limitState1 = b2Joint.e_atUpperLimit; | |
} | |
if (length2 < this.m_maxLength2) { | |
this.m_limitState2 = b2Joint.e_inactiveLimit; | |
this.m_limitImpulse2 = 0.0; | |
} | |
else { | |
this.m_limitState2 = b2Joint.e_atUpperLimit; | |
} | |
var cr1u1 = r1X * this.m_u1.y - r1Y * this.m_u1.x; | |
var cr2u2 = r2X * this.m_u2.y - r2Y * this.m_u2.x; | |
this.m_limitMass1 = bA.m_invMass + bA.m_invI * cr1u1 * cr1u1; | |
this.m_limitMass2 = bB.m_invMass + bB.m_invI * cr2u2 * cr2u2; | |
this.m_pulleyMass = this.m_limitMass1 + this.m_ratio * this.m_ratio * this.m_limitMass2; | |
this.m_limitMass1 = 1.0 / this.m_limitMass1; | |
this.m_limitMass2 = 1.0 / this.m_limitMass2; | |
this.m_pulleyMass = 1.0 / this.m_pulleyMass; | |
if (step.warmStarting) { | |
this.m_impulse *= step.dtRatio; | |
this.m_limitImpulse1 *= step.dtRatio; | |
this.m_limitImpulse2 *= step.dtRatio; | |
var P1X = ((-this.m_impulse) - this.m_limitImpulse1) * this.m_u1.x; | |
var P1Y = ((-this.m_impulse) - this.m_limitImpulse1) * this.m_u1.y; | |
var P2X = ((-this.m_ratio * this.m_impulse) - this.m_limitImpulse2) * this.m_u2.x; | |
var P2Y = ((-this.m_ratio * this.m_impulse) - this.m_limitImpulse2) * this.m_u2.y; | |
bA.m_linearVelocity.x += bA.m_invMass * P1X; | |
bA.m_linearVelocity.y += bA.m_invMass * P1Y; | |
bA.m_angularVelocity += bA.m_invI * (r1X * P1Y - r1Y * P1X); | |
bB.m_linearVelocity.x += bB.m_invMass * P2X; | |
bB.m_linearVelocity.y += bB.m_invMass * P2Y; | |
bB.m_angularVelocity += bB.m_invI * (r2X * P2Y - r2Y * P2X); | |
} | |
else { | |
this.m_impulse = 0.0; | |
this.m_limitImpulse1 = 0.0; | |
this.m_limitImpulse2 = 0.0; | |
} | |
} | |
b2PulleyJoint.prototype.SolveVelocityConstraints = function (step) { | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var tMat; | |
tMat = bA.m_xf.R; | |
var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; | |
var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; | |
var tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); | |
r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); | |
r1X = tX; | |
tMat = bB.m_xf.R; | |
var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; | |
var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); | |
r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); | |
r2X = tX; | |
var v1X = 0; | |
var v1Y = 0; | |
var v2X = 0; | |
var v2Y = 0; | |
var P1X = 0; | |
var P1Y = 0; | |
var P2X = 0; | |
var P2Y = 0; | |
var Cdot = 0; | |
var impulse = 0; | |
var oldImpulse = 0; | |
if (this.m_state == b2Joint.e_atUpperLimit) { | |
v1X = bA.m_linearVelocity.x + ((-bA.m_angularVelocity * r1Y)); | |
v1Y = bA.m_linearVelocity.y + (bA.m_angularVelocity * r1X); | |
v2X = bB.m_linearVelocity.x + ((-bB.m_angularVelocity * r2Y)); | |
v2Y = bB.m_linearVelocity.y + (bB.m_angularVelocity * r2X); | |
Cdot = (-(this.m_u1.x * v1X + this.m_u1.y * v1Y)) - this.m_ratio * (this.m_u2.x * v2X + this.m_u2.y * v2Y); | |
impulse = this.m_pulleyMass * ((-Cdot)); | |
oldImpulse = this.m_impulse; | |
this.m_impulse = b2Math.Max(0.0, this.m_impulse + impulse); | |
impulse = this.m_impulse - oldImpulse; | |
P1X = (-impulse * this.m_u1.x); | |
P1Y = (-impulse * this.m_u1.y); | |
P2X = (-this.m_ratio * impulse * this.m_u2.x); | |
P2Y = (-this.m_ratio * impulse * this.m_u2.y); | |
bA.m_linearVelocity.x += bA.m_invMass * P1X; | |
bA.m_linearVelocity.y += bA.m_invMass * P1Y; | |
bA.m_angularVelocity += bA.m_invI * (r1X * P1Y - r1Y * P1X); | |
bB.m_linearVelocity.x += bB.m_invMass * P2X; | |
bB.m_linearVelocity.y += bB.m_invMass * P2Y; | |
bB.m_angularVelocity += bB.m_invI * (r2X * P2Y - r2Y * P2X); | |
} | |
if (this.m_limitState1 == b2Joint.e_atUpperLimit) { | |
v1X = bA.m_linearVelocity.x + ((-bA.m_angularVelocity * r1Y)); | |
v1Y = bA.m_linearVelocity.y + (bA.m_angularVelocity * r1X); | |
Cdot = (-(this.m_u1.x * v1X + this.m_u1.y * v1Y)); | |
impulse = (-this.m_limitMass1 * Cdot); | |
oldImpulse = this.m_limitImpulse1; | |
this.m_limitImpulse1 = b2Math.Max(0.0, this.m_limitImpulse1 + impulse); | |
impulse = this.m_limitImpulse1 - oldImpulse; | |
P1X = (-impulse * this.m_u1.x); | |
P1Y = (-impulse * this.m_u1.y); | |
bA.m_linearVelocity.x += bA.m_invMass * P1X; | |
bA.m_linearVelocity.y += bA.m_invMass * P1Y; | |
bA.m_angularVelocity += bA.m_invI * (r1X * P1Y - r1Y * P1X); | |
} | |
if (this.m_limitState2 == b2Joint.e_atUpperLimit) { | |
v2X = bB.m_linearVelocity.x + ((-bB.m_angularVelocity * r2Y)); | |
v2Y = bB.m_linearVelocity.y + (bB.m_angularVelocity * r2X); | |
Cdot = (-(this.m_u2.x * v2X + this.m_u2.y * v2Y)); | |
impulse = (-this.m_limitMass2 * Cdot); | |
oldImpulse = this.m_limitImpulse2; | |
this.m_limitImpulse2 = b2Math.Max(0.0, this.m_limitImpulse2 + impulse); | |
impulse = this.m_limitImpulse2 - oldImpulse; | |
P2X = (-impulse * this.m_u2.x); | |
P2Y = (-impulse * this.m_u2.y); | |
bB.m_linearVelocity.x += bB.m_invMass * P2X; | |
bB.m_linearVelocity.y += bB.m_invMass * P2Y; | |
bB.m_angularVelocity += bB.m_invI * (r2X * P2Y - r2Y * P2X); | |
} | |
} | |
b2PulleyJoint.prototype.SolvePositionConstraints = function (baumgarte) { | |
if (baumgarte === undefined) baumgarte = 0; | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var tMat; | |
var s1X = this.m_ground.m_xf.position.x + this.m_groundAnchor1.x; | |
var s1Y = this.m_ground.m_xf.position.y + this.m_groundAnchor1.y; | |
var s2X = this.m_ground.m_xf.position.x + this.m_groundAnchor2.x; | |
var s2Y = this.m_ground.m_xf.position.y + this.m_groundAnchor2.y; | |
var r1X = 0; | |
var r1Y = 0; | |
var r2X = 0; | |
var r2Y = 0; | |
var p1X = 0; | |
var p1Y = 0; | |
var p2X = 0; | |
var p2Y = 0; | |
var length1 = 0; | |
var length2 = 0; | |
var C = 0; | |
var impulse = 0; | |
var oldImpulse = 0; | |
var oldLimitPositionImpulse = 0; | |
var tX = 0; | |
var linearError = 0.0; | |
if (this.m_state == b2Joint.e_atUpperLimit) { | |
tMat = bA.m_xf.R; | |
r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; | |
r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); | |
r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); | |
r1X = tX; | |
tMat = bB.m_xf.R; | |
r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; | |
r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); | |
r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); | |
r2X = tX; | |
p1X = bA.m_sweep.c.x + r1X; | |
p1Y = bA.m_sweep.c.y + r1Y; | |
p2X = bB.m_sweep.c.x + r2X; | |
p2Y = bB.m_sweep.c.y + r2Y; | |
this.m_u1.Set(p1X - s1X, p1Y - s1Y); | |
this.m_u2.Set(p2X - s2X, p2Y - s2Y); | |
length1 = this.m_u1.Length(); | |
length2 = this.m_u2.Length(); | |
if (length1 > b2Settings.b2_linearSlop) { | |
this.m_u1.Multiply(1.0 / length1); | |
} | |
else { | |
this.m_u1.SetZero(); | |
} | |
if (length2 > b2Settings.b2_linearSlop) { | |
this.m_u2.Multiply(1.0 / length2); | |
} | |
else { | |
this.m_u2.SetZero(); | |
} | |
C = this.m_constant - length1 - this.m_ratio * length2; | |
linearError = b2Math.Max(linearError, (-C)); | |
C = b2Math.Clamp(C + b2Settings.b2_linearSlop, (-b2Settings.b2_maxLinearCorrection), 0.0); | |
impulse = (-this.m_pulleyMass * C); | |
p1X = (-impulse * this.m_u1.x); | |
p1Y = (-impulse * this.m_u1.y); | |
p2X = (-this.m_ratio * impulse * this.m_u2.x); | |
p2Y = (-this.m_ratio * impulse * this.m_u2.y); | |
bA.m_sweep.c.x += bA.m_invMass * p1X; | |
bA.m_sweep.c.y += bA.m_invMass * p1Y; | |
bA.m_sweep.a += bA.m_invI * (r1X * p1Y - r1Y * p1X); | |
bB.m_sweep.c.x += bB.m_invMass * p2X; | |
bB.m_sweep.c.y += bB.m_invMass * p2Y; | |
bB.m_sweep.a += bB.m_invI * (r2X * p2Y - r2Y * p2X); | |
bA.SynchronizeTransform(); | |
bB.SynchronizeTransform(); | |
} | |
if (this.m_limitState1 == b2Joint.e_atUpperLimit) { | |
tMat = bA.m_xf.R; | |
r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; | |
r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); | |
r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); | |
r1X = tX; | |
p1X = bA.m_sweep.c.x + r1X; | |
p1Y = bA.m_sweep.c.y + r1Y; | |
this.m_u1.Set(p1X - s1X, p1Y - s1Y); | |
length1 = this.m_u1.Length(); | |
if (length1 > b2Settings.b2_linearSlop) { | |
this.m_u1.x *= 1.0 / length1; | |
this.m_u1.y *= 1.0 / length1; | |
} | |
else { | |
this.m_u1.SetZero(); | |
} | |
C = this.m_maxLength1 - length1; | |
linearError = b2Math.Max(linearError, (-C)); | |
C = b2Math.Clamp(C + b2Settings.b2_linearSlop, (-b2Settings.b2_maxLinearCorrection), 0.0); | |
impulse = (-this.m_limitMass1 * C); | |
p1X = (-impulse * this.m_u1.x); | |
p1Y = (-impulse * this.m_u1.y); | |
bA.m_sweep.c.x += bA.m_invMass * p1X; | |
bA.m_sweep.c.y += bA.m_invMass * p1Y; | |
bA.m_sweep.a += bA.m_invI * (r1X * p1Y - r1Y * p1X); | |
bA.SynchronizeTransform(); | |
} | |
if (this.m_limitState2 == b2Joint.e_atUpperLimit) { | |
tMat = bB.m_xf.R; | |
r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; | |
r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); | |
r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); | |
r2X = tX; | |
p2X = bB.m_sweep.c.x + r2X; | |
p2Y = bB.m_sweep.c.y + r2Y; | |
this.m_u2.Set(p2X - s2X, p2Y - s2Y); | |
length2 = this.m_u2.Length(); | |
if (length2 > b2Settings.b2_linearSlop) { | |
this.m_u2.x *= 1.0 / length2; | |
this.m_u2.y *= 1.0 / length2; | |
} | |
else { | |
this.m_u2.SetZero(); | |
} | |
C = this.m_maxLength2 - length2; | |
linearError = b2Math.Max(linearError, (-C)); | |
C = b2Math.Clamp(C + b2Settings.b2_linearSlop, (-b2Settings.b2_maxLinearCorrection), 0.0); | |
impulse = (-this.m_limitMass2 * C); | |
p2X = (-impulse * this.m_u2.x); | |
p2Y = (-impulse * this.m_u2.y); | |
bB.m_sweep.c.x += bB.m_invMass * p2X; | |
bB.m_sweep.c.y += bB.m_invMass * p2Y; | |
bB.m_sweep.a += bB.m_invI * (r2X * p2Y - r2Y * p2X); | |
bB.SynchronizeTransform(); | |
} | |
return linearError < b2Settings.b2_linearSlop; | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Dynamics.Joints.b2PulleyJoint.b2_minPulleyLength = 2.0; | |
}); | |
Box2D.inherit(b2PulleyJointDef, Box2D.Dynamics.Joints.b2JointDef); | |
b2PulleyJointDef.prototype.__super = Box2D.Dynamics.Joints.b2JointDef.prototype; | |
b2PulleyJointDef.b2PulleyJointDef = function () { | |
Box2D.Dynamics.Joints.b2JointDef.b2JointDef.apply(this, arguments); | |
this.groundAnchorA = new b2Vec2(); | |
this.groundAnchorB = new b2Vec2(); | |
this.localAnchorA = new b2Vec2(); | |
this.localAnchorB = new b2Vec2(); | |
}; | |
b2PulleyJointDef.prototype.b2PulleyJointDef = function () { | |
this.__super.b2JointDef.call(this); | |
this.type = b2Joint.e_pulleyJoint; | |
this.groundAnchorA.Set((-1.0), 1.0); | |
this.groundAnchorB.Set(1.0, 1.0); | |
this.localAnchorA.Set((-1.0), 0.0); | |
this.localAnchorB.Set(1.0, 0.0); | |
this.lengthA = 0.0; | |
this.maxLengthA = 0.0; | |
this.lengthB = 0.0; | |
this.maxLengthB = 0.0; | |
this.ratio = 1.0; | |
this.collideConnected = true; | |
} | |
b2PulleyJointDef.prototype.Initialize = function (bA, bB, gaA, gaB, anchorA, anchorB, r) { | |
if (r === undefined) r = 0; | |
this.bodyA = bA; | |
this.bodyB = bB; | |
this.groundAnchorA.SetV(gaA); | |
this.groundAnchorB.SetV(gaB); | |
this.localAnchorA = this.bodyA.GetLocalPoint(anchorA); | |
this.localAnchorB = this.bodyB.GetLocalPoint(anchorB); | |
var d1X = anchorA.x - gaA.x; | |
var d1Y = anchorA.y - gaA.y; | |
this.lengthA = Math.sqrt(d1X * d1X + d1Y * d1Y); | |
var d2X = anchorB.x - gaB.x; | |
var d2Y = anchorB.y - gaB.y; | |
this.lengthB = Math.sqrt(d2X * d2X + d2Y * d2Y); | |
this.ratio = r; | |
var C = this.lengthA + this.ratio * this.lengthB; | |
this.maxLengthA = C - this.ratio * b2PulleyJoint.b2_minPulleyLength; | |
this.maxLengthB = (C - b2PulleyJoint.b2_minPulleyLength) / this.ratio; | |
} | |
Box2D.inherit(b2RevoluteJoint, Box2D.Dynamics.Joints.b2Joint); | |
b2RevoluteJoint.prototype.__super = Box2D.Dynamics.Joints.b2Joint.prototype; | |
b2RevoluteJoint.b2RevoluteJoint = function () { | |
Box2D.Dynamics.Joints.b2Joint.b2Joint.apply(this, arguments); | |
this.K = new b2Mat22(); | |
this.K1 = new b2Mat22(); | |
this.K2 = new b2Mat22(); | |
this.K3 = new b2Mat22(); | |
this.impulse3 = new b2Vec3(); | |
this.impulse2 = new b2Vec2(); | |
this.reduced = new b2Vec2(); | |
this.m_localAnchor1 = new b2Vec2(); | |
this.m_localAnchor2 = new b2Vec2(); | |
this.m_impulse = new b2Vec3(); | |
this.m_mass = new b2Mat33(); | |
}; | |
b2RevoluteJoint.prototype.GetAnchorA = function () { | |
return this.m_bodyA.GetWorldPoint(this.m_localAnchor1); | |
} | |
b2RevoluteJoint.prototype.GetAnchorB = function () { | |
return this.m_bodyB.GetWorldPoint(this.m_localAnchor2); | |
} | |
b2RevoluteJoint.prototype.GetReactionForce = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
return new b2Vec2(inv_dt * this.m_impulse.x, inv_dt * this.m_impulse.y); | |
} | |
b2RevoluteJoint.prototype.GetReactionTorque = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
return inv_dt * this.m_impulse.z; | |
} | |
b2RevoluteJoint.prototype.GetJointAngle = function () { | |
return this.m_bodyB.m_sweep.a - this.m_bodyA.m_sweep.a - this.m_referenceAngle; | |
} | |
b2RevoluteJoint.prototype.GetJointSpeed = function () { | |
return this.m_bodyB.m_angularVelocity - this.m_bodyA.m_angularVelocity; | |
} | |
b2RevoluteJoint.prototype.IsLimitEnabled = function () { | |
return this.m_enableLimit; | |
} | |
b2RevoluteJoint.prototype.EnableLimit = function (flag) { | |
this.m_enableLimit = flag; | |
} | |
b2RevoluteJoint.prototype.GetLowerLimit = function () { | |
return this.m_lowerAngle; | |
} | |
b2RevoluteJoint.prototype.GetUpperLimit = function () { | |
return this.m_upperAngle; | |
} | |
b2RevoluteJoint.prototype.SetLimits = function (lower, upper) { | |
if (lower === undefined) lower = 0; | |
if (upper === undefined) upper = 0; | |
this.m_lowerAngle = lower; | |
this.m_upperAngle = upper; | |
} | |
b2RevoluteJoint.prototype.IsMotorEnabled = function () { | |
this.m_bodyA.SetAwake(true); | |
this.m_bodyB.SetAwake(true); | |
return this.m_enableMotor; | |
} | |
b2RevoluteJoint.prototype.EnableMotor = function (flag) { | |
this.m_enableMotor = flag; | |
} | |
b2RevoluteJoint.prototype.SetMotorSpeed = function (speed) { | |
if (speed === undefined) speed = 0; | |
this.m_bodyA.SetAwake(true); | |
this.m_bodyB.SetAwake(true); | |
this.m_motorSpeed = speed; | |
} | |
b2RevoluteJoint.prototype.GetMotorSpeed = function () { | |
return this.m_motorSpeed; | |
} | |
b2RevoluteJoint.prototype.SetMaxMotorTorque = function (torque) { | |
if (torque === undefined) torque = 0; | |
this.m_maxMotorTorque = torque; | |
} | |
b2RevoluteJoint.prototype.GetMotorTorque = function () { | |
return this.m_maxMotorTorque; | |
} | |
b2RevoluteJoint.prototype.b2RevoluteJoint = function (def) { | |
this.__super.b2Joint.call(this, def); | |
this.m_localAnchor1.SetV(def.localAnchorA); | |
this.m_localAnchor2.SetV(def.localAnchorB); | |
this.m_referenceAngle = def.referenceAngle; | |
this.m_impulse.SetZero(); | |
this.m_motorImpulse = 0.0; | |
this.m_lowerAngle = def.lowerAngle; | |
this.m_upperAngle = def.upperAngle; | |
this.m_maxMotorTorque = def.maxMotorTorque; | |
this.m_motorSpeed = def.motorSpeed; | |
this.m_enableLimit = def.enableLimit; | |
this.m_enableMotor = def.enableMotor; | |
this.m_limitState = b2Joint.e_inactiveLimit; | |
} | |
b2RevoluteJoint.prototype.InitVelocityConstraints = function (step) { | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var tMat; | |
var tX = 0; | |
if (this.m_enableMotor || this.m_enableLimit) {} | |
tMat = bA.m_xf.R; | |
var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; | |
var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); | |
r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); | |
r1X = tX; | |
tMat = bB.m_xf.R; | |
var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; | |
var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); | |
r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); | |
r2X = tX; | |
var m1 = bA.m_invMass; | |
var m2 = bB.m_invMass; | |
var i1 = bA.m_invI; | |
var i2 = bB.m_invI; | |
this.m_mass.col1.x = m1 + m2 + r1Y * r1Y * i1 + r2Y * r2Y * i2; | |
this.m_mass.col2.x = (-r1Y * r1X * i1) - r2Y * r2X * i2; | |
this.m_mass.col3.x = (-r1Y * i1) - r2Y * i2; | |
this.m_mass.col1.y = this.m_mass.col2.x; | |
this.m_mass.col2.y = m1 + m2 + r1X * r1X * i1 + r2X * r2X * i2; | |
this.m_mass.col3.y = r1X * i1 + r2X * i2; | |
this.m_mass.col1.z = this.m_mass.col3.x; | |
this.m_mass.col2.z = this.m_mass.col3.y; | |
this.m_mass.col3.z = i1 + i2; | |
this.m_motorMass = 1.0 / (i1 + i2); | |
if (this.m_enableMotor == false) { | |
this.m_motorImpulse = 0.0; | |
} | |
if (this.m_enableLimit) { | |
var jointAngle = bB.m_sweep.a - bA.m_sweep.a - this.m_referenceAngle; | |
if (b2Math.Abs(this.m_upperAngle - this.m_lowerAngle) < 2.0 * b2Settings.b2_angularSlop) { | |
this.m_limitState = b2Joint.e_equalLimits; | |
} | |
else if (jointAngle <= this.m_lowerAngle) { | |
if (this.m_limitState != b2Joint.e_atLowerLimit) { | |
this.m_impulse.z = 0.0; | |
} | |
this.m_limitState = b2Joint.e_atLowerLimit; | |
} | |
else if (jointAngle >= this.m_upperAngle) { | |
if (this.m_limitState != b2Joint.e_atUpperLimit) { | |
this.m_impulse.z = 0.0; | |
} | |
this.m_limitState = b2Joint.e_atUpperLimit; | |
} | |
else { | |
this.m_limitState = b2Joint.e_inactiveLimit; | |
this.m_impulse.z = 0.0; | |
} | |
} | |
else { | |
this.m_limitState = b2Joint.e_inactiveLimit; | |
} | |
if (step.warmStarting) { | |
this.m_impulse.x *= step.dtRatio; | |
this.m_impulse.y *= step.dtRatio; | |
this.m_motorImpulse *= step.dtRatio; | |
var PX = this.m_impulse.x; | |
var PY = this.m_impulse.y; | |
bA.m_linearVelocity.x -= m1 * PX; | |
bA.m_linearVelocity.y -= m1 * PY; | |
bA.m_angularVelocity -= i1 * ((r1X * PY - r1Y * PX) + this.m_motorImpulse + this.m_impulse.z); | |
bB.m_linearVelocity.x += m2 * PX; | |
bB.m_linearVelocity.y += m2 * PY; | |
bB.m_angularVelocity += i2 * ((r2X * PY - r2Y * PX) + this.m_motorImpulse + this.m_impulse.z); | |
} | |
else { | |
this.m_impulse.SetZero(); | |
this.m_motorImpulse = 0.0; | |
} | |
} | |
b2RevoluteJoint.prototype.SolveVelocityConstraints = function (step) { | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var tMat; | |
var tX = 0; | |
var newImpulse = 0; | |
var r1X = 0; | |
var r1Y = 0; | |
var r2X = 0; | |
var r2Y = 0; | |
var v1 = bA.m_linearVelocity; | |
var w1 = bA.m_angularVelocity; | |
var v2 = bB.m_linearVelocity; | |
var w2 = bB.m_angularVelocity; | |
var m1 = bA.m_invMass; | |
var m2 = bB.m_invMass; | |
var i1 = bA.m_invI; | |
var i2 = bB.m_invI; | |
if (this.m_enableMotor && this.m_limitState != b2Joint.e_equalLimits) { | |
var Cdot = w2 - w1 - this.m_motorSpeed; | |
var impulse = this.m_motorMass * ((-Cdot)); | |
var oldImpulse = this.m_motorImpulse; | |
var maxImpulse = step.dt * this.m_maxMotorTorque; | |
this.m_motorImpulse = b2Math.Clamp(this.m_motorImpulse + impulse, (-maxImpulse), maxImpulse); | |
impulse = this.m_motorImpulse - oldImpulse; | |
w1 -= i1 * impulse; | |
w2 += i2 * impulse; | |
} | |
if (this.m_enableLimit && this.m_limitState != b2Joint.e_inactiveLimit) { | |
tMat = bA.m_xf.R; | |
r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; | |
r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); | |
r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); | |
r1X = tX; | |
tMat = bB.m_xf.R; | |
r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; | |
r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); | |
r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); | |
r2X = tX; | |
var Cdot1X = v2.x + ((-w2 * r2Y)) - v1.x - ((-w1 * r1Y)); | |
var Cdot1Y = v2.y + (w2 * r2X) - v1.y - (w1 * r1X); | |
var Cdot2 = w2 - w1; | |
this.m_mass.Solve33(this.impulse3, (-Cdot1X), (-Cdot1Y), (-Cdot2)); | |
if (this.m_limitState == b2Joint.e_equalLimits) { | |
this.m_impulse.Add(this.impulse3); | |
} | |
else if (this.m_limitState == b2Joint.e_atLowerLimit) { | |
newImpulse = this.m_impulse.z + this.impulse3.z; | |
if (newImpulse < 0.0) { | |
this.m_mass.Solve22(this.reduced, (-Cdot1X), (-Cdot1Y)); | |
this.impulse3.x = this.reduced.x; | |
this.impulse3.y = this.reduced.y; | |
this.impulse3.z = (-this.m_impulse.z); | |
this.m_impulse.x += this.reduced.x; | |
this.m_impulse.y += this.reduced.y; | |
this.m_impulse.z = 0.0; | |
} | |
} | |
else if (this.m_limitState == b2Joint.e_atUpperLimit) { | |
newImpulse = this.m_impulse.z + this.impulse3.z; | |
if (newImpulse > 0.0) { | |
this.m_mass.Solve22(this.reduced, (-Cdot1X), (-Cdot1Y)); | |
this.impulse3.x = this.reduced.x; | |
this.impulse3.y = this.reduced.y; | |
this.impulse3.z = (-this.m_impulse.z); | |
this.m_impulse.x += this.reduced.x; | |
this.m_impulse.y += this.reduced.y; | |
this.m_impulse.z = 0.0; | |
} | |
} | |
v1.x -= m1 * this.impulse3.x; | |
v1.y -= m1 * this.impulse3.y; | |
w1 -= i1 * (r1X * this.impulse3.y - r1Y * this.impulse3.x + this.impulse3.z); | |
v2.x += m2 * this.impulse3.x; | |
v2.y += m2 * this.impulse3.y; | |
w2 += i2 * (r2X * this.impulse3.y - r2Y * this.impulse3.x + this.impulse3.z); | |
} | |
else { | |
tMat = bA.m_xf.R; | |
r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; | |
r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); | |
r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); | |
r1X = tX; | |
tMat = bB.m_xf.R; | |
r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; | |
r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); | |
r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); | |
r2X = tX; | |
var CdotX = v2.x + ((-w2 * r2Y)) - v1.x - ((-w1 * r1Y)); | |
var CdotY = v2.y + (w2 * r2X) - v1.y - (w1 * r1X); | |
this.m_mass.Solve22(this.impulse2, (-CdotX), (-CdotY)); | |
this.m_impulse.x += this.impulse2.x; | |
this.m_impulse.y += this.impulse2.y; | |
v1.x -= m1 * this.impulse2.x; | |
v1.y -= m1 * this.impulse2.y; | |
w1 -= i1 * (r1X * this.impulse2.y - r1Y * this.impulse2.x); | |
v2.x += m2 * this.impulse2.x; | |
v2.y += m2 * this.impulse2.y; | |
w2 += i2 * (r2X * this.impulse2.y - r2Y * this.impulse2.x); | |
} | |
bA.m_linearVelocity.SetV(v1); | |
bA.m_angularVelocity = w1; | |
bB.m_linearVelocity.SetV(v2); | |
bB.m_angularVelocity = w2; | |
} | |
b2RevoluteJoint.prototype.SolvePositionConstraints = function (baumgarte) { | |
if (baumgarte === undefined) baumgarte = 0; | |
var oldLimitImpulse = 0; | |
var C = 0; | |
var tMat; | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var angularError = 0.0; | |
var positionError = 0.0; | |
var tX = 0; | |
var impulseX = 0; | |
var impulseY = 0; | |
if (this.m_enableLimit && this.m_limitState != b2Joint.e_inactiveLimit) { | |
var angle = bB.m_sweep.a - bA.m_sweep.a - this.m_referenceAngle; | |
var limitImpulse = 0.0; | |
if (this.m_limitState == b2Joint.e_equalLimits) { | |
C = b2Math.Clamp(angle - this.m_lowerAngle, (-b2Settings.b2_maxAngularCorrection), b2Settings.b2_maxAngularCorrection); | |
limitImpulse = (-this.m_motorMass * C); | |
angularError = b2Math.Abs(C); | |
} | |
else if (this.m_limitState == b2Joint.e_atLowerLimit) { | |
C = angle - this.m_lowerAngle; | |
angularError = (-C); | |
C = b2Math.Clamp(C + b2Settings.b2_angularSlop, (-b2Settings.b2_maxAngularCorrection), 0.0); | |
limitImpulse = (-this.m_motorMass * C); | |
} | |
else if (this.m_limitState == b2Joint.e_atUpperLimit) { | |
C = angle - this.m_upperAngle; | |
angularError = C; | |
C = b2Math.Clamp(C - b2Settings.b2_angularSlop, 0.0, b2Settings.b2_maxAngularCorrection); | |
limitImpulse = (-this.m_motorMass * C); | |
} | |
bA.m_sweep.a -= bA.m_invI * limitImpulse; | |
bB.m_sweep.a += bB.m_invI * limitImpulse; | |
bA.SynchronizeTransform(); | |
bB.SynchronizeTransform(); | |
} { | |
tMat = bA.m_xf.R; | |
var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; | |
var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r1X + tMat.col2.x * r1Y); | |
r1Y = (tMat.col1.y * r1X + tMat.col2.y * r1Y); | |
r1X = tX; | |
tMat = bB.m_xf.R; | |
var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; | |
var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * r2X + tMat.col2.x * r2Y); | |
r2Y = (tMat.col1.y * r2X + tMat.col2.y * r2Y); | |
r2X = tX; | |
var CX = bB.m_sweep.c.x + r2X - bA.m_sweep.c.x - r1X; | |
var CY = bB.m_sweep.c.y + r2Y - bA.m_sweep.c.y - r1Y; | |
var CLengthSquared = CX * CX + CY * CY; | |
var CLength = Math.sqrt(CLengthSquared); | |
positionError = CLength; | |
var invMass1 = bA.m_invMass; | |
var invMass2 = bB.m_invMass; | |
var invI1 = bA.m_invI; | |
var invI2 = bB.m_invI; | |
var k_allowedStretch = 10.0 * b2Settings.b2_linearSlop; | |
if (CLengthSquared > k_allowedStretch * k_allowedStretch) { | |
var uX = CX / CLength; | |
var uY = CY / CLength; | |
var k = invMass1 + invMass2; | |
var m = 1.0 / k; | |
impulseX = m * ((-CX)); | |
impulseY = m * ((-CY)); | |
var k_beta = 0.5; | |
bA.m_sweep.c.x -= k_beta * invMass1 * impulseX; | |
bA.m_sweep.c.y -= k_beta * invMass1 * impulseY; | |
bB.m_sweep.c.x += k_beta * invMass2 * impulseX; | |
bB.m_sweep.c.y += k_beta * invMass2 * impulseY; | |
CX = bB.m_sweep.c.x + r2X - bA.m_sweep.c.x - r1X; | |
CY = bB.m_sweep.c.y + r2Y - bA.m_sweep.c.y - r1Y; | |
} | |
this.K1.col1.x = invMass1 + invMass2; | |
this.K1.col2.x = 0.0; | |
this.K1.col1.y = 0.0; | |
this.K1.col2.y = invMass1 + invMass2; | |
this.K2.col1.x = invI1 * r1Y * r1Y; | |
this.K2.col2.x = (-invI1 * r1X * r1Y); | |
this.K2.col1.y = (-invI1 * r1X * r1Y); | |
this.K2.col2.y = invI1 * r1X * r1X; | |
this.K3.col1.x = invI2 * r2Y * r2Y; | |
this.K3.col2.x = (-invI2 * r2X * r2Y); | |
this.K3.col1.y = (-invI2 * r2X * r2Y); | |
this.K3.col2.y = invI2 * r2X * r2X; | |
this.K.SetM(this.K1); | |
this.K.AddM(this.K2); | |
this.K.AddM(this.K3); | |
this.K.Solve(b2RevoluteJoint.tImpulse, (-CX), (-CY)); | |
impulseX = b2RevoluteJoint.tImpulse.x; | |
impulseY = b2RevoluteJoint.tImpulse.y; | |
bA.m_sweep.c.x -= bA.m_invMass * impulseX; | |
bA.m_sweep.c.y -= bA.m_invMass * impulseY; | |
bA.m_sweep.a -= bA.m_invI * (r1X * impulseY - r1Y * impulseX); | |
bB.m_sweep.c.x += bB.m_invMass * impulseX; | |
bB.m_sweep.c.y += bB.m_invMass * impulseY; | |
bB.m_sweep.a += bB.m_invI * (r2X * impulseY - r2Y * impulseX); | |
bA.SynchronizeTransform(); | |
bB.SynchronizeTransform(); | |
} | |
return positionError <= b2Settings.b2_linearSlop && angularError <= b2Settings.b2_angularSlop; | |
} | |
Box2D.postDefs.push(function () { | |
Box2D.Dynamics.Joints.b2RevoluteJoint.tImpulse = new b2Vec2(); | |
}); | |
Box2D.inherit(b2RevoluteJointDef, Box2D.Dynamics.Joints.b2JointDef); | |
b2RevoluteJointDef.prototype.__super = Box2D.Dynamics.Joints.b2JointDef.prototype; | |
b2RevoluteJointDef.b2RevoluteJointDef = function () { | |
Box2D.Dynamics.Joints.b2JointDef.b2JointDef.apply(this, arguments); | |
this.localAnchorA = new b2Vec2(); | |
this.localAnchorB = new b2Vec2(); | |
}; | |
b2RevoluteJointDef.prototype.b2RevoluteJointDef = function () { | |
this.__super.b2JointDef.call(this); | |
this.type = b2Joint.e_revoluteJoint; | |
this.localAnchorA.Set(0.0, 0.0); | |
this.localAnchorB.Set(0.0, 0.0); | |
this.referenceAngle = 0.0; | |
this.lowerAngle = 0.0; | |
this.upperAngle = 0.0; | |
this.maxMotorTorque = 0.0; | |
this.motorSpeed = 0.0; | |
this.enableLimit = false; | |
this.enableMotor = false; | |
} | |
b2RevoluteJointDef.prototype.Initialize = function (bA, bB, anchor) { | |
this.bodyA = bA; | |
this.bodyB = bB; | |
this.localAnchorA = this.bodyA.GetLocalPoint(anchor); | |
this.localAnchorB = this.bodyB.GetLocalPoint(anchor); | |
this.referenceAngle = this.bodyB.GetAngle() - this.bodyA.GetAngle(); | |
} | |
Box2D.inherit(b2WeldJoint, Box2D.Dynamics.Joints.b2Joint); | |
b2WeldJoint.prototype.__super = Box2D.Dynamics.Joints.b2Joint.prototype; | |
b2WeldJoint.b2WeldJoint = function () { | |
Box2D.Dynamics.Joints.b2Joint.b2Joint.apply(this, arguments); | |
this.m_localAnchorA = new b2Vec2(); | |
this.m_localAnchorB = new b2Vec2(); | |
this.m_impulse = new b2Vec3(); | |
this.m_mass = new b2Mat33(); | |
}; | |
b2WeldJoint.prototype.GetAnchorA = function () { | |
return this.m_bodyA.GetWorldPoint(this.m_localAnchorA); | |
} | |
b2WeldJoint.prototype.GetAnchorB = function () { | |
return this.m_bodyB.GetWorldPoint(this.m_localAnchorB); | |
} | |
b2WeldJoint.prototype.GetReactionForce = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
return new b2Vec2(inv_dt * this.m_impulse.x, inv_dt * this.m_impulse.y); | |
} | |
b2WeldJoint.prototype.GetReactionTorque = function (inv_dt) { | |
if (inv_dt === undefined) inv_dt = 0; | |
return inv_dt * this.m_impulse.z; | |
} | |
b2WeldJoint.prototype.b2WeldJoint = function (def) { | |
this.__super.b2Joint.call(this, def); | |
this.m_localAnchorA.SetV(def.localAnchorA); | |
this.m_localAnchorB.SetV(def.localAnchorB); | |
this.m_referenceAngle = def.referenceAngle; | |
this.m_impulse.SetZero(); | |
this.m_mass = new b2Mat33(); | |
} | |
b2WeldJoint.prototype.InitVelocityConstraints = function (step) { | |
var tMat; | |
var tX = 0; | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
tMat = bA.m_xf.R; | |
var rAX = this.m_localAnchorA.x - bA.m_sweep.localCenter.x; | |
var rAY = this.m_localAnchorA.y - bA.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * rAX + tMat.col2.x * rAY); | |
rAY = (tMat.col1.y * rAX + tMat.col2.y * rAY); | |
rAX = tX; | |
tMat = bB.m_xf.R; | |
var rBX = this.m_localAnchorB.x - bB.m_sweep.localCenter.x; | |
var rBY = this.m_localAnchorB.y - bB.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * rBX + tMat.col2.x * rBY); | |
rBY = (tMat.col1.y * rBX + tMat.col2.y * rBY); | |
rBX = tX; | |
var mA = bA.m_invMass; | |
var mB = bB.m_invMass; | |
var iA = bA.m_invI; | |
var iB = bB.m_invI; | |
this.m_mass.col1.x = mA + mB + rAY * rAY * iA + rBY * rBY * iB; | |
this.m_mass.col2.x = (-rAY * rAX * iA) - rBY * rBX * iB; | |
this.m_mass.col3.x = (-rAY * iA) - rBY * iB; | |
this.m_mass.col1.y = this.m_mass.col2.x; | |
this.m_mass.col2.y = mA + mB + rAX * rAX * iA + rBX * rBX * iB; | |
this.m_mass.col3.y = rAX * iA + rBX * iB; | |
this.m_mass.col1.z = this.m_mass.col3.x; | |
this.m_mass.col2.z = this.m_mass.col3.y; | |
this.m_mass.col3.z = iA + iB; | |
if (step.warmStarting) { | |
this.m_impulse.x *= step.dtRatio; | |
this.m_impulse.y *= step.dtRatio; | |
this.m_impulse.z *= step.dtRatio; | |
bA.m_linearVelocity.x -= mA * this.m_impulse.x; | |
bA.m_linearVelocity.y -= mA * this.m_impulse.y; | |
bA.m_angularVelocity -= iA * (rAX * this.m_impulse.y - rAY * this.m_impulse.x + this.m_impulse.z); | |
bB.m_linearVelocity.x += mB * this.m_impulse.x; | |
bB.m_linearVelocity.y += mB * this.m_impulse.y; | |
bB.m_angularVelocity += iB * (rBX * this.m_impulse.y - rBY * this.m_impulse.x + this.m_impulse.z); | |
} | |
else { | |
this.m_impulse.SetZero(); | |
} | |
} | |
b2WeldJoint.prototype.SolveVelocityConstraints = function (step) { | |
var tMat; | |
var tX = 0; | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
var vA = bA.m_linearVelocity; | |
var wA = bA.m_angularVelocity; | |
var vB = bB.m_linearVelocity; | |
var wB = bB.m_angularVelocity; | |
var mA = bA.m_invMass; | |
var mB = bB.m_invMass; | |
var iA = bA.m_invI; | |
var iB = bB.m_invI; | |
tMat = bA.m_xf.R; | |
var rAX = this.m_localAnchorA.x - bA.m_sweep.localCenter.x; | |
var rAY = this.m_localAnchorA.y - bA.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * rAX + tMat.col2.x * rAY); | |
rAY = (tMat.col1.y * rAX + tMat.col2.y * rAY); | |
rAX = tX; | |
tMat = bB.m_xf.R; | |
var rBX = this.m_localAnchorB.x - bB.m_sweep.localCenter.x; | |
var rBY = this.m_localAnchorB.y - bB.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * rBX + tMat.col2.x * rBY); | |
rBY = (tMat.col1.y * rBX + tMat.col2.y * rBY); | |
rBX = tX; | |
var Cdot1X = vB.x - wB * rBY - vA.x + wA * rAY; | |
var Cdot1Y = vB.y + wB * rBX - vA.y - wA * rAX; | |
var Cdot2 = wB - wA; | |
var impulse = new b2Vec3(); | |
this.m_mass.Solve33(impulse, (-Cdot1X), (-Cdot1Y), (-Cdot2)); | |
this.m_impulse.Add(impulse); | |
vA.x -= mA * impulse.x; | |
vA.y -= mA * impulse.y; | |
wA -= iA * (rAX * impulse.y - rAY * impulse.x + impulse.z); | |
vB.x += mB * impulse.x; | |
vB.y += mB * impulse.y; | |
wB += iB * (rBX * impulse.y - rBY * impulse.x + impulse.z); | |
bA.m_angularVelocity = wA; | |
bB.m_angularVelocity = wB; | |
} | |
b2WeldJoint.prototype.SolvePositionConstraints = function (baumgarte) { | |
if (baumgarte === undefined) baumgarte = 0; | |
var tMat; | |
var tX = 0; | |
var bA = this.m_bodyA; | |
var bB = this.m_bodyB; | |
tMat = bA.m_xf.R; | |
var rAX = this.m_localAnchorA.x - bA.m_sweep.localCenter.x; | |
var rAY = this.m_localAnchorA.y - bA.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * rAX + tMat.col2.x * rAY); | |
rAY = (tMat.col1.y * rAX + tMat.col2.y * rAY); | |
rAX = tX; | |
tMat = bB.m_xf.R; | |
var rBX = this.m_localAnchorB.x - bB.m_sweep.localCenter.x; | |
var rBY = this.m_localAnchorB.y - bB.m_sweep.localCenter.y; | |
tX = (tMat.col1.x * rBX + tMat.col2.x * rBY); | |
rBY = (tMat.col1.y * rBX + tMat.col2.y * rBY); | |
rBX = tX; | |
var mA = bA.m_invMass; | |
var mB = bB.m_invMass; | |
var iA = bA.m_invI; | |
var iB = bB.m_invI; | |
var C1X = bB.m_sweep.c.x + rBX - bA.m_sweep.c.x - rAX; | |
var C1Y = bB.m_sweep.c.y + rBY - bA.m_sweep.c.y - rAY; | |
var C2 = bB.m_sweep.a - bA.m_sweep.a - this.m_referenceAngle; | |
var k_allowedStretch = 10.0 * b2Settings.b2_linearSlop; | |
var positionError = Math.sqrt(C1X * C1X + C1Y * C1Y); | |
var angularError = b2Math.Abs(C2); | |
if (positionError > k_allowedStretch) { | |
iA *= 1.0; | |
iB *= 1.0; | |
} | |
this.m_mass.col1.x = mA + mB + rAY * rAY * iA + rBY * rBY * iB; | |
this.m_mass.col2.x = (-rAY * rAX * iA) - rBY * rBX * iB; | |
this.m_mass.col3.x = (-rAY * iA) - rBY * iB; | |
this.m_mass.col1.y = this.m_mass.col2.x; | |
this.m_mass.col2.y = mA + mB + rAX * rAX * iA + rBX * rBX * iB; | |
this.m_mass.col3.y = rAX * iA + rBX * iB; | |
this.m_mass.col1.z = this.m_mass.col3.x; | |
this.m_mass.col2.z = this.m_mass.col3.y; | |
this.m_mass.col3.z = iA + iB; | |
var impulse = new b2Vec3(); | |
this.m_mass.Solve33(impulse, (-C1X), (-C1Y), (-C2)); | |
bA.m_sweep.c.x -= mA * impulse.x; | |
bA.m_sweep.c.y -= mA * impulse.y; | |
bA.m_sweep.a -= iA * (rAX * impulse.y - rAY * impulse.x + impulse.z); | |
bB.m_sweep.c.x += mB * impulse.x; | |
bB.m_sweep.c.y += mB * impulse.y; | |
bB.m_sweep.a += iB * (rBX * impulse.y - rBY * impulse.x + impulse.z); | |
bA.SynchronizeTransform(); | |
bB.SynchronizeTransform(); | |
return positionError <= b2Settings.b2_linearSlop && angularError <= b2Settings.b2_angularSlop; | |
} | |
Box2D.inherit(b2WeldJointDef, Box2D.Dynamics.Joints.b2JointDef); | |
b2WeldJointDef.prototype.__super = Box2D.Dynamics.Joints.b2JointDef.prototype; | |
b2WeldJointDef.b2WeldJointDef = function () { | |
Box2D.Dynamics.Joints.b2JointDef.b2JointDef.apply(this, arguments); | |
this.localAnchorA = new b2Vec2(); | |
this.localAnchorB = new b2Vec2(); | |
}; | |
b2WeldJointDef.prototype.b2WeldJointDef = function () { | |
this.__super.b2JointDef.call(this); | |
this.type = b2Joint.e_weldJoint; | |
this.referenceAngle = 0.0; | |
} | |
b2WeldJointDef.prototype.Initialize = function (bA, bB, anchor) { | |
this.bodyA = bA; | |
this.bodyB = bB; | |
this.localAnchorA.SetV(this.bodyA.GetLocalPoint(anchor)); | |
this.localAnchorB.SetV(this.bodyB.GetLocalPoint(anchor)); | |
this.referenceAngle = this.bodyB.GetAngle() - this.bodyA.GetAngle(); | |
} | |
})(); | |
(function () { | |
var b2DebugDraw = Box2D.Dynamics.b2DebugDraw; | |
b2DebugDraw.b2DebugDraw = function () { | |
this.m_drawScale = 1.0; | |
this.m_lineThickness = 1.0; | |
this.m_alpha = 1.0; | |
this.m_fillAlpha = 1.0; | |
this.m_xformScale = 1.0; | |
var __this = this; | |
//#WORKAROUND | |
this.m_sprite = { | |
graphics: { | |
clear: function () { | |
__this.m_ctx.clearRect(0, 0, __this.m_ctx.canvas.width, __this.m_ctx.canvas.height) | |
} | |
} | |
}; | |
}; | |
b2DebugDraw.prototype._color = function (color, alpha) { | |
return "rgba(" + ((color & 0xFF0000) >> 16) + "," + ((color & 0xFF00) >> 8) + "," + (color & 0xFF) + "," + alpha + ")"; | |
}; | |
b2DebugDraw.prototype.b2DebugDraw = function () { | |
this.m_drawFlags = 0; | |
}; | |
b2DebugDraw.prototype.SetFlags = function (flags) { | |
if (flags === undefined) flags = 0; | |
this.m_drawFlags = flags; | |
}; | |
b2DebugDraw.prototype.GetFlags = function () { | |
return this.m_drawFlags; | |
}; | |
b2DebugDraw.prototype.AppendFlags = function (flags) { | |
if (flags === undefined) flags = 0; | |
this.m_drawFlags |= flags; | |
}; | |
b2DebugDraw.prototype.ClearFlags = function (flags) { | |
if (flags === undefined) flags = 0; | |
this.m_drawFlags &= ~flags; | |
}; | |
b2DebugDraw.prototype.SetSprite = function (sprite) { | |
this.m_ctx = sprite; | |
}; | |
b2DebugDraw.prototype.GetSprite = function () { | |
return this.m_ctx; | |
}; | |
b2DebugDraw.prototype.SetDrawScale = function (drawScale) { | |
if (drawScale === undefined) drawScale = 0; | |
this.m_drawScale = drawScale; | |
}; | |
b2DebugDraw.prototype.GetDrawScale = function () { | |
return this.m_drawScale; | |
}; | |
b2DebugDraw.prototype.SetLineThickness = function (lineThickness) { | |
if (lineThickness === undefined) lineThickness = 0; | |
this.m_lineThickness = lineThickness; | |
this.m_ctx.strokeWidth = lineThickness; | |
}; | |
b2DebugDraw.prototype.GetLineThickness = function () { | |
return this.m_lineThickness; | |
}; | |
b2DebugDraw.prototype.SetAlpha = function (alpha) { | |
if (alpha === undefined) alpha = 0; | |
this.m_alpha = alpha; | |
}; | |
b2DebugDraw.prototype.GetAlpha = function () { | |
return this.m_alpha; | |
}; | |
b2DebugDraw.prototype.SetFillAlpha = function (alpha) { | |
if (alpha === undefined) alpha = 0; | |
this.m_fillAlpha = alpha; | |
}; | |
b2DebugDraw.prototype.GetFillAlpha = function () { | |
return this.m_fillAlpha; | |
}; | |
b2DebugDraw.prototype.SetXFormScale = function (xformScale) { | |
if (xformScale === undefined) xformScale = 0; | |
this.m_xformScale = xformScale; | |
}; | |
b2DebugDraw.prototype.GetXFormScale = function () { | |
return this.m_xformScale; | |
}; | |
b2DebugDraw.prototype.DrawPolygon = function (vertices, vertexCount, color) { | |
if (!vertexCount) return; | |
var s = this.m_ctx; | |
var drawScale = this.m_drawScale; | |
s.beginPath(); | |
s.strokeStyle = this._color(color.color, this.m_alpha); | |
s.moveTo(vertices[0].x * drawScale, vertices[0].y * drawScale); | |
for (var i = 1; i < vertexCount; i++) { | |
s.lineTo(vertices[i].x * drawScale, vertices[i].y * drawScale); | |
} | |
s.lineTo(vertices[0].x * drawScale, vertices[0].y * drawScale); | |
s.closePath(); | |
s.stroke(); | |
}; | |
b2DebugDraw.prototype.DrawSolidPolygon = function (vertices, vertexCount, color) { | |
if (!vertexCount) return; | |
var s = this.m_ctx; | |
var drawScale = this.m_drawScale; | |
s.beginPath(); | |
s.strokeStyle = this._color(color.color, this.m_alpha); | |
s.fillStyle = this._color(color.color, this.m_fillAlpha); | |
s.moveTo(vertices[0].x * drawScale, vertices[0].y * drawScale); | |
for (var i = 1; i < vertexCount; i++) { | |
s.lineTo(vertices[i].x * drawScale, vertices[i].y * drawScale); | |
} | |
s.lineTo(vertices[0].x * drawScale, vertices[0].y * drawScale); | |
s.closePath(); | |
s.fill(); | |
s.stroke(); | |
}; | |
b2DebugDraw.prototype.DrawCircle = function (center, radius, color) { | |
if (!radius) return; | |
var s = this.m_ctx; | |
var drawScale = this.m_drawScale; | |
s.beginPath(); | |
s.strokeStyle = this._color(color.color, this.m_alpha); | |
s.arc(center.x * drawScale, center.y * drawScale, radius * drawScale, 0, Math.PI * 2, true); | |
s.closePath(); | |
s.stroke(); | |
}; | |
b2DebugDraw.prototype.DrawSolidCircle = function (center, radius, axis, color) { | |
if (!radius) return; | |
var s = this.m_ctx, | |
drawScale = this.m_drawScale, | |
cx = center.x * drawScale, | |
cy = center.y * drawScale; | |
s.moveTo(0, 0); | |
s.beginPath(); | |
s.strokeStyle = this._color(color.color, this.m_alpha); | |
s.fillStyle = this._color(color.color, this.m_fillAlpha); | |
s.arc(cx, cy, radius * drawScale, 0, Math.PI * 2, true); | |
s.moveTo(cx, cy); | |
s.lineTo((center.x + axis.x * radius) * drawScale, (center.y + axis.y * radius) * drawScale); | |
s.closePath(); | |
s.fill(); | |
s.stroke(); | |
}; | |
b2DebugDraw.prototype.DrawSegment = function (p1, p2, color) { | |
var s = this.m_ctx, | |
drawScale = this.m_drawScale; | |
s.strokeStyle = this._color(color.color, this.m_alpha); | |
s.beginPath(); | |
s.moveTo(p1.x * drawScale, p1.y * drawScale); | |
s.lineTo(p2.x * drawScale, p2.y * drawScale); | |
s.closePath(); | |
s.stroke(); | |
}; | |
b2DebugDraw.prototype.DrawTransform = function (xf) { | |
var s = this.m_ctx, | |
drawScale = this.m_drawScale; | |
s.beginPath(); | |
s.strokeStyle = this._color(0xff0000, this.m_alpha); | |
s.moveTo(xf.position.x * drawScale, xf.position.y * drawScale); | |
s.lineTo((xf.position.x + this.m_xformScale * xf.R.col1.x) * drawScale, (xf.position.y + this.m_xformScale * xf.R.col1.y) * drawScale); | |
s.strokeStyle = this._color(0xff00, this.m_alpha); | |
s.moveTo(xf.position.x * drawScale, xf.position.y * drawScale); | |
s.lineTo((xf.position.x + this.m_xformScale * xf.R.col2.x) * drawScale, (xf.position.y + this.m_xformScale * xf.R.col2.y) * drawScale); | |
s.closePath(); | |
s.stroke(); | |
}; | |
})(); //post-definitions | |
var i; | |
for (i = 0; i < Box2D.postDefs.length; ++i) Box2D.postDefs[i](); | |
delete Box2D.postDefs; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* dat-gui JavaScript Controller Library | |
* http://code.google.com/p/dat-gui | |
* | |
* Copyright 2011 Data Arts Team, Google Creative Lab | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
*/ | |
/** @namespace */ | |
var dat = dat || {}; | |
/** @namespace */ | |
dat.gui = dat.gui || {}; | |
/** @namespace */ | |
dat.utils = dat.utils || {}; | |
/** @namespace */ | |
dat.controllers = dat.controllers || {}; | |
/** @namespace */ | |
dat.dom = dat.dom || {}; | |
/** @namespace */ | |
dat.color = dat.color || {}; | |
dat.utils.css = (function () { | |
return { | |
load: function (url, doc) { | |
doc = doc || document; | |
var link = doc.createElement('link'); | |
link.type = 'text/css'; | |
link.rel = 'stylesheet'; | |
link.href = url; | |
doc.getElementsByTagName('head')[0].appendChild(link); | |
}, | |
inject: function(css, doc) { | |
doc = doc || document; | |
var injected = document.createElement('style'); | |
injected.type = 'text/css'; | |
injected.innerHTML = css; | |
doc.getElementsByTagName('head')[0].appendChild(injected); | |
} | |
} | |
})(); | |
dat.utils.common = (function () { | |
var ARR_EACH = Array.prototype.forEach; | |
var ARR_SLICE = Array.prototype.slice; | |
/** | |
* Band-aid methods for things that should be a lot easier in JavaScript. | |
* Implementation and structure inspired by underscore.js | |
* http://documentcloud.github.com/underscore/ | |
*/ | |
return { | |
BREAK: {}, | |
extend: function(target) { | |
this.each(ARR_SLICE.call(arguments, 1), function(obj) { | |
for (var key in obj) | |
if (!this.isUndefined(obj[key])) | |
target[key] = obj[key]; | |
}, this); | |
return target; | |
}, | |
defaults: function(target) { | |
this.each(ARR_SLICE.call(arguments, 1), function(obj) { | |
for (var key in obj) | |
if (this.isUndefined(target[key])) | |
target[key] = obj[key]; | |
}, this); | |
return target; | |
}, | |
compose: function() { | |
var toCall = ARR_SLICE.call(arguments); | |
return function() { | |
var args = ARR_SLICE.call(arguments); | |
for (var i = toCall.length -1; i >= 0; i--) { | |
args = [toCall[i].apply(this, args)]; | |
} | |
return args[0]; | |
} | |
}, | |
each: function(obj, itr, scope) { | |
if (ARR_EACH && obj.forEach === ARR_EACH) { | |
obj.forEach(itr, scope); | |
} else if (obj.length === obj.length + 0) { // Is number but not NaN | |
for (var key = 0, l = obj.length; key < l; key++) | |
if (key in obj && itr.call(scope, obj[key], key) === this.BREAK) | |
return; | |
} else { | |
for (var key in obj) | |
if (itr.call(scope, obj[key], key) === this.BREAK) | |
return; | |
} | |
}, | |
defer: function(fnc) { | |
setTimeout(fnc, 0); | |
}, | |
toArray: function(obj) { | |
if (obj.toArray) return obj.toArray(); | |
return ARR_SLICE.call(obj); | |
}, | |
isUndefined: function(obj) { | |
return obj === undefined; | |
}, | |
isNull: function(obj) { | |
return obj === null; | |
}, | |
isNaN: function(obj) { | |
return obj !== obj; | |
}, | |
isArray: Array.isArray || function(obj) { | |
return obj.constructor === Array; | |
}, | |
isObject: function(obj) { | |
return obj === Object(obj); | |
}, | |
isNumber: function(obj) { | |
return obj === obj+0; | |
}, | |
isString: function(obj) { | |
return obj === obj+''; | |
}, | |
isBoolean: function(obj) { | |
return obj === false || obj === true; | |
}, | |
isFunction: function(obj) { | |
return Object.prototype.toString.call(obj) === '[object Function]'; | |
} | |
}; | |
})(); | |
dat.controllers.Controller = (function (common) { | |
/** | |
* @class An "abstract" class that represents a given property of an object. | |
* | |
* @param {Object} object The object to be manipulated | |
* @param {string} property The name of the property to be manipulated | |
* | |
* @member dat.controllers | |
*/ | |
var Controller = function(object, property) { | |
this.initialValue = object[property]; | |
/** | |
* Those who extend this class will put their DOM elements in here. | |
* @type {DOMElement} | |
*/ | |
this.domElement = document.createElement('div'); | |
/** | |
* The object to manipulate | |
* @type {Object} | |
*/ | |
this.object = object; | |
/** | |
* The name of the property to manipulate | |
* @type {String} | |
*/ | |
this.property = property; | |
/** | |
* The function to be called on change. | |
* @type {Function} | |
* @ignore | |
*/ | |
this.__onChange = undefined; | |
/** | |
* The function to be called on finishing change. | |
* @type {Function} | |
* @ignore | |
*/ | |
this.__onFinishChange = undefined; | |
}; | |
common.extend( | |
Controller.prototype, | |
/** @lends dat.controllers.Controller.prototype */ | |
{ | |
/** | |
* Specify that a function fire every time someone changes the value with | |
* this Controller. | |
* | |
* @param {Function} fnc This function will be called whenever the value | |
* is modified via this Controller. | |
* @returns {dat.controllers.Controller} this | |
*/ | |
onChange: function(fnc) { | |
this.__onChange = fnc; | |
return this; | |
}, | |
/** | |
* Specify that a function fire every time someone "finishes" changing | |
* the value wih this Controller. Useful for values that change | |
* incrementally like numbers or strings. | |
* | |
* @param {Function} fnc This function will be called whenever | |
* someone "finishes" changing the value via this Controller. | |
* @returns {dat.controllers.Controller} this | |
*/ | |
onFinishChange: function(fnc) { | |
this.__onFinishChange = fnc; | |
return this; | |
}, | |
/** | |
* Change the value of <code>object[property]</code> | |
* | |
* @param {Object} newValue The new value of <code>object[property]</code> | |
*/ | |
setValue: function(newValue) { | |
this.object[this.property] = newValue; | |
if (this.__onChange) { | |
this.__onChange.call(this, newValue); | |
} | |
this.updateDisplay(); | |
return this; | |
}, | |
/** | |
* Gets the value of <code>object[property]</code> | |
* | |
* @returns {Object} The current value of <code>object[property]</code> | |
*/ | |
getValue: function() { | |
return this.object[this.property]; | |
}, | |
/** | |
* Refreshes the visual display of a Controller in order to keep sync | |
* with the object's current value. | |
* @returns {dat.controllers.Controller} this | |
*/ | |
updateDisplay: function() { | |
return this; | |
}, | |
/** | |
* @returns {Boolean} true if the value has deviated from initialValue | |
*/ | |
isModified: function() { | |
return this.initialValue !== this.getValue() | |
} | |
} | |
); | |
return Controller; | |
})(dat.utils.common); | |
dat.dom.dom = (function (common) { | |
var EVENT_MAP = { | |
'HTMLEvents': ['change'], | |
'MouseEvents': ['click','mousemove','mousedown','mouseup', 'mouseover'], | |
'KeyboardEvents': ['keydown'] | |
}; | |
var EVENT_MAP_INV = {}; | |
common.each(EVENT_MAP, function(v, k) { | |
common.each(v, function(e) { | |
EVENT_MAP_INV[e] = k; | |
}); | |
}); | |
var CSS_VALUE_PIXELS = /(\d+(\.\d+)?)px/; | |
function cssValueToPixels(val) { | |
if (val === '0' || common.isUndefined(val)) return 0; | |
var match = val.match(CSS_VALUE_PIXELS); | |
if (!common.isNull(match)) { | |
return parseFloat(match[1]); | |
} | |
// TODO ...ems? %? | |
return 0; | |
} | |
/** | |
* @namespace | |
* @member dat.dom | |
*/ | |
var dom = { | |
/** | |
* | |
* @param elem | |
* @param selectable | |
*/ | |
makeSelectable: function(elem, selectable) { | |
if (elem === undefined || elem.style === undefined) return; | |
elem.onselectstart = selectable ? function() { | |
return false; | |
} : function() { | |
}; | |
elem.style.MozUserSelect = selectable ? 'auto' : 'none'; | |
elem.style.KhtmlUserSelect = selectable ? 'auto' : 'none'; | |
elem.unselectable = selectable ? 'on' : 'off'; | |
}, | |
/** | |
* | |
* @param elem | |
* @param horizontal | |
* @param vertical | |
*/ | |
makeFullscreen: function(elem, horizontal, vertical) { | |
if (common.isUndefined(horizontal)) horizontal = true; | |
if (common.isUndefined(vertical)) vertical = true; | |
elem.style.position = 'absolute'; | |
if (horizontal) { | |
elem.style.left = 0; | |
elem.style.right = 0; | |
} | |
if (vertical) { | |
elem.style.top = 0; | |
elem.style.bottom = 0; | |
} | |
}, | |
/** | |
* | |
* @param elem | |
* @param eventType | |
* @param params | |
*/ | |
fakeEvent: function(elem, eventType, params, aux) { | |
params = params || {}; | |
var className = EVENT_MAP_INV[eventType]; | |
if (!className) { | |
throw new Error('Event type ' + eventType + ' not supported.'); | |
} | |
var evt = document.createEvent(className); | |
switch (className) { | |
case 'MouseEvents': | |
var clientX = params.x || params.clientX || 0; | |
var clientY = params.y || params.clientY || 0; | |
evt.initMouseEvent(eventType, params.bubbles || false, | |
params.cancelable || true, window, params.clickCount || 1, | |
0, //screen X | |
0, //screen Y | |
clientX, //client X | |
clientY, //client Y | |
false, false, false, false, 0, null); | |
break; | |
case 'KeyboardEvents': | |
var init = evt.initKeyboardEvent || evt.initKeyEvent; // webkit || moz | |
common.defaults(params, { | |
cancelable: true, | |
ctrlKey: false, | |
altKey: false, | |
shiftKey: false, | |
metaKey: false, | |
keyCode: undefined, | |
charCode: undefined | |
}); | |
init(eventType, params.bubbles || false, | |
params.cancelable, window, | |
params.ctrlKey, params.altKey, | |
params.shiftKey, params.metaKey, | |
params.keyCode, params.charCode); | |
break; | |
default: | |
evt.initEvent(eventType, params.bubbles || false, | |
params.cancelable || true); | |
break; | |
} | |
common.defaults(evt, aux); | |
elem.dispatchEvent(evt); | |
}, | |
/** | |
* | |
* @param elem | |
* @param event | |
* @param func | |
* @param bool | |
*/ | |
bind: function(elem, event, func, bool) { | |
bool = bool || false; | |
if (elem.addEventListener) | |
elem.addEventListener(event, func, bool); | |
else if (elem.attachEvent) | |
elem.attachEvent('on' + event, func); | |
return dom; | |
}, | |
/** | |
* | |
* @param elem | |
* @param event | |
* @param func | |
* @param bool | |
*/ | |
unbind: function(elem, event, func, bool) { | |
bool = bool || false; | |
if (elem.removeEventListener) | |
elem.removeEventListener(event, func, bool); | |
else if (elem.detachEvent) | |
elem.detachEvent('on' + event, func); | |
return dom; | |
}, | |
/** | |
* | |
* @param elem | |
* @param className | |
*/ | |
addClass: function(elem, className) { | |
if (elem.className === undefined) { | |
elem.className = className; | |
} else if (elem.className !== className) { | |
var classes = elem.className.split(/ +/); | |
if (classes.indexOf(className) == -1) { | |
classes.push(className); | |
elem.className = classes.join(' ').replace(/^\s+/, '').replace(/\s+$/, ''); | |
} | |
} | |
return dom; | |
}, | |
/** | |
* | |
* @param elem | |
* @param className | |
*/ | |
removeClass: function(elem, className) { | |
if (className) { | |
if (elem.className === undefined) { | |
// elem.className = className; | |
} else if (elem.className === className) { | |
elem.removeAttribute('class'); | |
} else { | |
var classes = elem.className.split(/ +/); | |
var index = classes.indexOf(className); | |
if (index != -1) { | |
classes.splice(index, 1); | |
elem.className = classes.join(' '); | |
} | |
} | |
} else { | |
elem.className = undefined; | |
} | |
return dom; | |
}, | |
hasClass: function(elem, className) { | |
return new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)').test(elem.className) || false; | |
}, | |
/** | |
* | |
* @param elem | |
*/ | |
getWidth: function(elem) { | |
var style = getComputedStyle(elem); | |
return cssValueToPixels(style['border-left-width']) + | |
cssValueToPixels(style['border-right-width']) + | |
cssValueToPixels(style['padding-left']) + | |
cssValueToPixels(style['padding-right']) + | |
cssValueToPixels(style['width']); | |
}, | |
/** | |
* | |
* @param elem | |
*/ | |
getHeight: function(elem) { | |
var style = getComputedStyle(elem); | |
return cssValueToPixels(style['border-top-width']) + | |
cssValueToPixels(style['border-bottom-width']) + | |
cssValueToPixels(style['padding-top']) + | |
cssValueToPixels(style['padding-bottom']) + | |
cssValueToPixels(style['height']); | |
}, | |
/** | |
* | |
* @param elem | |
*/ | |
getOffset: function(elem) { | |
var offset = {left: 0, top:0}; | |
if (elem.offsetParent) { | |
do { | |
offset.left += elem.offsetLeft; | |
offset.top += elem.offsetTop; | |
} while (elem = elem.offsetParent); | |
} | |
return offset; | |
}, | |
// http://stackoverflow.com/posts/2684561/revisions | |
/** | |
* | |
* @param elem | |
*/ | |
isActive: function(elem) { | |
return elem === document.activeElement && ( elem.type || elem.href ); | |
} | |
}; | |
return dom; | |
})(dat.utils.common); | |
dat.controllers.OptionController = (function (Controller, dom, common) { | |
/** | |
* @class Provides a select input to alter the property of an object, using a | |
* list of accepted values. | |
* | |
* @extends dat.controllers.Controller | |
* | |
* @param {Object} object The object to be manipulated | |
* @param {string} property The name of the property to be manipulated | |
* @param {Object|string[]} options A map of labels to acceptable values, or | |
* a list of acceptable string values. | |
* | |
* @member dat.controllers | |
*/ | |
var OptionController = function(object, property, options) { | |
OptionController.superclass.call(this, object, property); | |
var _this = this; | |
/** | |
* The drop down menu | |
* @ignore | |
*/ | |
this.__select = document.createElement('select'); | |
if (common.isArray(options)) { | |
var map = {}; | |
common.each(options, function(element) { | |
map[element] = element; | |
}); | |
options = map; | |
} | |
common.each(options, function(value, key) { | |
var opt = document.createElement('option'); | |
opt.innerHTML = key; | |
opt.setAttribute('value', value); | |
_this.__select.appendChild(opt); | |
}); | |
// Acknowledge original value | |
this.updateDisplay(); | |
dom.bind(this.__select, 'change', function() { | |
var desiredValue = this.options[this.selectedIndex].value; | |
_this.setValue(desiredValue); | |
}); | |
this.domElement.appendChild(this.__select); | |
}; | |
OptionController.superclass = Controller; | |
common.extend( | |
OptionController.prototype, | |
Controller.prototype, | |
{ | |
setValue: function(v) { | |
var toReturn = OptionController.superclass.prototype.setValue.call(this, v); | |
if (this.__onFinishChange) { | |
this.__onFinishChange.call(this, this.getValue()); | |
} | |
return toReturn; | |
}, | |
updateDisplay: function() { | |
this.__select.value = this.getValue(); | |
return OptionController.superclass.prototype.updateDisplay.call(this); | |
} | |
} | |
); | |
return OptionController; | |
})(dat.controllers.Controller, | |
dat.dom.dom, | |
dat.utils.common); | |
dat.controllers.NumberController = (function (Controller, common) { | |
/** | |
* @class Represents a given property of an object that is a number. | |
* | |
* @extends dat.controllers.Controller | |
* | |
* @param {Object} object The object to be manipulated | |
* @param {string} property The name of the property to be manipulated | |
* @param {Object} [params] Optional parameters | |
* @param {Number} [params.min] Minimum allowed value | |
* @param {Number} [params.max] Maximum allowed value | |
* @param {Number} [params.step] Increment by which to change value | |
* | |
* @member dat.controllers | |
*/ | |
var NumberController = function(object, property, params) { | |
NumberController.superclass.call(this, object, property); | |
params = params || {}; | |
this.__min = params.min; | |
this.__max = params.max; | |
this.__step = params.step; | |
if (common.isUndefined(this.__step)) { | |
if (this.initialValue == 0) { | |
this.__impliedStep = 1; // What are we, psychics? | |
} else { | |
// Hey Doug, check this out. | |
this.__impliedStep = Math.pow(10, Math.floor(Math.log(this.initialValue)/Math.LN10))/10; | |
} | |
} else { | |
this.__impliedStep = this.__step; | |
} | |
this.__precision = numDecimals(this.__impliedStep); | |
}; | |
NumberController.superclass = Controller; | |
common.extend( | |
NumberController.prototype, | |
Controller.prototype, | |
/** @lends dat.controllers.NumberController.prototype */ | |
{ | |
setValue: function(v) { | |
if (this.__min !== undefined && v < this.__min) { | |
v = this.__min; | |
} else if (this.__max !== undefined && v > this.__max) { | |
v = this.__max; | |
} | |
if (this.__step !== undefined && v % this.__step != 0) { | |
v = Math.round(v / this.__step) * this.__step; | |
} | |
return NumberController.superclass.prototype.setValue.call(this, v); | |
}, | |
/** | |
* Specify a minimum value for <code>object[property]</code>. | |
* | |
* @param {Number} minValue The minimum value for | |
* <code>object[property]</code> | |
* @returns {dat.controllers.NumberController} this | |
*/ | |
min: function(v) { | |
this.__min = v; | |
return this; | |
}, | |
/** | |
* Specify a maximum value for <code>object[property]</code>. | |
* | |
* @param {Number} maxValue The maximum value for | |
* <code>object[property]</code> | |
* @returns {dat.controllers.NumberController} this | |
*/ | |
max: function(v) { | |
this.__max = v; | |
return this; | |
}, | |
/** | |
* Specify a step value that dat.controllers.NumberController | |
* increments by. | |
* | |
* @param {Number} stepValue The step value for | |
* dat.controllers.NumberController | |
* @default if minimum and maximum specified increment is 1% of the | |
* difference otherwise stepValue is 1 | |
* @returns {dat.controllers.NumberController} this | |
*/ | |
step: function(v) { | |
this.__step = v; | |
return this; | |
} | |
} | |
); | |
function numDecimals(x) { | |
x = x.toString(); | |
if (x.indexOf('.') > -1) { | |
return x.length - x.indexOf('.') - 1; | |
} else { | |
return 0; | |
} | |
} | |
return NumberController; | |
})(dat.controllers.Controller, | |
dat.utils.common); | |
dat.controllers.NumberControllerBox = (function (NumberController, dom, common) { | |
/** | |
* @class Represents a given property of an object that is a number and | |
* provides an input element with which to manipulate it. | |
* | |
* @extends dat.controllers.Controller | |
* @extends dat.controllers.NumberController | |
* | |
* @param {Object} object The object to be manipulated | |
* @param {string} property The name of the property to be manipulated | |
* @param {Object} [params] Optional parameters | |
* @param {Number} [params.min] Minimum allowed value | |
* @param {Number} [params.max] Maximum allowed value | |
* @param {Number} [params.step] Increment by which to change value | |
* | |
* @member dat.controllers | |
*/ | |
var NumberControllerBox = function(object, property, params) { | |
this.__truncationSuspended = false; | |
NumberControllerBox.superclass.call(this, object, property, params); | |
var _this = this; | |
/** | |
* {Number} Previous mouse y position | |
* @ignore | |
*/ | |
var prev_y; | |
this.__input = document.createElement('input'); | |
this.__input.setAttribute('type', 'text'); | |
// Makes it so manually specified values are not truncated. | |
dom.bind(this.__input, 'change', onChange); | |
dom.bind(this.__input, 'blur', onBlur); | |
dom.bind(this.__input, 'mousedown', onMouseDown); | |
dom.bind(this.__input, 'keydown', function(e) { | |
// When pressing entire, you can be as precise as you want. | |
if (e.keyCode === 13) { | |
_this.__truncationSuspended = true; | |
this.blur(); | |
_this.__truncationSuspended = false; | |
} | |
}); | |
function onChange() { | |
var attempted = parseFloat(_this.__input.value); | |
if (!common.isNaN(attempted)) _this.setValue(attempted); | |
} | |
function onBlur() { | |
onChange(); | |
if (_this.__onFinishChange) { | |
_this.__onFinishChange.call(_this, _this.getValue()); | |
} | |
} | |
function onMouseDown(e) { | |
dom.bind(window, 'mousemove', onMouseDrag); | |
dom.bind(window, 'mouseup', onMouseUp); | |
prev_y = e.clientY; | |
} | |
function onMouseDrag(e) { | |
var diff = prev_y - e.clientY; | |
_this.setValue(_this.getValue() + diff * _this.__impliedStep); | |
prev_y = e.clientY; | |
} | |
function onMouseUp() { | |
dom.unbind(window, 'mousemove', onMouseDrag); | |
dom.unbind(window, 'mouseup', onMouseUp); | |
} | |
this.updateDisplay(); | |
this.domElement.appendChild(this.__input); | |
}; | |
NumberControllerBox.superclass = NumberController; | |
common.extend( | |
NumberControllerBox.prototype, | |
NumberController.prototype, | |
{ | |
updateDisplay: function() { | |
this.__input.value = this.__truncationSuspended ? this.getValue() : roundToDecimal(this.getValue(), this.__precision); | |
return NumberControllerBox.superclass.prototype.updateDisplay.call(this); | |
} | |
} | |
); | |
function roundToDecimal(value, decimals) { | |
var tenTo = Math.pow(10, decimals); | |
return Math.round(value * tenTo) / tenTo; | |
} | |
return NumberControllerBox; | |
})(dat.controllers.NumberController, | |
dat.dom.dom, | |
dat.utils.common); | |
dat.controllers.NumberControllerSlider = (function (NumberController, dom, css, common, styleSheet) { | |
/** | |
* @class Represents a given property of an object that is a number, contains | |
* a minimum and maximum, and provides a slider element with which to | |
* manipulate it. It should be noted that the slider element is made up of | |
* <code><div></code> tags, <strong>not</strong> the html5 | |
* <code><slider></code> element. | |
* | |
* @extends dat.controllers.Controller | |
* @extends dat.controllers.NumberController | |
* | |
* @param {Object} object The object to be manipulated | |
* @param {string} property The name of the property to be manipulated | |
* @param {Number} minValue Minimum allowed value | |
* @param {Number} maxValue Maximum allowed value | |
* @param {Number} stepValue Increment by which to change value | |
* | |
* @member dat.controllers | |
*/ | |
var NumberControllerSlider = function(object, property, min, max, step) { | |
NumberControllerSlider.superclass.call(this, object, property, { min: min, max: max, step: step }); | |
var _this = this; | |
this.__background = document.createElement('div'); | |
this.__foreground = document.createElement('div'); | |
dom.bind(this.__background, 'mousedown', onMouseDown); | |
dom.addClass(this.__background, 'slider'); | |
dom.addClass(this.__foreground, 'slider-fg'); | |
function onMouseDown(e) { | |
dom.bind(window, 'mousemove', onMouseDrag); | |
dom.bind(window, 'mouseup', onMouseUp); | |
onMouseDrag(e); | |
} | |
function onMouseDrag(e) { | |
e.preventDefault(); | |
var offset = dom.getOffset(_this.__background); | |
var width = dom.getWidth(_this.__background); | |
_this.setValue( | |
map(e.clientX, offset.left, offset.left + width, _this.__min, _this.__max) | |
); | |
return false; | |
} | |
function onMouseUp() { | |
dom.unbind(window, 'mousemove', onMouseDrag); | |
dom.unbind(window, 'mouseup', onMouseUp); | |
if (_this.__onFinishChange) { | |
_this.__onFinishChange.call(_this, _this.getValue()); | |
} | |
} | |
this.updateDisplay(); | |
this.__background.appendChild(this.__foreground); | |
this.domElement.appendChild(this.__background); | |
}; | |
NumberControllerSlider.superclass = NumberController; | |
/** | |
* Injects default stylesheet for slider elements. | |
*/ | |
NumberControllerSlider.useDefaultStyles = function() { | |
css.inject(styleSheet); | |
}; | |
common.extend( | |
NumberControllerSlider.prototype, | |
NumberController.prototype, | |
{ | |
updateDisplay: function() { | |
var pct = (this.getValue() - this.__min)/(this.__max - this.__min); | |
this.__foreground.style.width = pct*100+'%'; | |
return NumberControllerSlider.superclass.prototype.updateDisplay.call(this); | |
} | |
} | |
); | |
function map(v, i1, i2, o1, o2) { | |
return o1 + (o2 - o1) * ((v - i1) / (i2 - i1)); | |
} | |
return NumberControllerSlider; | |
})(dat.controllers.NumberController, | |
dat.dom.dom, | |
dat.utils.css, | |
dat.utils.common, | |
".slider {\n box-shadow: inset 0 2px 4px rgba(0,0,0,0.15);\n height: 1em;\n border-radius: 1em;\n background-color: #eee;\n padding: 0 0.5em;\n overflow: hidden;\n}\n\n.slider-fg {\n padding: 1px 0 2px 0;\n background-color: #aaa;\n height: 1em;\n margin-left: -0.5em;\n padding-right: 0.5em;\n border-radius: 1em 0 0 1em;\n}\n\n.slider-fg:after {\n display: inline-block;\n border-radius: 1em;\n background-color: #fff;\n border: 1px solid #aaa;\n content: '';\n float: right;\n margin-right: -1em;\n margin-top: -1px;\n height: 0.9em;\n width: 0.9em;\n}"); | |
dat.controllers.FunctionController = (function (Controller, dom, common) { | |
/** | |
* @class Provides a GUI interface to fire a specified method, a property of an object. | |
* | |
* @extends dat.controllers.Controller | |
* | |
* @param {Object} object The object to be manipulated | |
* @param {string} property The name of the property to be manipulated | |
* | |
* @member dat.controllers | |
*/ | |
var FunctionController = function(object, property, text) { | |
FunctionController.superclass.call(this, object, property); | |
var _this = this; | |
this.__button = document.createElement('div'); | |
this.__button.innerHTML = text === undefined ? 'Fire' : text; | |
dom.bind(this.__button, 'click', function(e) { | |
e.preventDefault(); | |
_this.fire(); | |
return false; | |
}); | |
dom.addClass(this.__button, 'button'); | |
this.domElement.appendChild(this.__button); | |
}; | |
FunctionController.superclass = Controller; | |
common.extend( | |
FunctionController.prototype, | |
Controller.prototype, | |
{ | |
fire: function() { | |
if (this.__onChange) { | |
this.__onChange.call(this); | |
} | |
if (this.__onFinishChange) { | |
this.__onFinishChange.call(this, this.getValue()); | |
} | |
this.getValue().call(this.object); | |
} | |
} | |
); | |
return FunctionController; | |
})(dat.controllers.Controller, | |
dat.dom.dom, | |
dat.utils.common); | |
dat.controllers.BooleanController = (function (Controller, dom, common) { | |
/** | |
* @class Provides a checkbox input to alter the boolean property of an object. | |
* @extends dat.controllers.Controller | |
* | |
* @param {Object} object The object to be manipulated | |
* @param {string} property The name of the property to be manipulated | |
* | |
* @member dat.controllers | |
*/ | |
var BooleanController = function(object, property) { | |
BooleanController.superclass.call(this, object, property); | |
var _this = this; | |
this.__prev = this.getValue(); | |
this.__checkbox = document.createElement('input'); | |
this.__checkbox.setAttribute('type', 'checkbox'); | |
dom.bind(this.__checkbox, 'change', onChange, false); | |
this.domElement.appendChild(this.__checkbox); | |
// Match original value | |
this.updateDisplay(); | |
function onChange() { | |
_this.setValue(!_this.__prev); | |
} | |
}; | |
BooleanController.superclass = Controller; | |
common.extend( | |
BooleanController.prototype, | |
Controller.prototype, | |
{ | |
setValue: function(v) { | |
var toReturn = BooleanController.superclass.prototype.setValue.call(this, v); | |
if (this.__onFinishChange) { | |
this.__onFinishChange.call(this, this.getValue()); | |
} | |
this.__prev = this.getValue(); | |
return toReturn; | |
}, | |
updateDisplay: function() { | |
if (this.getValue() === true) { | |
this.__checkbox.setAttribute('checked', 'checked'); | |
this.__checkbox.checked = true; | |
} else { | |
this.__checkbox.checked = false; | |
} | |
return BooleanController.superclass.prototype.updateDisplay.call(this); | |
} | |
} | |
); | |
return BooleanController; | |
})(dat.controllers.Controller, | |
dat.dom.dom, | |
dat.utils.common); | |
dat.color.toString = (function (common) { | |
return function(color) { | |
if (color.a == 1 || common.isUndefined(color.a)) { | |
var s = color.hex.toString(16); | |
while (s.length < 6) { | |
s = '0' + s; | |
} | |
return '#' + s; | |
} else { | |
return 'rgba(' + Math.round(color.r) + ',' + Math.round(color.g) + ',' + Math.round(color.b) + ',' + color.a + ')'; | |
} | |
} | |
})(dat.utils.common); | |
dat.color.interpret = (function (toString, common) { | |
var result, toReturn; | |
var interpret = function() { | |
toReturn = false; | |
var original = arguments.length > 1 ? common.toArray(arguments) : arguments[0]; | |
common.each(INTERPRETATIONS, function(family) { | |
if (family.litmus(original)) { | |
common.each(family.conversions, function(conversion, conversionName) { | |
result = conversion.read(original); | |
if (toReturn === false && result !== false) { | |
toReturn = result; | |
result.conversionName = conversionName; | |
result.conversion = conversion; | |
return common.BREAK; | |
} | |
}); | |
return common.BREAK; | |
} | |
}); | |
return toReturn; | |
}; | |
var INTERPRETATIONS = [ | |
// Strings | |
{ | |
litmus: common.isString, | |
conversions: { | |
THREE_CHAR_HEX: { | |
read: function(original) { | |
var test = original.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i); | |
if (test === null) return false; | |
return { | |
space: 'HEX', | |
hex: parseInt( | |
'0x' + | |
test[1].toString() + test[1].toString() + | |
test[2].toString() + test[2].toString() + | |
test[3].toString() + test[3].toString()) | |
}; | |
}, | |
write: toString | |
}, | |
SIX_CHAR_HEX: { | |
read: function(original) { | |
var test = original.match(/^#([A-F0-9]{6})$/i); | |
if (test === null) return false; | |
return { | |
space: 'HEX', | |
hex: parseInt('0x' + test[1].toString()) | |
}; | |
}, | |
write: toString | |
}, | |
CSS_RGB: { | |
read: function(original) { | |
var test = original.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/); | |
if (test === null) return false; | |
return { | |
space: 'RGB', | |
r: parseFloat(test[1]), | |
g: parseFloat(test[2]), | |
b: parseFloat(test[3]) | |
}; | |
}, | |
write: toString | |
}, | |
CSS_RGBA: { | |
read: function(original) { | |
var test = original.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\,\s*(.+)\s*\)/); | |
if (test === null) return false; | |
return { | |
space: 'RGB', | |
r: parseFloat(test[1]), | |
g: parseFloat(test[2]), | |
b: parseFloat(test[3]), | |
a: parseFloat(test[4]) | |
}; | |
}, | |
write: toString | |
} | |
} | |
}, | |
// Numbers | |
{ | |
litmus: common.isNumber, | |
conversions: { | |
HEX: { | |
read: function(original) { | |
return { | |
space: 'HEX', | |
hex: original, | |
conversionName: 'HEX' | |
} | |
}, | |
write: function(color) { | |
return color.hex; | |
} | |
} | |
} | |
}, | |
// Arrays | |
{ | |
litmus: common.isArray, | |
conversions: { | |
RGB_ARRAY: { | |
read: function(original) { | |
if (original.length != 3) return false; | |
return { | |
space: 'RGB', | |
r: original[0], | |
g: original[1], | |
b: original[2] | |
}; | |
}, | |
write: function(color) { | |
return [color.r, color.g, color.b]; | |
} | |
}, | |
RGBA_ARRAY: { | |
read: function(original) { | |
if (original.length != 4) return false; | |
return { | |
space: 'RGB', | |
r: original[0], | |
g: original[1], | |
b: original[2], | |
a: original[3] | |
}; | |
}, | |
write: function(color) { | |
return [color.r, color.g, color.b, color.a]; | |
} | |
} | |
} | |
}, | |
// Objects | |
{ | |
litmus: common.isObject, | |
conversions: { | |
RGBA_OBJ: { | |
read: function(original) { | |
if (common.isNumber(original.r) && | |
common.isNumber(original.g) && | |
common.isNumber(original.b) && | |
common.isNumber(original.a)) { | |
return { | |
space: 'RGB', | |
r: original.r, | |
g: original.g, | |
b: original.b, | |
a: original.a | |
} | |
} | |
return false; | |
}, | |
write: function(color) { | |
return { | |
r: color.r, | |
g: color.g, | |
b: color.b, | |
a: color.a | |
} | |
} | |
}, | |
RGB_OBJ: { | |
read: function(original) { | |
if (common.isNumber(original.r) && | |
common.isNumber(original.g) && | |
common.isNumber(original.b)) { | |
return { | |
space: 'RGB', | |
r: original.r, | |
g: original.g, | |
b: original.b | |
} | |
} | |
return false; | |
}, | |
write: function(color) { | |
return { | |
r: color.r, | |
g: color.g, | |
b: color.b | |
} | |
} | |
}, | |
HSVA_OBJ: { | |
read: function(original) { | |
if (common.isNumber(original.h) && | |
common.isNumber(original.s) && | |
common.isNumber(original.v) && | |
common.isNumber(original.a)) { | |
return { | |
space: 'HSV', | |
h: original.h, | |
s: original.s, | |
v: original.v, | |
a: original.a | |
} | |
} | |
return false; | |
}, | |
write: function(color) { | |
return { | |
h: color.h, | |
s: color.s, | |
v: color.v, | |
a: color.a | |
} | |
} | |
}, | |
HSV_OBJ: { | |
read: function(original) { | |
if (common.isNumber(original.h) && | |
common.isNumber(original.s) && | |
common.isNumber(original.v)) { | |
return { | |
space: 'HSV', | |
h: original.h, | |
s: original.s, | |
v: original.v | |
} | |
} | |
return false; | |
}, | |
write: function(color) { | |
return { | |
h: color.h, | |
s: color.s, | |
v: color.v | |
} | |
} | |
} | |
} | |
} | |
]; | |
return interpret; | |
})(dat.color.toString, | |
dat.utils.common); | |
dat.GUI = dat.gui.GUI = (function (css, saveDialogueContents, styleSheet, controllerFactory, Controller, BooleanController, FunctionController, NumberControllerBox, NumberControllerSlider, OptionController, ColorController, requestAnimationFrame, CenteredDiv, dom, common) { | |
css.inject(styleSheet); | |
/** Outer-most className for GUI's */ | |
var CSS_NAMESPACE = 'dg'; | |
var HIDE_KEY_CODE = 72; | |
/** The only value shared between the JS and SCSS. Use caution. */ | |
var CLOSE_BUTTON_HEIGHT = 20; | |
var DEFAULT_DEFAULT_PRESET_NAME = 'Default'; | |
var SUPPORTS_LOCAL_STORAGE = (function() { | |
try { | |
return 'localStorage' in window && window['localStorage'] !== null; | |
} catch (e) { | |
return false; | |
} | |
})(); | |
var SAVE_DIALOGUE; | |
/** Have we yet to create an autoPlace GUI? */ | |
var auto_place_virgin = true; | |
/** Fixed position div that auto place GUI's go inside */ | |
var auto_place_container; | |
/** Are we hiding the GUI's ? */ | |
var hide = false; | |
/** GUI's which should be hidden */ | |
var hideable_guis = []; | |
/** | |
* A lightweight controller library for JavaScript. It allows you to easily | |
* manipulate variables and fire functions on the fly. | |
* @class | |
* | |
* @member dat.gui | |
* | |
* @param {Object} [params] | |
* @param {String} [params.name] The name of this GUI. | |
* @param {Object} [params.load] JSON object representing the saved state of | |
* this GUI. | |
* @param {Boolean} [params.auto=true] | |
* @param {dat.gui.GUI} [params.parent] The GUI I'm nested in. | |
* @param {Boolean} [params.closed] If true, starts closed | |
*/ | |
var GUI = function(params) { | |
var _this = this; | |
/** | |
* Outermost DOM Element | |
* @type DOMElement | |
*/ | |
this.domElement = document.createElement('div'); | |
this.__ul = document.createElement('ul'); | |
this.domElement.appendChild(this.__ul); | |
dom.addClass(this.domElement, CSS_NAMESPACE); | |
/** | |
* Nested GUI's by name | |
* @ignore | |
*/ | |
this.__folders = {}; | |
this.__controllers = []; | |
/** | |
* List of objects I'm remembering for save, only used in top level GUI | |
* @ignore | |
*/ | |
this.__rememberedObjects = []; | |
/** | |
* Maps the index of remembered objects to a map of controllers, only used | |
* in top level GUI. | |
* | |
* @private | |
* @ignore | |
* | |
* @example | |
* [ | |
* { | |
* propertyName: Controller, | |
* anotherPropertyName: Controller | |
* }, | |
* { | |
* propertyName: Controller | |
* } | |
* ] | |
*/ | |
this.__rememberedObjectIndecesToControllers = []; | |
this.__listening = []; | |
params = params || {}; | |
// Default parameters | |
params = common.defaults(params, { | |
autoPlace: true, | |
width: GUI.DEFAULT_WIDTH | |
}); | |
params = common.defaults(params, { | |
resizable: params.autoPlace, | |
hideable: params.autoPlace | |
}); | |
if (!common.isUndefined(params.load)) { | |
// Explicit preset | |
if (params.preset) params.load.preset = params.preset; | |
} else { | |
params.load = { preset: DEFAULT_DEFAULT_PRESET_NAME }; | |
} | |
if (common.isUndefined(params.parent) && params.hideable) { | |
hideable_guis.push(this); | |
} | |
// Only root level GUI's are resizable. | |
params.resizable = common.isUndefined(params.parent) && params.resizable; | |
if (params.autoPlace && common.isUndefined(params.scrollable)) { | |
params.scrollable = true; | |
} | |
// params.scrollable = common.isUndefined(params.parent) && params.scrollable === true; | |
// Not part of params because I don't want people passing this in via | |
// constructor. Should be a 'remembered' value. | |
var use_local_storage = | |
SUPPORTS_LOCAL_STORAGE && | |
localStorage.getItem(getLocalStorageHash(this, 'isLocal')) === 'true'; | |
Object.defineProperties(this, | |
/** @lends dat.gui.GUI.prototype */ | |
{ | |
/** | |
* The parent <code>GUI</code> | |
* @type dat.gui.GUI | |
*/ | |
parent: { | |
get: function() { | |
return params.parent; | |
} | |
}, | |
scrollable: { | |
get: function() { | |
return params.scrollable; | |
} | |
}, | |
/** | |
* Handles <code>GUI</code>'s element placement for you | |
* @type Boolean | |
*/ | |
autoPlace: { | |
get: function() { | |
return params.autoPlace; | |
} | |
}, | |
/** | |
* The identifier for a set of saved values | |
* @type String | |
*/ | |
preset: { | |
get: function() { | |
if (_this.parent) { | |
return _this.getRoot().preset; | |
} else { | |
return params.load.preset; | |
} | |
}, | |
set: function(v) { | |
if (_this.parent) { | |
_this.getRoot().preset = v; | |
} else { | |
params.load.preset = v; | |
} | |
setPresetSelectIndex(this); | |
_this.revert(); | |
} | |
}, | |
/** | |
* The width of <code>GUI</code> element | |
* @type Number | |
*/ | |
width: { | |
get: function() { | |
return params.width; | |
}, | |
set: function(v) { | |
params.width = v; | |
setWidth(_this, v); | |
} | |
}, | |
/** | |
* The name of <code>GUI</code>. Used for folders. i.e | |
* a folder's name | |
* @type String | |
*/ | |
name: { | |
get: function() { | |
return params.name; | |
}, | |
set: function(v) { | |
// TODO Check for collisions among sibling folders | |
params.name = v; | |
if (title_row_name) { | |
title_row_name.innerHTML = params.name; | |
} | |
} | |
}, | |
/** | |
* Whether the <code>GUI</code> is collapsed or not | |
* @type Boolean | |
*/ | |
closed: { | |
get: function() { | |
return params.closed; | |
}, | |
set: function(v) { | |
params.closed = v; | |
if (params.closed) { | |
dom.addClass(_this.__ul, GUI.CLASS_CLOSED); | |
} else { | |
dom.removeClass(_this.__ul, GUI.CLASS_CLOSED); | |
} | |
// For browsers that aren't going to respect the CSS transition, | |
// Lets just check our height against the window height right off | |
// the bat. | |
this.onResize(); | |
if (_this.__closeButton) { | |
_this.__closeButton.innerHTML = v ? GUI.TEXT_OPEN : GUI.TEXT_CLOSED; | |
} | |
} | |
}, | |
/** | |
* Contains all presets | |
* @type Object | |
*/ | |
load: { | |
get: function() { | |
return params.load; | |
} | |
}, | |
/** | |
* Determines whether or not to use <a href="https://developer.mozilla.org/en/DOM/Storage#localStorage">localStorage</a> as the means for | |
* <code>remember</code>ing | |
* @type Boolean | |
*/ | |
useLocalStorage: { | |
get: function() { | |
return use_local_storage; | |
}, | |
set: function(bool) { | |
if (SUPPORTS_LOCAL_STORAGE) { | |
use_local_storage = bool; | |
if (bool) { | |
dom.bind(window, 'unload', saveToLocalStorage); | |
} else { | |
dom.unbind(window, 'unload', saveToLocalStorage); | |
} | |
localStorage.setItem(getLocalStorageHash(_this, 'isLocal'), bool); | |
} | |
} | |
} | |
}); | |
// Are we a root level GUI? | |
if (common.isUndefined(params.parent)) { | |
params.closed = false; | |
dom.addClass(this.domElement, GUI.CLASS_MAIN); | |
dom.makeSelectable(this.domElement, false); | |
// Are we supposed to be loading locally? | |
if (SUPPORTS_LOCAL_STORAGE) { | |
if (use_local_storage) { | |
_this.useLocalStorage = true; | |
var saved_gui = localStorage.getItem(getLocalStorageHash(this, 'gui')); | |
if (saved_gui) { | |
params.load = JSON.parse(saved_gui); | |
} | |
} | |
} | |
this.__closeButton = document.createElement('div'); | |
this.__closeButton.innerHTML = GUI.TEXT_CLOSED; | |
dom.addClass(this.__closeButton, GUI.CLASS_CLOSE_BUTTON); | |
this.domElement.appendChild(this.__closeButton); | |
dom.bind(this.__closeButton, 'click', function() { | |
_this.closed = !_this.closed; | |
}); | |
// Oh, you're a nested GUI! | |
} else { | |
if (params.closed === undefined) { | |
params.closed = true; | |
} | |
var title_row_name = document.createTextNode(params.name); | |
dom.addClass(title_row_name, 'controller-name'); | |
var title_row = addRow(_this, title_row_name); | |
var on_click_title = function(e) { | |
e.preventDefault(); | |
_this.closed = !_this.closed; | |
return false; | |
}; | |
dom.addClass(this.__ul, GUI.CLASS_CLOSED); | |
dom.addClass(title_row, 'title'); | |
dom.bind(title_row, 'click', on_click_title); | |
if (!params.closed) { | |
this.closed = false; | |
} | |
} | |
if (params.autoPlace) { | |
if (common.isUndefined(params.parent)) { | |
if (auto_place_virgin) { | |
auto_place_container = document.createElement('div'); | |
dom.addClass(auto_place_container, CSS_NAMESPACE); | |
dom.addClass(auto_place_container, GUI.CLASS_AUTO_PLACE_CONTAINER); | |
document.body.appendChild(auto_place_container); | |
auto_place_virgin = false; | |
} | |
// Put it in the dom for you. | |
auto_place_container.appendChild(this.domElement); | |
// Apply the auto styles | |
dom.addClass(this.domElement, GUI.CLASS_AUTO_PLACE); | |
} | |
// Make it not elastic. | |
if (!this.parent) setWidth(_this, params.width); | |
} | |
dom.bind(window, 'resize', function() { _this.onResize() }); | |
dom.bind(this.__ul, 'webkitTransitionEnd', function() { _this.onResize(); }); | |
dom.bind(this.__ul, 'transitionend', function() { _this.onResize() }); | |
dom.bind(this.__ul, 'oTransitionEnd', function() { _this.onResize() }); | |
this.onResize(); | |
if (params.resizable) { | |
addResizeHandle(this); | |
} | |
function saveToLocalStorage() { | |
localStorage.setItem(getLocalStorageHash(_this, 'gui'), JSON.stringify(_this.getSaveObject())); | |
} | |
var root = _this.getRoot(); | |
function resetWidth() { | |
var root = _this.getRoot(); | |
root.width += 1; | |
common.defer(function() { | |
root.width -= 1; | |
}); | |
} | |
if (!params.parent) { | |
resetWidth(); | |
} | |
}; | |
GUI.toggleHide = function() { | |
hide = !hide; | |
common.each(hideable_guis, function(gui) { | |
gui.domElement.style.zIndex = hide ? -999 : 999; | |
gui.domElement.style.opacity = hide ? 0 : 1; | |
}); | |
}; | |
GUI.CLASS_AUTO_PLACE = 'a'; | |
GUI.CLASS_AUTO_PLACE_CONTAINER = 'ac'; | |
GUI.CLASS_MAIN = 'main'; | |
GUI.CLASS_CONTROLLER_ROW = 'cr'; | |
GUI.CLASS_TOO_TALL = 'taller-than-window'; | |
GUI.CLASS_CLOSED = 'closed'; | |
GUI.CLASS_CLOSE_BUTTON = 'close-button'; | |
GUI.CLASS_DRAG = 'drag'; | |
GUI.DEFAULT_WIDTH = 245; | |
GUI.TEXT_CLOSED = 'Close Controls'; | |
GUI.TEXT_OPEN = 'Open Controls'; | |
dom.bind(window, 'keydown', function(e) { | |
if (document.activeElement.type !== 'text' && | |
(e.which === HIDE_KEY_CODE || e.keyCode == HIDE_KEY_CODE)) { | |
GUI.toggleHide(); | |
} | |
}, false); | |
common.extend( | |
GUI.prototype, | |
/** @lends dat.gui.GUI */ | |
{ | |
/** | |
* @param object | |
* @param property | |
* @returns {dat.controllers.Controller} The new controller that was added. | |
* @instance | |
*/ | |
add: function(object, property) { | |
return add( | |
this, | |
object, | |
property, | |
{ | |
factoryArgs: Array.prototype.slice.call(arguments, 2) | |
} | |
); | |
}, | |
/** | |
* @param object | |
* @param property | |
* @returns {dat.controllers.ColorController} The new controller that was added. | |
* @instance | |
*/ | |
addColor: function(object, property) { | |
return add( | |
this, | |
object, | |
property, | |
{ | |
color: true | |
} | |
); | |
}, | |
/** | |
* @param controller | |
* @instance | |
*/ | |
remove: function(controller) { | |
// TODO listening? | |
this.__ul.removeChild(controller.__li); | |
this.__controllers.slice(this.__controllers.indexOf(controller), 1); | |
var _this = this; | |
common.defer(function() { | |
_this.onResize(); | |
}); | |
}, | |
destroy: function() { | |
if (this.autoPlace) { | |
auto_place_container.removeChild(this.domElement); | |
} | |
}, | |
/** | |
* @param name | |
* @returns {dat.gui.GUI} The new folder. | |
* @throws {Error} if this GUI already has a folder by the specified | |
* name | |
* @instance | |
*/ | |
addFolder: function(name) { | |
// We have to prevent collisions on names in order to have a key | |
// by which to remember saved values | |
if (this.__folders[name] !== undefined) { | |
throw new Error('You already have a folder in this GUI by the' + | |
' name "' + name + '"'); | |
} | |
var new_gui_params = { name: name, parent: this }; | |
// We need to pass down the autoPlace trait so that we can | |
// attach event listeners to open/close folder actions to | |
// ensure that a scrollbar appears if the window is too short. | |
new_gui_params.autoPlace = this.autoPlace; | |
// Do we have saved appearance data for this folder? | |
if (this.load && // Anything loaded? | |
this.load.folders && // Was my parent a dead-end? | |
this.load.folders[name]) { // Did daddy remember me? | |
// Start me closed if I was closed | |
new_gui_params.closed = this.load.folders[name].closed; | |
// Pass down the loaded data | |
new_gui_params.load = this.load.folders[name]; | |
} | |
var gui = new GUI(new_gui_params); | |
this.__folders[name] = gui; | |
var li = addRow(this, gui.domElement); | |
dom.addClass(li, 'folder'); | |
return gui; | |
}, | |
open: function() { | |
this.closed = false; | |
}, | |
close: function() { | |
this.closed = true; | |
}, | |
onResize: function() { | |
var root = this.getRoot(); | |
if (root.scrollable) { | |
var top = dom.getOffset(root.__ul).top; | |
var h = 0; | |
common.each(root.__ul.childNodes, function(node) { | |
if (! (root.autoPlace && node === root.__save_row)) | |
h += dom.getHeight(node); | |
}); | |
if (window.innerHeight - top - CLOSE_BUTTON_HEIGHT < h) { | |
dom.addClass(root.domElement, GUI.CLASS_TOO_TALL); | |
root.__ul.style.height = window.innerHeight - top - CLOSE_BUTTON_HEIGHT + 'px'; | |
} else { | |
dom.removeClass(root.domElement, GUI.CLASS_TOO_TALL); | |
root.__ul.style.height = 'auto'; | |
} | |
} | |
if (root.__resize_handle) { | |
common.defer(function() { | |
root.__resize_handle.style.height = root.__ul.offsetHeight + 'px'; | |
}); | |
} | |
if (root.__closeButton) { | |
root.__closeButton.style.width = root.width + 'px'; | |
} | |
}, | |
/** | |
* Mark objects for saving. The order of these objects cannot change as | |
* the GUI grows. When remembering new objects, append them to the end | |
* of the list. | |
* | |
* @param {Object...} objects | |
* @throws {Error} if not called on a top level GUI. | |
* @instance | |
*/ | |
remember: function() { | |
if (common.isUndefined(SAVE_DIALOGUE)) { | |
SAVE_DIALOGUE = new CenteredDiv(); | |
SAVE_DIALOGUE.domElement.innerHTML = saveDialogueContents; | |
} | |
if (this.parent) { | |
throw new Error("You can only call remember on a top level GUI."); | |
} | |
var _this = this; | |
common.each(Array.prototype.slice.call(arguments), function(object) { | |
if (_this.__rememberedObjects.length == 0) { | |
addSaveMenu(_this); | |
} | |
if (_this.__rememberedObjects.indexOf(object) == -1) { | |
_this.__rememberedObjects.push(object); | |
} | |
}); | |
if (this.autoPlace) { | |
// Set save row width | |
setWidth(this, this.width); | |
} | |
}, | |
/** | |
* @returns {dat.gui.GUI} the topmost parent GUI of a nested GUI. | |
* @instance | |
*/ | |
getRoot: function() { | |
var gui = this; | |
while (gui.parent) { | |
gui = gui.parent; | |
} | |
return gui; | |
}, | |
/** | |
* @returns {Object} a JSON object representing the current state of | |
* this GUI as well as its remembered properties. | |
* @instance | |
*/ | |
getSaveObject: function() { | |
var toReturn = this.load; | |
toReturn.closed = this.closed; | |
// Am I remembering any values? | |
if (this.__rememberedObjects.length > 0) { | |
toReturn.preset = this.preset; | |
if (!toReturn.remembered) { | |
toReturn.remembered = {}; | |
} | |
toReturn.remembered[this.preset] = getCurrentPreset(this); | |
} | |
toReturn.folders = {}; | |
common.each(this.__folders, function(element, key) { | |
toReturn.folders[key] = element.getSaveObject(); | |
}); | |
return toReturn; | |
}, | |
save: function() { | |
if (!this.load.remembered) { | |
this.load.remembered = {}; | |
} | |
this.load.remembered[this.preset] = getCurrentPreset(this); | |
markPresetModified(this, false); | |
}, | |
saveAs: function(presetName) { | |
if (!this.load.remembered) { | |
// Retain default values upon first save | |
this.load.remembered = {}; | |
this.load.remembered[DEFAULT_DEFAULT_PRESET_NAME] = getCurrentPreset(this, true); | |
} | |
this.load.remembered[presetName] = getCurrentPreset(this); | |
this.preset = presetName; | |
addPresetOption(this, presetName, true); | |
}, | |
revert: function(gui) { | |
common.each(this.__controllers, function(controller) { | |
// Make revert work on Default. | |
if (!this.getRoot().load.remembered) { | |
controller.setValue(controller.initialValue); | |
} else { | |
recallSavedValue(gui || this.getRoot(), controller); | |
} | |
}, this); | |
common.each(this.__folders, function(folder) { | |
folder.revert(folder); | |
}); | |
if (!gui) { | |
markPresetModified(this.getRoot(), false); | |
} | |
}, | |
listen: function(controller) { | |
var init = this.__listening.length == 0; | |
this.__listening.push(controller); | |
if (init) updateDisplays(this.__listening); | |
} | |
} | |
); | |
function add(gui, object, property, params) { | |
if (object[property] === undefined) { | |
throw new Error("Object " + object + " has no property \"" + property + "\""); | |
} | |
var controller; | |
if (params.color) { | |
controller = new ColorController(object, property); | |
} else { | |
var factoryArgs = [object,property].concat(params.factoryArgs); | |
controller = controllerFactory.apply(gui, factoryArgs); | |
} | |
if (params.before instanceof Controller) { | |
params.before = params.before.__li; | |
} | |
recallSavedValue(gui, controller); | |
dom.addClass(controller.domElement, 'c'); | |
var name = document.createElement('span'); | |
dom.addClass(name, 'property-name'); | |
name.innerHTML = controller.property; | |
var container = document.createElement('div'); | |
container.appendChild(name); | |
container.appendChild(controller.domElement); | |
var li = addRow(gui, container, params.before); | |
dom.addClass(li, GUI.CLASS_CONTROLLER_ROW); | |
dom.addClass(li, typeof controller.getValue()); | |
augmentController(gui, li, controller); | |
gui.__controllers.push(controller); | |
return controller; | |
} | |
/** | |
* Add a row to the end of the GUI or before another row. | |
* | |
* @param gui | |
* @param [dom] If specified, inserts the dom content in the new row | |
* @param [liBefore] If specified, places the new row before another row | |
*/ | |
function addRow(gui, dom, liBefore) { | |
var li = document.createElement('li'); | |
if (dom) li.appendChild(dom); | |
if (liBefore) { | |
gui.__ul.insertBefore(li, params.before); | |
} else { | |
gui.__ul.appendChild(li); | |
} | |
gui.onResize(); | |
return li; | |
} | |
function augmentController(gui, li, controller) { | |
controller.__li = li; | |
controller.__gui = gui; | |
common.extend(controller, { | |
options: function(options) { | |
if (arguments.length > 1) { | |
controller.remove(); | |
return add( | |
gui, | |
controller.object, | |
controller.property, | |
{ | |
before: controller.__li.nextElementSibling, | |
factoryArgs: [common.toArray(arguments)] | |
} | |
); | |
} | |
if (common.isArray(options) || common.isObject(options)) { | |
controller.remove(); | |
return add( | |
gui, | |
controller.object, | |
controller.property, | |
{ | |
before: controller.__li.nextElementSibling, | |
factoryArgs: [options] | |
} | |
); | |
} | |
}, | |
name: function(v) { | |
controller.__li.firstElementChild.firstElementChild.innerHTML = v; | |
return controller; | |
}, | |
listen: function() { | |
controller.__gui.listen(controller); | |
return controller; | |
}, | |
remove: function() { | |
controller.__gui.remove(controller); | |
return controller; | |
} | |
}); | |
// All sliders should be accompanied by a box. | |
if (controller instanceof NumberControllerSlider) { | |
var box = new NumberControllerBox(controller.object, controller.property, | |
{ min: controller.__min, max: controller.__max, step: controller.__step }); | |
common.each(['updateDisplay', 'onChange', 'onFinishChange'], function(method) { | |
var pc = controller[method]; | |
var pb = box[method]; | |
controller[method] = box[method] = function() { | |
var args = Array.prototype.slice.call(arguments); | |
pc.apply(controller, args); | |
return pb.apply(box, args); | |
} | |
}); | |
dom.addClass(li, 'has-slider'); | |
controller.domElement.insertBefore(box.domElement, controller.domElement.firstElementChild); | |
} | |
else if (controller instanceof NumberControllerBox) { | |
var r = function(returned) { | |
// Have we defined both boundaries? | |
if (common.isNumber(controller.__min) && common.isNumber(controller.__max)) { | |
// Well, then lets just replace this with a slider. | |
controller.remove(); | |
return add( | |
gui, | |
controller.object, | |
controller.property, | |
{ | |
before: controller.__li.nextElementSibling, | |
factoryArgs: [controller.__min, controller.__max, controller.__step] | |
}); | |
} | |
return returned; | |
}; | |
controller.min = common.compose(r, controller.min); | |
controller.max = common.compose(r, controller.max); | |
} | |
else if (controller instanceof BooleanController) { | |
dom.bind(li, 'click', function() { | |
dom.fakeEvent(controller.__checkbox, 'click'); | |
}); | |
dom.bind(controller.__checkbox, 'click', function(e) { | |
e.stopPropagation(); // Prevents double-toggle | |
}) | |
} | |
else if (controller instanceof FunctionController) { | |
dom.bind(li, 'click', function() { | |
dom.fakeEvent(controller.__button, 'click'); | |
}); | |
dom.bind(li, 'mouseover', function() { | |
dom.addClass(controller.__button, 'hover'); | |
}); | |
dom.bind(li, 'mouseout', function() { | |
dom.removeClass(controller.__button, 'hover'); | |
}); | |
} | |
else if (controller instanceof ColorController) { | |
dom.addClass(li, 'color'); | |
controller.updateDisplay = common.compose(function(r) { | |
li.style.borderLeftColor = controller.__color.toString(); | |
return r; | |
}, controller.updateDisplay); | |
controller.updateDisplay(); | |
} | |
controller.setValue = common.compose(function(r) { | |
if (gui.getRoot().__preset_select && controller.isModified()) { | |
markPresetModified(gui.getRoot(), true); | |
} | |
return r; | |
}, controller.setValue); | |
} | |
function recallSavedValue(gui, controller) { | |
// Find the topmost GUI, that's where remembered objects live. | |
var root = gui.getRoot(); | |
// Does the object we're controlling match anything we've been told to | |
// remember? | |
var matched_index = root.__rememberedObjects.indexOf(controller.object); | |
// Why yes, it does! | |
if (matched_index != -1) { | |
// Let me fetch a map of controllers for thcommon.isObject. | |
var controller_map = | |
root.__rememberedObjectIndecesToControllers[matched_index]; | |
// Ohp, I believe this is the first controller we've created for this | |
// object. Lets make the map fresh. | |
if (controller_map === undefined) { | |
controller_map = {}; | |
root.__rememberedObjectIndecesToControllers[matched_index] = | |
controller_map; | |
} | |
// Keep track of this controller | |
controller_map[controller.property] = controller; | |
// Okay, now have we saved any values for this controller? | |
if (root.load && root.load.remembered) { | |
var preset_map = root.load.remembered; | |
// Which preset are we trying to load? | |
var preset; | |
if (preset_map[gui.preset]) { | |
preset = preset_map[gui.preset]; | |
} else if (preset_map[DEFAULT_DEFAULT_PRESET_NAME]) { | |
// Uhh, you can have the default instead? | |
preset = preset_map[DEFAULT_DEFAULT_PRESET_NAME]; | |
} else { | |
// Nada. | |
return; | |
} | |
// Did the loaded object remember thcommon.isObject? | |
if (preset[matched_index] && | |
// Did we remember this particular property? | |
preset[matched_index][controller.property] !== undefined) { | |
// We did remember something for this guy ... | |
var value = preset[matched_index][controller.property]; | |
// And that's what it is. | |
controller.initialValue = value; | |
controller.setValue(value); | |
} | |
} | |
} | |
} | |
function getLocalStorageHash(gui, key) { | |
// TODO how does this deal with multiple GUI's? | |
return document.location.href + '.' + key; | |
} | |
function addSaveMenu(gui) { | |
var div = gui.__save_row = document.createElement('li'); | |
dom.addClass(gui.domElement, 'has-save'); | |
gui.__ul.insertBefore(div, gui.__ul.firstChild); | |
dom.addClass(div, 'save-row'); | |
var gears = document.createElement('span'); | |
gears.innerHTML = ' '; | |
dom.addClass(gears, 'button gears'); | |
// TODO replace with FunctionController | |
var button = document.createElement('span'); | |
button.innerHTML = 'Save'; | |
dom.addClass(button, 'button'); | |
dom.addClass(button, 'save'); | |
var button2 = document.createElement('span'); | |
button2.innerHTML = 'New'; | |
dom.addClass(button2, 'button'); | |
dom.addClass(button2, 'save-as'); | |
var button3 = document.createElement('span'); | |
button3.innerHTML = 'Revert'; | |
dom.addClass(button3, 'button'); | |
dom.addClass(button3, 'revert'); | |
var select = gui.__preset_select = document.createElement('select'); | |
if (gui.load && gui.load.remembered) { | |
common.each(gui.load.remembered, function(value, key) { | |
addPresetOption(gui, key, key == gui.preset); | |
}); | |
} else { | |
addPresetOption(gui, DEFAULT_DEFAULT_PRESET_NAME, false); | |
} | |
dom.bind(select, 'change', function() { | |
for (var index = 0; index < gui.__preset_select.length; index++) { | |
gui.__preset_select[index].innerHTML = gui.__preset_select[index].value; | |
} | |
gui.preset = this.value; | |
}); | |
div.appendChild(select); | |
div.appendChild(gears); | |
div.appendChild(button); | |
div.appendChild(button2); | |
div.appendChild(button3); | |
if (SUPPORTS_LOCAL_STORAGE) { | |
var saveLocally = document.getElementById('dg-save-locally'); | |
var explain = document.getElementById('dg-local-explain'); | |
saveLocally.style.display = 'block'; | |
var localStorageCheckBox = document.getElementById('dg-local-storage'); | |
if (localStorage.getItem(getLocalStorageHash(gui, 'isLocal')) === 'true') { | |
localStorageCheckBox.setAttribute('checked', 'checked'); | |
} | |
function showHideExplain() { | |
explain.style.display = gui.useLocalStorage ? 'block' : 'none'; | |
} | |
showHideExplain(); | |
// TODO: Use a boolean controller, fool! | |
dom.bind(localStorageCheckBox, 'change', function() { | |
gui.useLocalStorage = !gui.useLocalStorage; | |
showHideExplain(); | |
}); | |
} | |
var newConstructorTextArea = document.getElementById('dg-new-constructor'); | |
dom.bind(newConstructorTextArea, 'keydown', function(e) { | |
if (e.metaKey && (e.which === 67 || e.keyCode == 67)) { | |
SAVE_DIALOGUE.hide(); | |
} | |
}); | |
dom.bind(gears, 'click', function() { | |
newConstructorTextArea.innerHTML = JSON.stringify(gui.getSaveObject(), undefined, 2); | |
SAVE_DIALOGUE.show(); | |
newConstructorTextArea.focus(); | |
newConstructorTextArea.select(); | |
}); | |
dom.bind(button, 'click', function() { | |
gui.save(); | |
}); | |
dom.bind(button2, 'click', function() { | |
var presetName = prompt('Enter a new preset name.'); | |
if (presetName) gui.saveAs(presetName); | |
}); | |
dom.bind(button3, 'click', function() { | |
gui.revert(); | |
}); | |
// div.appendChild(button2); | |
} | |
function addResizeHandle(gui) { | |
gui.__resize_handle = document.createElement('div'); | |
common.extend(gui.__resize_handle.style, { | |
width: '6px', | |
marginLeft: '-3px', | |
height: '200px', | |
cursor: 'ew-resize', | |
position: 'absolute' | |
// border: '1px solid blue' | |
}); | |
var pmouseX; | |
dom.bind(gui.__resize_handle, 'mousedown', dragStart); | |
dom.bind(gui.__closeButton, 'mousedown', dragStart); | |
gui.domElement.insertBefore(gui.__resize_handle, gui.domElement.firstElementChild); | |
function dragStart(e) { | |
e.preventDefault(); | |
pmouseX = e.clientX; | |
dom.addClass(gui.__closeButton, GUI.CLASS_DRAG); | |
dom.bind(window, 'mousemove', drag); | |
dom.bind(window, 'mouseup', dragStop); | |
return false; | |
} | |
function drag(e) { | |
e.preventDefault(); | |
gui.width += pmouseX - e.clientX; | |
gui.onResize(); | |
pmouseX = e.clientX; | |
return false; | |
} | |
function dragStop() { | |
dom.removeClass(gui.__closeButton, GUI.CLASS_DRAG); | |
dom.unbind(window, 'mousemove', drag); | |
dom.unbind(window, 'mouseup', dragStop); | |
} | |
} | |
function setWidth(gui, w) { | |
gui.domElement.style.width = w + 'px'; | |
// Auto placed save-rows are position fixed, so we have to | |
// set the width manually if we want it to bleed to the edge | |
if (gui.__save_row && gui.autoPlace) { | |
gui.__save_row.style.width = w + 'px'; | |
}if (gui.__closeButton) { | |
gui.__closeButton.style.width = w + 'px'; | |
} | |
} | |
function getCurrentPreset(gui, useInitialValues) { | |
var toReturn = {}; | |
// For each object I'm remembering | |
common.each(gui.__rememberedObjects, function(val, index) { | |
var saved_values = {}; | |
// The controllers I've made for thcommon.isObject by property | |
var controller_map = | |
gui.__rememberedObjectIndecesToControllers[index]; | |
// Remember each value for each property | |
common.each(controller_map, function(controller, property) { | |
saved_values[property] = useInitialValues ? controller.initialValue : controller.getValue(); | |
}); | |
// Save the values for thcommon.isObject | |
toReturn[index] = saved_values; | |
}); | |
return toReturn; | |
} | |
function addPresetOption(gui, name, setSelected) { | |
var opt = document.createElement('option'); | |
opt.innerHTML = name; | |
opt.value = name; | |
gui.__preset_select.appendChild(opt); | |
if (setSelected) { | |
gui.__preset_select.selectedIndex = gui.__preset_select.length - 1; | |
} | |
} | |
function setPresetSelectIndex(gui) { | |
for (var index = 0; index < gui.__preset_select.length; index++) { | |
if (gui.__preset_select[index].value == gui.preset) { | |
gui.__preset_select.selectedIndex = index; | |
} | |
} | |
} | |
function markPresetModified(gui, modified) { | |
var opt = gui.__preset_select[gui.__preset_select.selectedIndex]; | |
// console.log('mark', modified, opt); | |
if (modified) { | |
opt.innerHTML = opt.value + "*"; | |
} else { | |
opt.innerHTML = opt.value; | |
} | |
} | |
function updateDisplays(controllerArray) { | |
if (controllerArray.length != 0) { | |
requestAnimationFrame(function() { | |
updateDisplays(controllerArray); | |
}); | |
} | |
common.each(controllerArray, function(c) { | |
c.updateDisplay(); | |
}); | |
} | |
return GUI; | |
})(dat.utils.css, | |
"<div id=\"dg-save\" class=\"dg dialogue\">\n\n Here's the new load parameter for your <code>GUI</code>'s constructor:\n\n <textarea id=\"dg-new-constructor\"></textarea>\n\n <div id=\"dg-save-locally\">\n\n <input id=\"dg-local-storage\" type=\"checkbox\"/> Automatically save\n values to <code>localStorage</code> on exit.\n\n <div id=\"dg-local-explain\">The values saved to <code>localStorage</code> will\n override those passed to <code>dat.GUI</code>'s constructor. This makes it\n easier to work incrementally, but <code>localStorage</code> is fragile,\n and your friends may not see the same values you do.\n \n </div>\n \n </div>\n\n</div>", | |
".dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{-webkit-transition:opacity 0.1s linear;-o-transition:opacity 0.1s linear;-moz-transition:opacity 0.1s linear;transition:opacity 0.1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1 !important}.dg.main:hover .close-button,.dg.main .close-button.drag{opacity:1}.dg.main .close-button{-webkit-transition:opacity 0.1s linear;-o-transition:opacity 0.1s linear;-moz-transition:opacity 0.1s linear;transition:opacity 0.1s linear;border:0;position:absolute;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-x:hidden}.dg.a.has-save ul{margin-top:27px}.dg.a.has-save ul.closed{margin-top:0}.dg.a .save-row{position:fixed;top:0;z-index:1002}.dg li{-webkit-transition:height 0.1s ease-out;-o-transition:height 0.1s ease-out;-moz-transition:height 0.1s ease-out;transition:height 0.1s ease-out}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;overflow:hidden;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid rgba(0,0,0,0)}.dg li.title{cursor:pointer;margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li > *{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .c{float:left;width:60%}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:9px}.dg .c select{margin-top:5px}.dg .cr.function,.dg .cr.function .property-name,.dg .cr.function *,.dg .cr.boolean,.dg .cr.boolean *{cursor:pointer}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0px 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco, monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px 'Lucida Grande', sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px 4px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid rgba(255,255,255,0.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2fa1d6}.dg .cr.number input[type=text]{color:#2fa1d6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.function:hover,.dg .cr.boolean:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2fa1d6}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda}\n", | |
dat.controllers.factory = (function (OptionController, NumberControllerBox, NumberControllerSlider, StringController, FunctionController, BooleanController, common) { | |
return function(object, property) { | |
var initialValue = object[property]; | |
// Providing options? | |
if (common.isArray(arguments[2]) || common.isObject(arguments[2])) { | |
return new OptionController(object, property, arguments[2]); | |
} | |
// Providing a map? | |
if (common.isNumber(initialValue)) { | |
if (common.isNumber(arguments[2]) && common.isNumber(arguments[3])) { | |
// Has min and max. | |
return new NumberControllerSlider(object, property, arguments[2], arguments[3]); | |
} else { | |
return new NumberControllerBox(object, property, { min: arguments[2], max: arguments[3] }); | |
} | |
} | |
if (common.isString(initialValue)) { | |
return new StringController(object, property); | |
} | |
if (common.isFunction(initialValue)) { | |
return new FunctionController(object, property, ''); | |
} | |
if (common.isBoolean(initialValue)) { | |
return new BooleanController(object, property); | |
} | |
} | |
})(dat.controllers.OptionController, | |
dat.controllers.NumberControllerBox, | |
dat.controllers.NumberControllerSlider, | |
dat.controllers.StringController = (function (Controller, dom, common) { | |
/** | |
* @class Provides a text input to alter the string property of an object. | |
* | |
* @extends dat.controllers.Controller | |
* | |
* @param {Object} object The object to be manipulated | |
* @param {string} property The name of the property to be manipulated | |
* | |
* @member dat.controllers | |
*/ | |
var StringController = function(object, property) { | |
StringController.superclass.call(this, object, property); | |
var _this = this; | |
this.__input = document.createElement('input'); | |
this.__input.setAttribute('type', 'text'); | |
dom.bind(this.__input, 'keyup', onChange); | |
dom.bind(this.__input, 'change', onChange); | |
dom.bind(this.__input, 'blur', onBlur); | |
dom.bind(this.__input, 'keydown', function(e) { | |
if (e.keyCode === 13) { | |
this.blur(); | |
} | |
}); | |
function onChange() { | |
_this.setValue(_this.__input.value); | |
} | |
function onBlur() { | |
if (_this.__onFinishChange) { | |
_this.__onFinishChange.call(_this, _this.getValue()); | |
} | |
} | |
this.updateDisplay(); | |
this.domElement.appendChild(this.__input); | |
}; | |
StringController.superclass = Controller; | |
common.extend( | |
StringController.prototype, | |
Controller.prototype, | |
{ | |
updateDisplay: function() { | |
// Stops the caret from moving on account of: | |
// keyup -> setValue -> updateDisplay | |
if (!dom.isActive(this.__input)) { | |
this.__input.value = this.getValue(); | |
} | |
return StringController.superclass.prototype.updateDisplay.call(this); | |
} | |
} | |
); | |
return StringController; | |
})(dat.controllers.Controller, | |
dat.dom.dom, | |
dat.utils.common), | |
dat.controllers.FunctionController, | |
dat.controllers.BooleanController, | |
dat.utils.common), | |
dat.controllers.Controller, | |
dat.controllers.BooleanController, | |
dat.controllers.FunctionController, | |
dat.controllers.NumberControllerBox, | |
dat.controllers.NumberControllerSlider, | |
dat.controllers.OptionController, | |
dat.controllers.ColorController = (function (Controller, dom, Color, interpret, common) { | |
var ColorController = function(object, property) { | |
ColorController.superclass.call(this, object, property); | |
this.__color = new Color(this.getValue()); | |
this.__temp = new Color(0); | |
var _this = this; | |
this.domElement = document.createElement('div'); | |
dom.makeSelectable(this.domElement, false); | |
this.__selector = document.createElement('div'); | |
this.__selector.className = 'selector'; | |
this.__saturation_field = document.createElement('div'); | |
this.__saturation_field.className = 'saturation-field'; | |
this.__field_knob = document.createElement('div'); | |
this.__field_knob.className = 'field-knob'; | |
this.__field_knob_border = '2px solid '; | |
this.__hue_knob = document.createElement('div'); | |
this.__hue_knob.className = 'hue-knob'; | |
this.__hue_field = document.createElement('div'); | |
this.__hue_field.className = 'hue-field'; | |
this.__input = document.createElement('input'); | |
this.__input.type = 'text'; | |
this.__input_textShadow = '0 1px 1px '; | |
dom.bind(this.__input, 'keydown', function(e) { | |
if (e.keyCode === 13) { // on enter | |
onBlur.call(this); | |
} | |
}); | |
dom.bind(this.__input, 'blur', onBlur); | |
dom.bind(this.__selector, 'mousedown', function(e) { | |
dom | |
.addClass(this, 'drag') | |
.bind(window, 'mouseup', function(e) { | |
dom.removeClass(_this.__selector, 'drag'); | |
}); | |
}); | |
var value_field = document.createElement('div'); | |
common.extend(this.__selector.style, { | |
width: '122px', | |
height: '102px', | |
padding: '3px', | |
backgroundColor: '#222', | |
boxShadow: '0px 1px 3px rgba(0,0,0,0.3)' | |
}); | |
common.extend(this.__field_knob.style, { | |
position: 'absolute', | |
width: '12px', | |
height: '12px', | |
border: this.__field_knob_border + (this.__color.v < .5 ? '#fff' : '#000'), | |
boxShadow: '0px 1px 3px rgba(0,0,0,0.5)', | |
borderRadius: '12px', | |
zIndex: 1 | |
}); | |
common.extend(this.__hue_knob.style, { | |
position: 'absolute', | |
width: '15px', | |
height: '2px', | |
borderRight: '4px solid #fff', | |
zIndex: 1 | |
}); | |
common.extend(this.__saturation_field.style, { | |
width: '100px', | |
height: '100px', | |
border: '1px solid #555', | |
marginRight: '3px', | |
display: 'inline-block', | |
cursor: 'pointer' | |
}); | |
common.extend(value_field.style, { | |
width: '100%', | |
height: '100%', | |
background: 'none' | |
}); | |
linearGradient(value_field, 'top', 'rgba(0,0,0,0)', '#000'); | |
common.extend(this.__hue_field.style, { | |
width: '15px', | |
height: '100px', | |
display: 'inline-block', | |
border: '1px solid #555', | |
cursor: 'ns-resize' | |
}); | |
hueGradient(this.__hue_field); | |
common.extend(this.__input.style, { | |
outline: 'none', | |
// width: '120px', | |
textAlign: 'center', | |
// padding: '4px', | |
// marginBottom: '6px', | |
color: '#fff', | |
border: 0, | |
fontWeight: 'bold', | |
textShadow: this.__input_textShadow + 'rgba(0,0,0,0.7)' | |
}); | |
dom.bind(this.__saturation_field, 'mousedown', fieldDown); | |
dom.bind(this.__field_knob, 'mousedown', fieldDown); | |
dom.bind(this.__hue_field, 'mousedown', function(e) { | |
setH(e); | |
dom.bind(window, 'mousemove', setH); | |
dom.bind(window, 'mouseup', unbindH); | |
}); | |
function fieldDown(e) { | |
setSV(e); | |
// document.body.style.cursor = 'none'; | |
dom.bind(window, 'mousemove', setSV); | |
dom.bind(window, 'mouseup', unbindSV); | |
} | |
function unbindSV() { | |
dom.unbind(window, 'mousemove', setSV); | |
dom.unbind(window, 'mouseup', unbindSV); | |
// document.body.style.cursor = 'default'; | |
} | |
function onBlur() { | |
var i = interpret(this.value); | |
if (i !== false) { | |
_this.__color.__state = i; | |
_this.setValue(_this.__color.toOriginal()); | |
} else { | |
this.value = _this.__color.toString(); | |
} | |
} | |
function unbindH() { | |
dom.unbind(window, 'mousemove', setH); | |
dom.unbind(window, 'mouseup', unbindH); | |
} | |
this.__saturation_field.appendChild(value_field); | |
this.__selector.appendChild(this.__field_knob); | |
this.__selector.appendChild(this.__saturation_field); | |
this.__selector.appendChild(this.__hue_field); | |
this.__hue_field.appendChild(this.__hue_knob); | |
this.domElement.appendChild(this.__input); | |
this.domElement.appendChild(this.__selector); | |
this.updateDisplay(); | |
function setSV(e) { | |
e.preventDefault(); | |
var w = dom.getWidth(_this.__saturation_field); | |
var o = dom.getOffset(_this.__saturation_field); | |
var s = (e.clientX - o.left + document.body.scrollLeft) / w; | |
var v = 1 - (e.clientY - o.top + document.body.scrollTop) / w; | |
if (v > 1) v = 1; | |
else if (v < 0) v = 0; | |
if (s > 1) s = 1; | |
else if (s < 0) s = 0; | |
_this.__color.v = v; | |
_this.__color.s = s; | |
_this.setValue(_this.__color.toOriginal()); | |
return false; | |
} | |
function setH(e) { | |
e.preventDefault(); | |
var s = dom.getHeight(_this.__hue_field); | |
var o = dom.getOffset(_this.__hue_field); | |
var h = 1 - (e.clientY - o.top + document.body.scrollTop) / s; | |
if (h > 1) h = 1; | |
else if (h < 0) h = 0; | |
_this.__color.h = h * 360; | |
_this.setValue(_this.__color.toOriginal()); | |
return false; | |
} | |
}; | |
ColorController.superclass = Controller; | |
common.extend( | |
ColorController.prototype, | |
Controller.prototype, | |
{ | |
updateDisplay: function() { | |
var i = interpret(this.getValue()); | |
if (i !== false) { | |
var mismatch = false; | |
// Check for mismatch on the interpreted value. | |
common.each(Color.COMPONENTS, function(component) { | |
if (!common.isUndefined(i[component]) && | |
!common.isUndefined(this.__color.__state[component]) && | |
i[component] !== this.__color.__state[component]) { | |
mismatch = true; | |
return {}; // break | |
} | |
}, this); | |
// If nothing diverges, we keep our previous values | |
// for statefulness, otherwise we recalculate fresh | |
if (mismatch) { | |
common.extend(this.__color.__state, i); | |
} | |
} | |
common.extend(this.__temp.__state, this.__color.__state); | |
this.__temp.a = 1; | |
var flip = (this.__color.v < .5 || this.__color.s > .5) ? 255 : 0; | |
var _flip = 255 - flip; | |
common.extend(this.__field_knob.style, { | |
marginLeft: 100 * this.__color.s - 7 + 'px', | |
marginTop: 100 * (1 - this.__color.v) - 7 + 'px', | |
backgroundColor: this.__temp.toString(), | |
border: this.__field_knob_border + 'rgb(' + flip + ',' + flip + ',' + flip +')' | |
}); | |
this.__hue_knob.style.marginTop = (1 - this.__color.h / 360) * 100 + 'px' | |
this.__temp.s = 1; | |
this.__temp.v = 1; | |
linearGradient(this.__saturation_field, 'left', '#fff', this.__temp.toString()); | |
common.extend(this.__input.style, { | |
backgroundColor: this.__input.value = this.__color.toString(), | |
color: 'rgb(' + flip + ',' + flip + ',' + flip +')', | |
textShadow: this.__input_textShadow + 'rgba(' + _flip + ',' + _flip + ',' + _flip +',.7)' | |
}); | |
} | |
} | |
); | |
var vendors = ['-moz-','-o-','-webkit-','-ms-','']; | |
function linearGradient(elem, x, a, b) { | |
elem.style.background = ''; | |
common.each(vendors, function(vendor) { | |
elem.style.cssText += 'background: ' + vendor + 'linear-gradient('+x+', '+a+' 0%, ' + b + ' 100%); '; | |
}); | |
} | |
function hueGradient(elem) { | |
elem.style.background = ''; | |
elem.style.cssText += 'background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);' | |
elem.style.cssText += 'background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);' | |
elem.style.cssText += 'background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);' | |
elem.style.cssText += 'background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);' | |
elem.style.cssText += 'background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);' | |
} | |
return ColorController; | |
})(dat.controllers.Controller, | |
dat.dom.dom, | |
dat.color.Color = (function (interpret, math, toString, common) { | |
var Color = function() { | |
this.__state = interpret.apply(this, arguments); | |
if (this.__state === false) { | |
throw 'Failed to interpret color arguments'; | |
} | |
this.__state.a = this.__state.a || 1; | |
}; | |
Color.COMPONENTS = ['r','g','b','h','s','v','hex','a']; | |
common.extend(Color.prototype, { | |
toString: function() { | |
return toString(this); | |
}, | |
toOriginal: function() { | |
return this.__state.conversion.write(this); | |
} | |
}); | |
defineRGBComponent(Color.prototype, 'r', 2); | |
defineRGBComponent(Color.prototype, 'g', 1); | |
defineRGBComponent(Color.prototype, 'b', 0); | |
defineHSVComponent(Color.prototype, 'h'); | |
defineHSVComponent(Color.prototype, 's'); | |
defineHSVComponent(Color.prototype, 'v'); | |
Object.defineProperty(Color.prototype, 'a', { | |
get: function() { | |
return this.__state.a; | |
}, | |
set: function(v) { | |
this.__state.a = v; | |
} | |
}); | |
Object.defineProperty(Color.prototype, 'hex', { | |
get: function() { | |
if (!this.__state.space !== 'HEX') { | |
this.__state.hex = math.rgb_to_hex(this.r, this.g, this.b); | |
} | |
return this.__state.hex; | |
}, | |
set: function(v) { | |
this.__state.space = 'HEX'; | |
this.__state.hex = v; | |
} | |
}); | |
function defineRGBComponent(target, component, componentHexIndex) { | |
Object.defineProperty(target, component, { | |
get: function() { | |
if (this.__state.space === 'RGB') { | |
return this.__state[component]; | |
} | |
recalculateRGB(this, component, componentHexIndex); | |
return this.__state[component]; | |
}, | |
set: function(v) { | |
if (this.__state.space !== 'RGB') { | |
recalculateRGB(this, component, componentHexIndex); | |
this.__state.space = 'RGB'; | |
} | |
this.__state[component] = v; | |
} | |
}); | |
} | |
function defineHSVComponent(target, component) { | |
Object.defineProperty(target, component, { | |
get: function() { | |
if (this.__state.space === 'HSV') | |
return this.__state[component]; | |
recalculateHSV(this); | |
return this.__state[component]; | |
}, | |
set: function(v) { | |
if (this.__state.space !== 'HSV') { | |
recalculateHSV(this); | |
this.__state.space = 'HSV'; | |
} | |
this.__state[component] = v; | |
} | |
}); | |
} | |
function recalculateRGB(color, component, componentHexIndex) { | |
if (color.__state.space === 'HEX') { | |
color.__state[component] = math.component_from_hex(color.__state.hex, componentHexIndex); | |
} else if (color.__state.space === 'HSV') { | |
common.extend(color.__state, math.hsv_to_rgb(color.__state.h, color.__state.s, color.__state.v)); | |
} else { | |
throw 'Corrupted color state'; | |
} | |
} | |
function recalculateHSV(color) { | |
var result = math.rgb_to_hsv(color.r, color.g, color.b); | |
common.extend(color.__state, | |
{ | |
s: result.s, | |
v: result.v | |
} | |
); | |
if (!common.isNaN(result.h)) { | |
color.__state.h = result.h; | |
} else if (common.isUndefined(color.__state.h)) { | |
color.__state.h = 0; | |
} | |
} | |
return Color; | |
})(dat.color.interpret, | |
dat.color.math = (function () { | |
var tmpComponent; | |
return { | |
hsv_to_rgb: function(h, s, v) { | |
var hi = Math.floor(h / 60) % 6; | |
var f = h / 60 - Math.floor(h / 60); | |
var p = v * (1.0 - s); | |
var q = v * (1.0 - (f * s)); | |
var t = v * (1.0 - ((1.0 - f) * s)); | |
var c = [ | |
[v, t, p], | |
[q, v, p], | |
[p, v, t], | |
[p, q, v], | |
[t, p, v], | |
[v, p, q] | |
][hi]; | |
return { | |
r: c[0] * 255, | |
g: c[1] * 255, | |
b: c[2] * 255 | |
}; | |
}, | |
rgb_to_hsv: function(r, g, b) { | |
var min = Math.min(r, g, b), | |
max = Math.max(r, g, b), | |
delta = max - min, | |
h, s; | |
if (max != 0) { | |
s = delta / max; | |
} else { | |
return { | |
h: NaN, | |
s: 0, | |
v: 0 | |
}; | |
} | |
if (r == max) { | |
h = (g - b) / delta; | |
} else if (g == max) { | |
h = 2 + (b - r) / delta; | |
} else { | |
h = 4 + (r - g) / delta; | |
} | |
h /= 6; | |
if (h < 0) { | |
h += 1; | |
} | |
return { | |
h: h * 360, | |
s: s, | |
v: max / 255 | |
}; | |
}, | |
rgb_to_hex: function(r, g, b) { | |
var hex = this.hex_with_component(0, 2, r); | |
hex = this.hex_with_component(hex, 1, g); | |
hex = this.hex_with_component(hex, 0, b); | |
return hex; | |
}, | |
component_from_hex: function(hex, componentIndex) { | |
return (hex >> (componentIndex * 8)) & 0xFF; | |
}, | |
hex_with_component: function(hex, componentIndex, value) { | |
return value << (tmpComponent = componentIndex * 8) | (hex & ~ (0xFF << tmpComponent)); | |
} | |
} | |
})(), | |
dat.color.toString, | |
dat.utils.common), | |
dat.color.interpret, | |
dat.utils.common), | |
dat.utils.requestAnimationFrame = (function () { | |
/** | |
* requirejs version of Paul Irish's RequestAnimationFrame | |
* http://paulirish.com/2011/requestanimationframe-for-smart-animating/ | |
*/ | |
return window.webkitRequestAnimationFrame || | |
window.mozRequestAnimationFrame || | |
window.oRequestAnimationFrame || | |
window.msRequestAnimationFrame || | |
function(callback, element) { | |
window.setTimeout(callback, 1000 / 60); | |
}; | |
})(), | |
dat.dom.CenteredDiv = (function (dom, common) { | |
var CenteredDiv = function() { | |
this.backgroundElement = document.createElement('div'); | |
common.extend(this.backgroundElement.style, { | |
backgroundColor: 'rgba(0,0,0,0.8)', | |
top: 0, | |
left: 0, | |
display: 'none', | |
zIndex: '1000', | |
opacity: 0, | |
WebkitTransition: 'opacity 0.2s linear' | |
}); | |
dom.makeFullscreen(this.backgroundElement); | |
this.backgroundElement.style.position = 'fixed'; | |
this.domElement = document.createElement('div'); | |
common.extend(this.domElement.style, { | |
position: 'fixed', | |
display: 'none', | |
zIndex: '1001', | |
opacity: 0, | |
WebkitTransition: '-webkit-transform 0.2s ease-out, opacity 0.2s linear' | |
}); | |
document.body.appendChild(this.backgroundElement); | |
document.body.appendChild(this.domElement); | |
var _this = this; | |
dom.bind(this.backgroundElement, 'click', function() { | |
_this.hide(); | |
}); | |
}; | |
CenteredDiv.prototype.show = function() { | |
var _this = this; | |
this.backgroundElement.style.display = 'block'; | |
this.domElement.style.display = 'block'; | |
this.domElement.style.opacity = 0; | |
// this.domElement.style.top = '52%'; | |
this.domElement.style.webkitTransform = 'scale(1.1)'; | |
this.layout(); | |
common.defer(function() { | |
_this.backgroundElement.style.opacity = 1; | |
_this.domElement.style.opacity = 1; | |
_this.domElement.style.webkitTransform = 'scale(1)'; | |
}); | |
}; | |
CenteredDiv.prototype.hide = function() { | |
var _this = this; | |
var hide = function() { | |
_this.domElement.style.display = 'none'; | |
_this.backgroundElement.style.display = 'none'; | |
dom.unbind(_this.domElement, 'webkitTransitionEnd', hide); | |
dom.unbind(_this.domElement, 'transitionend', hide); | |
dom.unbind(_this.domElement, 'oTransitionEnd', hide); | |
}; | |
dom.bind(this.domElement, 'webkitTransitionEnd', hide); | |
dom.bind(this.domElement, 'transitionend', hide); | |
dom.bind(this.domElement, 'oTransitionEnd', hide); | |
this.backgroundElement.style.opacity = 0; | |
// this.domElement.style.top = '48%'; | |
this.domElement.style.opacity = 0; | |
this.domElement.style.webkitTransform = 'scale(1.1)'; | |
}; | |
CenteredDiv.prototype.layout = function() { | |
this.domElement.style.left = window.innerWidth/2 - dom.getWidth(this.domElement) / 2 + 'px'; | |
this.domElement.style.top = window.innerHeight/2 - dom.getHeight(this.domElement) / 2 + 'px'; | |
}; | |
function lockScroll(e) { | |
console.log(e); | |
} | |
return CenteredDiv; | |
})(dat.dom.dom, | |
dat.utils.common), | |
dat.dom.dom, | |
dat.utils.common); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html><html><head><base href="http://www.google.com"><meta http-equiv="content-type" content="text/html; charset=UTF-8"><meta name="description" content="Search the world's information, including webpages, images, videos and more. Google has many special features to help you find exactly what you're looking for."><meta name="robots" content="noodp"><title>Google</title><script>window.google={kEI:"RzP1TsPtDaPA0QXo0sCnAQ",getEI:function(a){var b;while(a&&!(a.getAttribute&&(b=a.getAttribute("eid"))))a=a.parentNode;return b||google.kEI},https:function(){return window.location.protocol=="https:"},kEXPI:"17259,17311,24472,27147,30869,31396,33491,33523,33524,35213,35300,35387",kCSI:{e:"17259,17311,24472,27147,30869,31396,33491,33523,33524,35213,35300,35387",ei:"RzP1TsPtDaPA0QXo0sCnAQ"},authuser:0, | |
ml:function(){},pageState:"#",kHL:"en",time:function(){return(new Date).getTime()},log:function(a,b,c,e){var d=new Image,g=google,h=g.lc,f=g.li,j="";d.onerror=(d.onload=(d.onabort=function(){delete h[f]}));h[f]=d;if(!c&&b.search("&ei=")==-1)j="&ei="+google.getEI(e);var i=c||"/gen_204?atyp=i&ct="+a+"&cad="+b+j+"&zx="+google.time(),k=/^http:/i;if(k.test(i)&&google.https()){google.ml(new Error("GLMM"),false,{src:i}); | |
delete h[f];return}d.src=i;g.li=f+1},lc:[],li:0,j:{en:1,l:function(){google.fl=true},e:function(){google.fl=true},b:location.hash&&location.hash!="#",bv:21,cf:"osb",pm:"p",pl:[],mc:0,sc:0.5,u:"c9c918f0"},Toolbelt:{},y:{},x:function(a,b){google.y[a.id]= | |
[a,b];return false}};(function(){var a=google.j;window.onpopstate= | |
function(){a.psc=1};for(var b=0,c;c=["ad","bc","inpr","is","p","pa","ac","pc","pah","ph","sa","sifp","slp","spf","spn","xx","zc","zz"][b++];)(function(e){a[e]=function(){a.pl.push([e,arguments])}})(c)})();if(!window.chrome)window.chrome={};window.chrome.sv=1.00; | |
window.google.sn="webhp";window.google.timers={};window.google.startTick=function(a,b){window.google.timers[a]={t:{start:(new Date).getTime()},bfr:!(!b)}};window.google.tick=function(a,b,c){if(!window.google.timers[a])google.startTick(a);window.google.timers[a].t[b]=c||(new Date).getTime()};google.startTick("load",true);try{window.google.pt=window.chrome&&window.chrome.csi&&Math.floor(window.chrome.csi().pageT);}catch(u){} | |
</script><style>#gb{font:13px/27px Arial,sans-serif;height:102px}#gbz,#gbg{position:absolute;white-space:nowrap;top:0;height:30px;z-index:1000}#gbz{left:0;padding-left:4px}#gbg{right:0;padding-right:5px}#gbs{background:transparent;position:absolute;top:-999px;visibility:hidden;z-index:998}.gbto #gbs{background #fff}#gbx3,#gbx4{background-color:#2d2d2d;background-image:none;_background-image:none;background-position:0 -138px;background-repeat:repeat-x;border-bottom:1px solid #000;font-size:24px;height:29px;_height:30px;opacity:1;filter:alpha(opacity=100);position:absolute;top:0;width:100%;z-index:990}#gbx3{left:0}#gbx4{right:0}.gbtcb{position:absolute;visibility:hidden}#gbz .gbtcb{right:0}#gbg .gbtcb{left:0}.gbxx{display:none !important}.gbm{position:absolute;z-index:999;top:-999px;visibility:hidden;text-align:left;border:1px solid #bebebe;background:#fff;-moz-box-shadow:-1px 1px 1px rgba(0,0,0,.2);-webkit-box-shadow:0 2px 4px rgba(0,0,0,.2);box-shadow:0 2px 4px rgba(0,0,0,.2)}.gbrtl .gbm{-moz-box-shadow:1px 1px 1px rgba(0,0,0,.2)}.gbto .gbm,.gbto #gbs{top:50px;visibility:visible}#gbz .gbm,#gbz #gbs{left:0}#gbg .gbm,#gbg #gbs{right:0}.gbxms{background-color:#ccc;display:block;position:absolute;z-index:1;top:-1px;left:-2px;right:-2px;bottom:-2px;opacity:.4;-moz-border-radius:3px;filter:progid:DXImageTransform.Microsoft.Blur(pixelradius=5);*opacity:1;*top:-2px;*left:-5px;*right:5px;*bottom:4px;-ms-filter:"progid:DXImageTransform.Microsoft.Blur(pixelradius=5)";opacity:1\0/;top:-4px\0/;left:-6px\0/;right:5px\0/;bottom:4px\0/}.gbma{position:relative;top:-1px;border-style:solid dashed dashed;border-color:transparent;border-top-color:#c0c0c0;display:-moz-inline-box;display:inline-block;font-size:0;height:0;line-height:0;width:0;border-width:3px 3px 0;padding-top:1px;left:4px}#gbztms1,#gbi4m1,#gbi4s,#gbi4t{zoom:1}.gbtc,.gbmc,.gbmcc{display:block;list-style:none;margin:0;padding:0}.gbmc{background:#fff;padding:10px 0;position:relative;z-index:2;zoom:1}.gbt{position:relative;display:-moz-inline-box;display:inline-block;line-height:27px;padding:0;vertical-align:top}.gbt{*display:inline}.gbto{box-shadow:0 2px 4px rgba(0,0,0,.2);-moz-box-shadow:0 2px 4px rgba(0,0,0,.2);-webkit-box-shadow:0 2px 4px rgba(0,0,0,.2)}.gbzt,.gbgt{cursor:pointer;display:block;text-decoration:none !important}.gbts{border-left:1px solid transparent;border-right:1px solid transparent;display:block;*display:inline-block;padding:0 5px;position:relative;z-index:1000}.gbts{*display:inline}.gbto .gbts{background:#fff;border-color:#bebebe;color:#36c;padding-bottom:1px;padding-top:2px}.gbz0l .gbts{color:#fff;font-weight:bold}.gbtsa{padding-right:9px}#gbz .gbzt,#gbz .gbgt,#gbg .gbgt{color:#ccc!important}.gbtb2{display:block;border-top:2px solid transparent}.gbto .gbzt .gbtb2,.gbto .gbgt .gbtb2{border-top-width:0}.gbtb .gbts{background:url(//ssl.gstatic.com/gb/images/b_8d5afc09.png);_background:url(//ssl.gstatic.com/gb/images/b8_3615d64d.png);background-position:-27px -22px;border:0;font-size:0;padding:29px 0 0;*padding:27px 0 0;width:1px}.gbzt-hvr,.gbzt:focus,.gbgt-hvr,.gbgt:focus{background-color:transparent;background-image:none;_background-image:none;background-position:0 -102px;background-repeat:repeat-x;outline:none;text-decoration:none !important}.gbpdjs .gbto .gbm{min-width:99%}.gbz0l .gbtb2{border-top-color:#dd4b39!important}#gbi4s,#gbi4s1{font-weight:bold}#gbg6.gbgt-hvr,#gbg6.gbgt:focus{background-color:transparent;background-image:none}.gbg4a{font-size:0;line-height:0}.gbg4a .gbts{padding:27px 5px 0;*padding:25px 5px 0}.gbto .gbg4a .gbts{padding:29px 5px 1px;*padding:27px 5px 1px}#gbi4i,#gbi4id{left:5px;border:0;height:24px;position:absolute;top:1px;width:24px}.gbto #gbi4i,.gbto #gbi4id{top:3px}.gbi4p{display:block;width:24px}#gbi4id,#gbmpid{background:url(//ssl.gstatic.com/gb/images/b_8d5afc09.png);_background:url(//ssl.gstatic.com/gb/images/b8_3615d64d.png)}#gbi4id{background-position:-29px -54px}#gbmpid{background-position:-58px 0px}#gbmpi,#gbmpid{border:none;display:inline-block;margin:10px 20px;height:48px;width:48px}#gbmpi,#gbmpid{*display:inline}#gbg5{font-size:0}#gbgs5{padding:5px !important}.gbto #gbgs5{padding:7px 5px 6px !important}#gbi5{background:url(//ssl.gstatic.com/gb/images/b_8d5afc09.png);_background:url(//ssl.gstatic.com/gb/images/b8_3615d64d.png);background-position:0 0;display:block;font-size:0;height:17px;width:16px}.gbto #gbi5{background-position:-6px -22px}#gbgf .gbmt,.gbn .gbmt,.gbn .gbmt:visited,.gbnd .gbmt,.gbnd .gbmt:visited{color:#dd8e27 !important}.gbf .gbmt,.gbf .gbmt:visited{color:#900 !important}.gbmt,.gbml1,.gbmt:visited,.gbml1:visited{color:#36c !important;text-decoration:none !important}.gbmt,.gbmt:visited{display:block}.gbml1,.gbml1:visited{display:inline-block;margin:0 10px;padding:0 10px}.gbml1{*display:inline}.gbml1-hvr,.gbml1:focus{background:#eff3fb;outline:none}#gbpm .gbml1{display:inline;margin:0;padding:0;white-space:nowrap}#gbpm .gbml1-hvr,#gbpm .gbml1:focus{background:none;text-decoration:underline !important}.gbmt{padding:0 20px}.gbmt-hvr,.gbmt:focus{background:#eff3fb;cursor:pointer;outline:0 solid black;text-decoration:none !important}.gbm0l,.gbm0l:visited{color:#000 !important;font-weight:bold}.gbmh{border-top:1px solid #e5e5e5;font-size:0;margin:10px 0}#gbd4 .gbmh{margin:0}.gbmtc{padding:0;margin:0;line-height:27px}.GBMCC:last-child:after,#GBMPAL:last-child:after{content:'\0A\0A';white-space:pre;position:absolute}#gbd4 .gbpc,#gbmpas .gbmt{line-height:17px}#gbd4 .gbpgs .gbmtc{line-height:27px}#gbmpas .gbmt{padding-bottom:10px;padding-top:10px}#gbmple .gbmt,#gbmpas .gbmt{font-size:15px}#gbd4 .gbpc{display:inline-block;margin:6px 0 10px;margin-right:50px;vertical-align:top}#gbd4 .gbpc{*display:inline}.gbpc .gbps,.gbpc .gbps2{display:block;margin:0 20px}#gbmplp.gbps{margin:0 10px}.gbpc .gbps{color:#000;font-weight:bold}.gbpc .gbps2{font-size:13px}.gbpc .gbpd{margin-bottom:5px}.gbpd .gbmt,.gbmpmtd .gbmt{color:#666 !important}.gbmpme,.gbps2{color:#666;display:block;font-size:11px}.gbp0 .gbps2,.gbmpmta .gbmpme{font-weight:bold}#gbmpp{display:none}#gbd4 .gbmcc{margin-top:5px}.gbpmc{background:#edfeea}.gbpmc .gbmt{padding:10px 20px}#gbpm{*border-collapse:collapse;border-spacing:0;margin:0;white-space:normal}#gbpm .gbmt{border-top:none;color:#666 !important;font:11px Arial,sans-serif}#gbpms{*white-space:nowrap}.gbpms2{font-weight:bold;white-space:nowrap}#gbmpal{*border-collapse:collapse;border-spacing:0;margin:0;white-space:nowrap}.gbmpala,.gbmpalb{font:13px Arial,sans-serif;line-height:27px;padding:10px 20px 0;white-space:nowrap}.gbmpala{padding-left:0;text-align:left}.gbmpalb{padding-right:0;text-align:right}.gbp0 .gbps,.gbmpmta .gbmpmn{color:#000;display:inline-block;font-weight:bold;padding-right:34px;position:relative}.gbp0 .gbps,.gbmpmta .gbmpmn{*display:inline}.gbmpmtc,.gbp0i{background:url(//ssl.gstatic.com/gb/images/b_8d5afc09.png);_background:url(//ssl.gstatic.com/gb/images/b8_3615d64d.png);background-position:-484px -32px;position:absolute;height:21px;width:24px;right:0;top:-3px}#gb{height:98px}.gbxx{display:none !important}#gbq,#gbu,#gbn{position:absolute;top:20px;white-space:nowrap}#gbu,#gbn{height:97px}#gbu,#gbn,#gbq1,#gbq3{z-index:987}#gbq{left:0;_overflow:hidden;width:100%}#gbq2{top:16px;z-index:986}#gbu{right:0;height:30px;margin-right:44px;padding-bottom:21px;padding-top:20px}#gbn{left:0;height:30px;margin-left:149px;padding-bottom:21px;padding-top:20px}#gbx1,#gbx2{background:#f1f1f1;background:-webkit-gradient(radial,100 36,0,100 -40,120,from(#f1f1f1),to(#f1f1f1)),#f1f1f1;border-bottom:1px solid #666;border-color:#e5e5e5;height:97px;position:absolute;top:0;width:100%;z-index:985;min-width:980px;}#gbx1.gbxngh,#gbx2.gbxngh{background:-webkit-gradient(radial,100 20,0,100 20,120,from(#f1f1f1),to(#f1f1f1)),#f1f1f1}#gbx1{left:0}#gbx2{right:0}#gbq1{left:0;margin:0;padding:0;margin-left:44px;position:absolute}#gbq1 .gbmai{right:4px;top:46px}.gbes#gbq1{margin-left:0}#gbq3{left:220px;padding-bottom:21px;padding-top:20px;position:absolute;top:16px}#gbql{background:url(//ssl.gstatic.com/gb/images/j_40368b96.png) no-repeat;background-position:-180px -74px;display:block;height:45px;width:116px}#gbqlw{display:table-cell;height:98px;padding-right:16px;position:relative;vertical-align:middle;top:3px;}#gbqld{border:none;display:block}#gog{height:99px}.gbh{border-top:none}.gbpl,.gbpr,#gbpx1,#gbpx2{border-top:none !important;top:102px !important}.gbpl,.gbpr{margin-top:4px}.gbi5t{color:#666;display:block;margin:1px 15px;text-shadow:none}#gbq2{display:block;margin-left:220px;padding-bottom:0;padding-top:20px}#gbqf{display:block;margin:0;max-width:572px;min-width:572px;padding-right:104px;position:relative;white-space:nowrap}#gbqff{border:none;margin:0;padding:0}#gbqfqw{background:#fff}#gbqfqw,#gbqfb{vertical-align:top}#gbqfaa,#gbqfab,#gbqfqwb{position:absolute}#gbqfaa{left:0}#gbqfab{right:0}#gbqfqwb{right:0;left:0;cursor:text}.gbqfqwb{padding:0 8px}#gbqfbw{right:0;margin:0 15px;position:absolute;top:0}.gbqfb{background-color:#4d90fe;background-image:-webkit-gradient(linear,left top,left bottom,from(#4d90fe),to(#4787ed));background-image:-webkit-linear-gradient(top,#4d90fe,#4787ed);background-image:-moz-linear-gradient(top,#4d90fe,#4787ed);background-image:-ms-linear-gradient(top,#4d90fe,#4787ed);background-image:-o-linear-gradient(top,#4d90fe,#4787ed);background-image:linear-gradient(top,#4d90fe,#4787ed);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#4d90fe',EndColorStr='#4787ed');border:1px solid #3079ed;-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;-moz-user-select:none;-webkit-user-select:none;color:#fff;cursor:default;font-size:11px;font-weight:bold;height:29px;min-width:54px;*min-width:70px;text-align:center;padding:0 8px}.gbqfb-hvr{border:1px solid #2f5bb7;background-color:#357ae8;background-image:-webkit-gradient(linear,left top,left bottom,from(#4d90fe),to(#357ae8));background-image:-webkit-linear-gradient(top,#4d90fe,#357ae8);background-image:-moz-linear-gradient(top,#4d90fe,#357ae8);background-image:-ms-linear-gradient(top,#4d90fe,#357ae8);background-image:-o-linear-gradient(top,#4d90fe,#357ae8);background-image:linear-gradient(top,#4d90fe,#357ae8);-webkit-box-shadow:0 1px 1px rgba(0,0,0,.1);-moz-box-shadow:0 1px 1px rgba(0,0,0,.1);box-shadow:0 1px 1px rgba(0,0,0,.1)}.gbqfb:focus{-moz-box-shadow:inset 0 0 0 1px #fff;-webkit-box-shadow:inset 0 0 0 1px #fff;box-shadow:inset 0 0 0 1px #fff;outline:none}.gbqfb::-moz-focus-inner{border:0}.gbqfb-hvr:focus{-moz-box-shadow:inset 0 0 0 1px #fff,0 1px 1px rgba(0,0,0,.1);-webkit-box-shadow:inset 0 0 0 1px #fff,0 1px 1px rgba(0,0,0,.1);box-shadow:inset 0 0 0 1px #fff,0 1px 1px rgba(0,0,0,.1)}.gbqfb:active{-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.3);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.3);box-shadow:inset 0 1px 2px rgba(0,0,0,.3)}#gbqfi{background:url(//ssl.gstatic.com/gb/images/j_40368b96.png);background-position:-211px -124px;display:inline-block;height:13px;margin:0 19px;vertical-align:text-top;width:14px}#gbqfi{*display:inline}#gbqfqw{border:1px solid #d9d9d9;border-top:1px solid #c0c0c0;-moz-border-radius:1px;-webkit-border-radius:1px;border-radius:1px;height:27px;position:relative}.gbqfqw-hvr{border:1px solid #b9b9b9;border-top:1px solid #a0a0a0;-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}#gbqfqw:active,#gbqfqw.gbqfqwf{border:1px solid #4d90fe;-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.3);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.3);box-shadow:inset 0 1px 2px rgba(0,0,0,.3);outline:none}#gbqfq{background:transparent;border:none;height:19px;margin-top:4px;padding:0;vertical-align:top;width:100%}#gbqfq:focus{outline:none}.gbqfif,.gbqfsf{font:16px arial,sans-serif}#gbqfbwa{text-align:center;height:0}.gbqfba{background-color:#f5f5f5;background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#f1f1f1));background-image:-webkit-linear-gradient(top,#f5f5f5,#f1f1f1);background-image:-moz-linear-gradient(top,#f5f5f5,#f1f1f1);background-image:-ms-linear-gradient(top,#f5f5f5,#f1f1f1);background-image:-o-linear-gradient(top,#f5f5f5,#f1f1f1);background-image:linear-gradient(top,#f5f5f5,#f1f1f1);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#f5f5f5',EndColorStr='#f1f1f1');border-color:#dcdcdc;border-color:rgba(0,0,0,.1);color:#555;margin:16px 8px;-moz-transition:all .218s;-o-transition:all .218s;-webkit-transition:all .218s;transition:all .218s}#gbqfbwa .gbqfb-hvr{border-color:#c6c6c6;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.1);-moz-box-shadow:0 1px 1px rgba(0,0,0,.1);box-shadow:0 1px 1px rgba(0,0,0,.1);color:#333;background-color:#f8f8f8;background-image:-webkit-gradient(linear,left top,left bottom,from(#f8f8f8),to(#f1f1f1));background-image:-webkit-linear-gradient(top,#f8f8f8,#f1f1f1);background-image:-moz-linear-gradient(top,#f8f8f8,#f1f1f1);background-image:-ms-linear-gradient(top,#f8f8f8,#f1f1f1);background-image:-o-linear-gradient(top,#f8f8f8,#f1f1f1);background-image:linear-gradient(top,#f8f8f8,#f1f1f1);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#f8f8f8',EndColorStr='#f1f1f1')}.gbqfba:active{border-color:#c6c6c6;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1);color:#333}.gbqfba:focus{border:1px solid #4d90fe;outline:none}#gbqfsa,#gbqfsb{font:bold 11px/27px Arial,sans-serif !important}.gbqfh #gbql{background:url(//ssl.gstatic.com/gb/images/j_40368b96.png);background-repeat:no-repeat;display:block;margin-bottom:21px;margin-top:25px}.gbqfh #gbql,.gbemi#gb .gbqfh #gbql,.gbesi#gb .gbqfh #gbql,.gbqfh .gbem#gbql,.gbqfh .gbes#gbql{background-position:-32px -74px;height:27px;width:71px}.gbqfh#gbpr .gbqpa{width:71px}.gbqfh .gbes#gbql,.gbesi#gb .gbqfh #gbql{margin-bottom:14px;margin-top:18px}.gbqfh#gbq2{z-index:985}.gbqfh#gbq2{margin:0;margin-left:0 !important;padding-top:0;top:340px}.gbqfh #gbqf{margin:auto;min-width:534px;padding:0 223px !important}.gbqfh #gbqfbw{display:none}#gbqfbwa{display:none}.gbqfh #gbqfbwa{display:block}.gbqfh#gbn{display:block}#gbn{display:none}.gbes .gbqfh#gbq2,.gbesi#gb .gbqfh#gbq2{padding-top:0;top:340px}.gbem .gbqfh#gbq2,.gbemi#gb .gbqfh#gbq2{padding-top:0;top:340px}.gbqfh #gbqld{display:none !important}#gbql{display:none}#gbu .gbm,#gbu #gbs{right:0}#gbu .gbgt{color:#666}#gbu .gbt{margin-left:15px}#gbu .gbto{box-shadow:none;-moz-box-shadow:none;-webkit-box-shadow:none}#gbd1 .gbmc,#gbd3 .gbmc{padding:0}#gbns{display:none}.gbmwc{right:0;margin-top:-2px;position:absolute;top:-999px;width:440px;z-index:999}#gbwc.gbmwca{top:94px}.gbmsg{display:none;position:absolute;top:0}.gbmsgo .gbmsg{display:block;background:#fff;width:100%;text-align:center;z-index:3;top:30%}.gbmab,.gbmac,.gbmad,.gbmae{left:5px;border-style:dashed dashed solid;border-color:transparent;border-bottom-color:#bebebe;border-width:0 10px 10px;display:-moz-inline-box;display:inline-block;font-size:0;height:0;line-height:0;position:absolute;top:0;width:0;z-index:1000}.gbmab,.gbmac{visibility:hidden}.gbmac{border-bottom-color:#fff}.gbto .gbmab,.gbto .gbmac{visibility:visible}.gbmai{background:url(//ssl.gstatic.com/gb/images/j_40368b96.png);background-position:-180px 0;opacity:.8;filter:alpha(opacity=80);font-size:0;line-height:0;position:absolute;height:4px;width:7px}.gbgt-hvr .gbmai{opacity:1;filter:alpha(opacity=100)}#gbgs3{background-color:#f8f8f8;background-image:-webkit-gradient(linear,left top,left bottom,from(#f8f8f8),to(#ececec));background-image:-webkit-linear-gradient(top,#f8f8f8,#ececec);background-image:-moz-linear-gradient(top,#f8f8f8,#ececec);background-image:-ms-linear-gradient(top,#f8f8f8,#ececec);background-image:-o-linear-gradient(top,#f8f8f8,#ececec);background-image:linear-gradient(top,#f8f8f8,#ececec);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#f8f8f8',EndColorStr='#ececec');border:1px solid #c6c6c6;-moz-border-radius:2px;-o-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;padding:0 10px;position:relative}#gbgsi{background:url(//ssl.gstatic.com/gb/images/j_40368b96.png);background-position:0 -281px;height:10px;opacity:.8;filter:alpha(opacity=80);position:absolute;top:8px;_top:10px;width:10px;left:10px}#gbgsa{background:url(//ssl.gstatic.com/gb/images/j_40368b96.png);background-position:0 -53px;height:11px;margin-left:-2px;position:absolute;top:8px;width:10px;left:100%}.gbgt-hvr #gbgsa{background-position:-285px 0}#gbg3:active #gbgsa{background-position:0 -37px}.gbgt-hvr #gbgsi{opacity:1;filter:alpha(opacity=100)}#gbi3{padding-left:18px;vertical-align:top;zoom:1}.gbgt-hvr #gbgs3,#gbg3:focus #gbgs3,#gbg3:active #gbgs3{background-color:#ffffff;background-image:-webkit-gradient(linear,left top,left bottom,from(#ffffff),to(#ececec));background-image:-webkit-linear-gradient(top,#ffffff,#ececec);background-image:-moz-linear-gradient(top,#ffffff,#ececec);background-image:-ms-linear-gradient(top,#ffffff,#ececec);background-image:-o-linear-gradient(top,#ffffff,#ececec);background-image:linear-gradient(top,#ffffff,#ececec);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffffff',EndColorStr='#ececec');border-color:#bbb}#gbg3:active #gbgs3{border-color:#b6b6b6}#gbg3:active #gbgs3{-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.2);box-shadow:inset 0 1px 2px rgba(0,0,0,.2)}#gbgs3 .gbmab{margin:39px 0 0}#gbgs3 .gbmac{margin:40px 0 0}#gbgs1{display:block;overflow:hidden;position:relative}#gbi1a{background-color:#d14836;background-image:-webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#d14836));background-image:-webkit-linear-gradient(top,#dd4b39,#d14836);background-image:-moz-linear-gradient(top,#dd4b39,#d14836);background-image:-ms-linear-gradient(top,#dd4b39,#d14836);background-image:-o-linear-gradient(top,#dd4b39,#d14836);background-image:linear-gradient(top,#dd4b39,#d14836);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#dd4b39',EndColorStr='#d14836');border:1px solid #c13828;-moz-border-radius:2px;-o-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;display:block;height:27px;width:27px}.gbgt-hvr #gbi1a{background-color:#c53727;background-image:-webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#c53727));background-image:-webkit-linear-gradient(top,#dd4b39,#c53727);background-image:-moz-linear-gradient(top,#dd4b39,#c53727);background-image:-ms-linear-gradient(top,#dd4b39,#c53727);background-image:-o-linear-gradient(top,#dd4b39,#c53727);background-image:linear-gradient(top,#dd4b39,#c53727);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#dd4b39',EndColorStr='#c53727');border-color:#b0281a;border-bottom-color:#af301f;-moz-box-shadow:0 1px 1px rgba(0,0,0,.2);-webkit-box-shadow:0 1px 1px rgba(0,0,0,.2);box-shadow:0 1px 1px rgba(0,0,0,.2)}#gbg1:focus #gbi1a,#gbg1:active #gbi1a{background-color:#b0281a;background-image:-webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#b0281a));background-image:-webkit-linear-gradient(top,#dd4b39,#b0281a);background-image:-moz-linear-gradient(top,#dd4b39,#b0281a);background-image:-ms-linear-gradient(top,#dd4b39,#b0281a);background-image:-o-linear-gradient(top,#dd4b39,#b0281a);background-image:linear-gradient(top,#dd4b39,#b0281a);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#dd4b39',EndColorStr='#b0281a');border-color:#992a1b;-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.3);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.3);box-shadow:inset 0 1px 2px rgba(0,0,0,.3)}.gbid#gbi1a{background-color:#f8f8f8;background-image:-webkit-gradient(linear,left top,left bottom,from(#f8f8f8),to(#ececec));background-image:-webkit-linear-gradient(top,#f8f8f8,#ececec);background-image:-moz-linear-gradient(top,#f8f8f8,#ececec);background-image:-ms-linear-gradient(top,#f8f8f8,#ececec);background-image:-o-linear-gradient(top,#f8f8f8,#ececec);background-image:linear-gradient(top,#f8f8f8,#ececec);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#f8f8f8',EndColorStr='#ececec');border-color:#c6c6c6}.gbgt-hvr .gbid#gbi1a,#gbg1:focus .gbid#gbi1a,#gbg1:active .gbid#gbi1a{background-color:#ffffff;background-image:-webkit-gradient(linear,left top,left bottom,from(#ffffff),to(#ececec));background-image:-webkit-linear-gradient(top,#ffffff,#ececec);background-image:-moz-linear-gradient(top,#ffffff,#ececec);background-image:-ms-linear-gradient(top,#ffffff,#ececec);background-image:-o-linear-gradient(top,#ffffff,#ececec);background-image:linear-gradient(top,#ffffff,#ececec);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffffff',EndColorStr='#ececec');border-color:#bbb}#gbg1:active .gbid#gbi1a{border-color:#b6b6b6;-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.3);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.3);box-shadow:inset 0 1px 2px rgba(0,0,0,.3)}#gbi1,#gbi1c{left:0;bottom:1px;color:#fff;display:block;font-size:14px;font-weight:bold;position:absolute;text-align:center;text-shadow:0 1px rgba(0,0,0,.1);-moz-transition-property:bottom;-moz-transition-duration:0;-o-transition-property:bottom;-o-transition-duration:0;-webkit-transition-property:bottom;-webkit-transition-duration:0;-moz-user-select:none;-o-user-select:none;-webkit-user-select:none;user-select:none;width:100%}.gbgt-hvr #gbi1,#gbg1:focus #gbi1{text-shadow:0 1px rgba(0,0,0,.3)}.gbids#gbi1,.gbgt-hvr .gbids#gbi1,#gbg1:focus .gbids#gbi1,#gbg1:active .gbids#gbi1{color:#999;text-shadow:none}#gbg1 .gbmab{margin:40px 0 0}#gbg1 .gbmac{margin:41px 0 0}#gbi4t{display:block;margin:1px 0;overflow:hidden;text-overflow:ellipsis}#gbg6 #gbi4t,#gbg4 #gbgs4d{color:#666;text-shadow:none}#gb_70 #gbi4t,#gbg7 .gbit{margin:0 15px}#gbg7 .gbgs{margin-left:10px}#gbgs4,.gbgs{background-color:#f8f8f8;background-image:-webkit-gradient(linear,left top,left bottom,from(#f8f8f8),to(#ececec));background-image:-webkit-linear-gradient(top,#f8f8f8,#ececec);background-image:-moz-linear-gradient(top,#f8f8f8,#ececec);background-image:-ms-linear-gradient(top,#f8f8f8,#ececec);background-image:-o-linear-gradient(top,#f8f8f8,#ececec);background-image:linear-gradient(top,#f8f8f8,#ececec);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#f8f8f8',EndColorStr='#ececec');border:1px solid #c6c6c6;display:block;-moz-border-radius:2px;-o-border-radius:2px;-webkit-border-radius:2px;border-radius:2px}#gbgs4d{display:block;position:relative}#gbgs4dn{display:inline-block;overflow:hidden;text-overflow:ellipsis}.gbgt-hvr #gbgs4d{background-color:transparent;background-image:none}#gbg4 #gbgs4{position:relative;height:27px;width:27px}.gbgt-hvr #gbgs4,#gbg4:focus #gbgs4,#gbg4:active #gbgs4,#gbg_70:focus #gbgs4,#gbg_70:active #gbgs4,#gbg7:focus .gbgs,#gbg7:active .gbgs{background-color:#ffffff;background-image:-webkit-gradient(linear,left top,left bottom,from(#ffffff),to(#ececec));background-image:-webkit-linear-gradient(top,#ffffff,#ececec);background-image:-moz-linear-gradient(top,#ffffff,#ececec);background-image:-ms-linear-gradient(top,#ffffff,#ececec);background-image:-o-linear-gradient(top,#ffffff,#ececec);background-image:linear-gradient(top,#ffffff,#ececec);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffffff',EndColorStr='#ececec');border-color:#bbb}#gbg4:active #gbgs4,#gb_70:active #gbgs4,#gbg7:active .gbgs{border-color:#b6b6b6;-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.3);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.3);box-shadow:inset 0 1px 2px rgba(0,0,0,.3)}#gbi4i,#gbi4id{left:0;height:27px;position:absolute;top:0;width:27px}#gbmpi,#gbmpid{margin-right:0;height:96px;width:96px}#gbi4id,#gbmpid{background:url(//ssl.gstatic.com/gb/images/j_40368b96.png)}#gbi4id{background-position:-111px -74px}#gbmpid{background-position:-111px -166px}.gbto #gbi4i,.gbto #gbi4id{top:0}#gbgs4 .gbmai{left:33px;top:12px}#gbgs4d .gbmai{left:100%;margin-left:5px;top:12px}#gbgs4 .gbmab{margin:40px 0 0}#gbgs4 .gbmac{margin:41px 0 0}#gbgs4d .gbmab{margin:40px 0 0}#gbgs4d .gbmac{margin:41px 0 0}#gbgs4d .gbmab,#gbgs4d .gbmac{left:50%;margin-left:-5px}.gbmpmtc,.gbp0i{background:url(//ssl.gstatic.com/gb/images/j_40368b96.png);background-position:-256px 0}#gbq1 #gbqla .gbmab,#gbq1 #gbqla .gbmac{left:100%;margin-left:-17px;z-index:1001}#gbq1 .gbmab{border-bottom-color:#bebebe;margin:77px 0 0}#gbq1 .gbmac{border-bottom-color:#2d2d2d;margin:78px 0 0}#gbq1 .gbt{position:static}#gbz{top:-999px;left:-39px}#gbz.gbm{border:1px solid #bebebe}#gbz .gbt{display:block;margin:0}#gbq1.gbto #gbz,#gbq1.gbto #gbs{top:87px !important}#gbq1.gbto{-moz-box-shadow:none;-o-box-shadow:none;-webkit-box-shadow:none;box-shadow:none}#gbq1 .gbts{border:none;border-bottom:1px solid #686868}.gbmasc{border-left:1px solid #e5e5e5;display:inline-block;vertical-align:top}.gbmasc{*display:inline}#gbm1{border:none}#gbd .gbts{border:none}#gbd .gbtb2{border-top:1px solid transparent}#gbq1 #gbz{height:auto;padding-left:0;margin-left:24px}#gbq1 #gbs{margin-left:24px}#gbz .gbts,#gbd .gbts{font-size:12px;font-weight:bold}#gbz .gbts{background:#2d2d2d;color:#fff;overflow:hidden;text-overflow:ellipsis;padding:8px 16px;padding-left:64px;width:112px}#gbd .gbts{background:#fff;color:#333}#gbqlw{cursor:default}#gbqlw:focus{background:rgba(77,144,243,.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.2);box-shadow:inset 0 1px 2px rgba(0,0,0,.2)}#gbqlw:active,#gbqlw.gbgt-hvr{background:none;-moz-box-shadow:none;-webkit-box-shadow:none;box-shadow:none}#gbq1 #gbz .gbzt,#gbq1 #gbz .gbgt,#gbq1 #gbz .gbmt{position:relative}#gbq1 .gbzt-hvr .gbts,#gbq1 .gbzt:focus .gbts,#gbq1 .gbgt-hvr .gbts,#gbq1 .gbgt:focus .gbts{background-color:#4c4c4c;cursor:pointer}#gbq1 .gbmt-hvr,#gbq1 .gbmt:focus,#gbq1 .gbmt-hvr .gbts,#gbq1 .gbmt:focus .gbts{background-color:#f5f5f5;cursor:pointer}#gbd{left:100% !important;border-left:none;overflow:visible;top:-1px !important}#gbd .gbmt,#gbd .gbmc{padding:0}#gbd .gbmasph{display:block;height:43px;width:192px}#gbd .gbmt,#gbd .gbmasph{border-bottom:1px solid #e5e5e5}#gbq1.gbto #gbd{visibility:hidden}#gbtem .gbmt,#gbtem .gbts{background-color:#f5f5f5}#gbtem .gbmt-hvr,#gbtem .gbmt-hvr .gbts{background-color:#f1f1f1}#gbq1 .gbtb2{left:16px;background-image:url(//ssl.gstatic.com/gb/images/j_40368b96.png);background-position:-237px -37px;border-top:none;height:32px;position:absolute;top:6px;width:32px;z-index:1001}#gbqla{font-size:0;line-height:0;position:relative;top:0;vertical-align:top;z-index:1001}#gbq1 #gbz.gbzat,#gbqla.gbqlat{-webkit-transition:opacity .218s;-moz-transition:opacity .218s;-o-transition:opacity .218s;transition:opacity .218s}.gbdat{-webkit-transition:width .4s;-moz-transition:width .4s;-o-transition:width .4s;transition:width .4s;width:0}#gbzb,#gbmb{position:absolute;left:-25px;right:-25px;top:-25px;bottom:-25px}.gbem#gb,.gbemi#gb{height:102px}.gbes#gb,.gbesi#gb{height:102px}.gbem#gbx1,.gbem#gbx2,.gbem#gbqlw,.gbemi#gb #gbx1,.gbemi#gb #gbx2,.gbemi#gb #gbqlw{height:97px}.gbem#gbu,.gbem#gbn,.gbem#gbq2,.gbem#gbq3,.gbemi#gb #gbu,.gbemi#gb #gbn,.gbemi#gb #gbq2,.gbemi#gb #gbq3{padding-bottom:21px;padding-top:20px}.gbem#gbq2,.gbemi#gb #gbq2{margin-left:160px;padding-bottom:0}.gbem#gbq3,.gbemi#gb #gbq3{left:160px}.gbem#gbmail,.gbemi#gb #gbmail{top:46px}.gbes#gbx1,.gbes#gbx2,.gbes#gbqlw,.gbesi#gb #gbx1,.gbesi#gb #gbx2,.gbesi#gb #gbqlw{height:97px}.gbes#gbu,.gbes#gbn,.gbes#gbq2,.gbes#gbq3,.gbesi#gb #gbu,.gbesi#gb #gbn,.gbesi#gb #gbq2,.gbesi#gb #gbq3{padding-bottom:21px;padding-top:20px}.gbes#gbq2,.gbesi#gb #gbq2{margin-left:140px;padding-bottom:0}.gbemi #gbq1.gbto #gbz,.gbemi #gbq1.gbto #gbs,.gbem #gbq1.gbto #gbz,.gbem #gbq1.gbto #gbs{top:87px !important;left:-23px}.gbesi #gbq1.gbto #gbz,.gbesi #gbq1.gbto #gbs,.gbes #gbq1.gbto #gbz,.gbes #gbq1.gbto #gbs{top:87px !important;left:-11px}.gbemi #gbq1 .gbmab,.gbem #gbq1 .gbmab{margin:77px 0 0}.gbemi #gbq1 .gbmac,.gbem #gbq1 .gbmac{margin:78px 0 0}.gbesi #gbq1 .gbmab,.gbes #gbq1 .gbmab{margin:77px 0 0}.gbesi #gbq1 .gbmac,.gbes #gbq1 .gbmac{margin:78px 0 0}.gbemi #gbq1 #gbz,.gbem#gbq1 #gbz,.gbemi #gbq1 #gbs,.gbem#gbq1 #gbs{margin-left:8px}.gbesi #gbq1 #gbz,.gbes#gbq1 #gbz,.gbesi #gbq1 #gbs,.gbes#gbq1 #gbs{margin-left:-4px}.gbes#gbq3,.gbesi#gb #gbq3{left:140px}.gbem#gbq1,.gbemi#gb #gbq1{margin-left:28px}.gbem#gbql,.gbemi#gb #gbql,.gbes#gbql,.gbesi#gb #gbql{background-position:-111px -124px;height:37px;width:95px}.gbes#gbq1,.gbesi#gb #gbq1{margin-left:9px}.gbemi#gb .gbqldr,.gbem#gbqlw .gbqldr{max-height:97px}.gbem#gbu,.gbemi#gb #gbu{margin-right:28px}.gbem#gbn,.gbemi#gb #gbn{margin-left:139px}.gbes#gbu,.gbesi#gb #gbu{margin-right:16px}.gbes#gbn,.gbesi#gb #gbn{margin-left:105px}.gbes#gbu .gbt,.gbesi#gb #gbu .gbt{margin-left:6px}.gbesi#gb .gbqldr,.gbes#gbqlw .gbqldr{max-height:97px}.gbes#gbmail,.gbesi#gb #gbmail{top:46px}.gbemi#gb #gbpr,.gbem#gbpr{left:28px}.gbemi#gb .gbqpa,.gbem#gbpr .gbqpa,.gbesi#gb .gbqpa,.gbes#gbpr .gbqpa{width:71px}.gbesi#gb #gbpr,.gbes#gbpr{left:16px}.gbemi#gb #gbd1,.gbemi#gb #gbd3,.gbemi#gb #gbd4,.gbemi#gb #gbs,.gbem#gbd1,.gbem#gbd3,.gbem#gbd4,.gbem#gbs{top:50px}.gbesi#gb #gbd1,.gbesi#gb #gbd3,.gbesi#gb #gbd4,.gbesi#gb #gbs,.gbes#gbd1,.gbes#gbd3,.gbes#gbd4,.gbes#gbs{top:50px}.gbemi#gb #gbg1 .gbmab,.gbem#gbg1 .gbmab,.gbemi#gb #gbg3 .gbmab,.gbem#gbg3 .gbmab,.gbemi#gb #gbgs4 .gbmab,.gbem#gbg4 .gbmab{margin:40px 0 0}.gbemi#gb #gbg1 .gbmac,.gbem#gbg1 .gbmac,.gbemi#gb #gbg3 .gbmac,.gbem#gbg3 .gbmac,.gbemi#gb #gbgs4 .gbmac,.gbem#gbg4 .gbmac{margin:41px 0 0}.gbesi#gb #gbg1 .gbmab,.gbes#gbg1 .gbmab,.gbesi#gb #gbg3 .gbmab,.gbes#gbg3 .gbmab,.gbesi#gb #gbgs4 .gbmab,.gbes#gbg4 .gbmab{margin:40px 0 0}.gbesi#gb #gbg1 .gbmac,.gbes#gbg1 .gbmac,.gbesi#gb #gbg3 .gbmac,.gbes#gbg3 .gbmac,.gbesi#gb #gbgs4 .gbmac,.gbes#gbg4 .gbmac{margin:41px 0 0}.gbemi#gb #gbgs4d .gbmab,.gbem#gbg4 #gbgs4d .gbmab{margin:40px 0 0}.gbesi#gb #gbgs4d .gbmab,.gbes#gbg4 #gbgs4d .gbmab{margin:40px 0 0}.gbemi#gb #gbgs4d .gbmac,.gbem#gbg4 #gbgs4d .gbmac{margin:41px 0 0}.gbesi#gb #gbgs4d .gbmac,.gbes#gbg4 #gbgs4d .gbmac{margin:41px 0 0}.gbemi#gb #gbgs4d .gbmac,.gbem#gbg4 #gbgs4d .gbmac,.gbesi#gb #gbgs4d .gbmac,.gbes#gbg4 #gbgs4d .gbmac,.gbemi#gb #gbgs4d .gbmab,.gbem#gbg4 #gbgs4d .gbmab,.gbesi#gb #gbgs4d .gbmab,.gbes#gbg4 #gbgs4d .gbmab{margin-left:-5px}.gbemi#gb .gbmwca,.gbem#gb .gbmwca{top:94px}.gbesi#gb .gbmwca,.gbes#gb .gbmwca{top:94px}#gbx3,#gbx4{background-color:#f1f1f1;border-bottom-color:#f1f1f1;height:4px;min-width:980px;}#gbq,#gbv,#gbn,#gbx1,#gbx2{top:4px}#gb{height:106px}.gbem#gb,.gbemi#gb{height:102px}.gbes#gb,.gbesi#gb{height:102px}</style><style id=gstyle>body{margin:0;overflow-y:scroll}#gog{padding:3px 8px 0}.gac_m td{line-height:17px}body,td,a,p,.h{font-family:arial,sans-serif}.h{color:#12c;font-size:20px}.q{color:#00c}.ts td{padding:0}.ts{border-collapse:collapse}em{font-weight:bold;font-style:normal}.lst{height:20px;width:496px}.ds{display:-moz-inline-box;display:inline-block}span.ds{border-bottom:solid 1px #e7e7e7;border-right:solid 1px #e7e7e7;margin:3px 0 4px;margin-left:4px}.ctr-p{margin:0 auto;min-width:980px}.jhp input[type="submit"]{background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#f1f1f1));background-image:-webkit-linear-gradient(top,#f5f5f5,#f1f1f1);-webkit-border-radius:2px;-webkit-user-select:none;background-color:#f5f5f5;background-image:linear-gradient(top,#f5f5f5,#f1f1f1);background-image:-o-linear-gradient(top,#f5f5f5,#f1f1f1);border:1px solid #dcdcdc;border:1px solid rgba(0, 0, 0, 0.1);border-radius:2px;color:#666;cursor:default;font-family:arial,sans-serif;font-size:11px;font-weight:bold;height:29px;line-height:27px;margin:11px 6px;min-width:54px;padding:0 8px;text-align:center}.jhp input[type="submit"]:hover{background-image:-webkit-gradient(linear,left top,left bottom,from(#f8f8f8),to(#f1f1f1));background-image:-webkit-linear-gradient(top,#f8f8f8,#f1f1f1);-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.1);background-color:#f8f8f8;background-image:linear-gradient(top,#f8f8f8,#f1f1f1);background-image:-o-linear-gradient(top,#f8f8f8,#f1f1f1);border:1px solid #c6c6c6;box-shadow:0 1px 1px rgba(0,0,0,0.1);color:#333}.jhp input[type="submit"]:focus{border:1px solid #4d90fe;outline:none}input{font-family:inherit}a.gb1,a.gb2,a.gb3,a.gb4{color:#11c !important}body{background:#fff;color:#222}a{color:#12c;text-decoration:none}a:hover,a:active{text-decoration:underline}.fl a{color:#12c}a:visited{color:#61c}a.gb1,a.gb4{text-decoration:underline}a.gb3:hover{text-decoration:none}#ghead a.gb2:hover{color:#fff!important}.sblc{padding-top:5px}.sblc a{display:block;margin:2px 0;margin-left:13px;font-size:11px;}.lsbb{height:30px;display:block}.ftl,#footer a{color:#666;margin:2px 10px 0}#footer a:active{color:#d14836}.lsb{border:none;color:#000;cursor:pointer;height:30px;margin:0;outline:0;font:15px arial,sans-serif;vertical-align:top}.lst:focus{outline:none}#addlang a{padding:0 3px}.gac_v div{display:none}.gac_v .gac_v2,.gac_bt{display:block!important}body,html{font-size:small}h1,ol,ul,li{margin:0;padding:0}.nojsb{display:none}.nojsv{visibility:hidden}#body,#footer{display:block}#footer{font-size:10pt;min-height:49px;position:relative}#footer>div{border-top:1px solid #ebebeb;bottom:0;padding-top:3px;position:absolute;width:100%}#flci{float:left;margin-left:-260px;text-align:left;width:260px}#fll{float:right;text-align:right;width:100%}#ftby{padding-left:260px}#ftby>div,#fll>div,#footer a{display:inline-block}@media only screen and (min-width:1222px){#ftby{margin: 0 44px}}.nojsb{display:none}.nojsv{visibility:hidden}.nbcl{background:url(/images/nav_logo99.png) no-repeat -140px -230px;height:11px;width:11px}</style><style>.kpbb,.kprb,.kpgb,.kpgrb{-webkit-border-radius:2px;border-radius:2px;color:#fff}.kpbb:hover,.kprb:hover,.kpgb:hover,.kpgrb:hover{-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.1);box-shadow:0 1px 1px rgba(0,0,0,0.1);color:#fff}.kpbb:active,.kprb:active,.kpgb:active,.kpgrb:active{-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.3);box-shadow:inset 0 1px 2px rgba(0,0,0,0.3)}.kpbb{background-image:-webkit-gradient(linear,left top,left bottom,from(#4d90fe),to(#4787ed));background-image:-webkit-linear-gradient(top,#4d90fe,#4787ed);background-color:#4d90fe;background-image:linear-gradient(top,#4d90fe,#4787ed);border:1px solid #3079ed}.kpbb:hover{background-image:-webkit-gradient(linear,left top,left bottom,from(#4d90fe),to(#357ae8));background-image:-webkit-linear-gradient(top,#4d90fe,#357ae8);background-color:#357ae8;background-image:linear-gradient(top,#4d90fe,#357ae8);border:1px solid #2f5bb7}a.kpbb:link,a.kpbb:visited{color:#fff}.kprb{background-image:-webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#d14836));background-image:-webkit-linear-gradient(top,#dd4b39,#d14836);background-color:#d14836;background-image:linear-gradient(top,#dd4b39,#d14836);border:1px solid #d14836}.kprb:hover{background-image:-webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#c53727));background-image:-webkit-linear-gradient(top,#dd4b39,#c53727);background-color:#c53727;background-image:linear-gradient(top,#dd4b39,#c53727);border:1px solid #b0281a;border-color-bottom:#af301f}.kprb:active{background-image:-webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#b0281a));background-image:-webkit-linear-gradient(top,#dd4b39,#b0281a);background-color:#b0281a;background-image:linear-gradient(top,#dd4b39,#b0281a);}.kpgb{background-image:-webkit-gradient(linear,left top,left bottom,from(#3d9400),to(#398a00));background-image:-webkit-linear-gradient(top,#3d9400,#398a00);background-color:#3d9400;background-image:linear-gradient(top,#3d9400,#398a00);border:1px solid #29691d;}.kpgb:hover{background-image:-webkit-gradient(linear,left top,left bottom,from(#3d9400),to(#368200));background-image:-webkit-linear-gradient(top,#3d9400,#368200);background-color:#368200;background-image:linear-gradient(top,#3d9400,#368200);border:1px solid #2d6200}.kpgrb{background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#f1f1f1));background-image:-webkit-linear-gradient(top,#f5f5f5,#f1f1f1);background-color:#f5f5f5;background-image:linear-gradient(top,#f5f5f5,#f1f1f1);border:1px solid #dcdcdc;color:#555}.kpgrb:hover{background-image:-webkit-gradient(linear,left top,left bottom,from(#f8f8f8),to(#f1f1f1));background-image:-webkit-linear-gradient(top,#f8f8f8,#f1f1f1);background-color:#f8f8f8;background-image:linear-gradient(top,#f8f8f8,#f1f1f1);border:1px solid #dcdc;color:#333}a.kpgrb:link,a.kpgrb:visited{color:#555}#gbqfq{padding:1px 0 0 9px}.gl{white-space:nowrap}.big .tsf-p{padding-left:220px;padding-right:260px}.tsf-p{padding-left:140px;padding-right:32px}.fade #center_col,.fade #rhs,.fade #leftnav{filter:alpha(opacity=33.3);opacity:0.333}.fade-hidden #center_col,.fade-hidden #rhs,.fade-hidden #leftnav{visibility:hidden}.flt,.flt u,a.fl{text-decoration:none}.flt:hover,.flt:hover u,a.fl:hover{text-decoration:underline}#knavm{color:#4273db;display:inline;font:11px arial,sans-serif!important;left:-13px;position:absolute;top:2px;z-index:2}#pnprev #knavm{bottom:1px;top:auto}#pnnext #knavm{bottom:1px;left:40px;top:auto}a.noline{outline:0}</style><script>var _gjwl=location;function _gjuc(){var b=_gjwl.href.indexOf("#");if(b>=0){var a=_gjwl.href.substring(b+1);if(/(^|&)q=/.test(a)&&a.indexOf("#")==-1&&!/(^|&)cad=h($|&)/.test(a)){_gjwl.replace("/search?"+a.replace(/(^|&)fp=[^&]*/g,"")+"&cad=h");return 1}}return 0}function _gjp(){!(window._gjwl.hash&&window._gjuc())&&setTimeout(_gjp,500)}; | |
window.rwt=function(a,f,g,l,m,h,c,n,i){return true}; | |
(function(){try{var e=true,i=false,aa={B:1,D:2,R:3,v:4,M:5,G:6,a:7,h:8,V:9,L:10,F:11,j:12,K:13,i:14,J:15,I:16,T:17,z:18,H:19,U:20,S:21,w:22,C:23,X:24,Y:25,W:26,A:27,k:28,u:29,o:30,Q:31,N:32,O:33,c:500,P:501};var m=window.gbar=window.gbar||{};function _tvn(a,b){var c=parseInt(a,10);return isNaN(c)?b:c}function _tvf(a,b){var c=parseFloat(a);return isNaN(c)?b:c}function _tvv(a){return!!a}function n(a,b,c){(c||m)[a]=b}m.bv={n:_tvn("2",0),r:"r_gc.r_pw.",f:".36.37.40.",m:_tvn("2",1)};var o=function(a){return function(){return m.bv.m==a}},ba=o(1),ca=o(2);n("sb",ba);n("kn",ca);var p={},da={},q=[],ga=function(a,b){q.push([a,b])},ja=function(a,b){p[a]=b},ka=function(a){return a in p},r={},t=function(a,b){r[a]||(r[a]=[]);r[a].push(b)},u=function(a){t("m",a)},v=function(a){var b=document.createElement("script");b.src=a;(document.getElementById("xjsc")||document.body).appendChild(b)},x=function(a){for(var b=0,c;c=q[b];++b)if(c[0]==a)break;if(c&&!c[1].l&&!c[1].s){c[1].s=e;w(2,a);v(c[1].url)}},y=function(a){t("gc",a)},z=null,la=function(a){z=a},w=function(a,b,c){if(z){a={t:a, | |
b:b};if(c)for(var d in c)a[d]=c[d];try{z(a)}catch(g){}}};n("mdc",p);n("mdi",da);n("bnc",q);n("qGC",y);n("qm",u);n("qd",r);n("lb",x);n("mcf",ja);n("bcf",ga);n("aq",t);n("mdd","");n("has",ka);n("trh",la);n("tev",w);var A=function(){},B=function(){},E=function(a){var b=new Image,c=C;b.onerror=b.onload=b.onabort=function(){try{delete D[c]}catch(d){}};D[c]=b;b.src=a;C=c+1},D=[],C=0;n("logger",{il:B,ml:A});var F=window.gbar.logger;var G=_tvf("0.5",1.0E-4),H=0; | |
function _mlToken(a,b){try{if(H<1){H++;var c,d=a,g=b||{},f=encodeURIComponent,h=["//www.google.com/gen_204?atyp=i&zx=",(new Date).getTime(),"&jexpid=",f("35387"),"&srcpg=",f("prop=1"),"&jsr=",Math.round(1/G),"&ogf=",m.bv.f,"&ogv=",f("1324001618.1324332217"),"&ogd=",f("com"),"&ogl=",f("en")];if(g._sn)g._sn="og."+g._sn;for(var l in g){h.push("&");h.push(f(l));h.push("=");h.push(f(g[l]))}h.push("&emsg=");h.push(f(d.name+ | |
":"+d.message));var j=h.join("");if(I(j))j=j.substr(0,2E3);c=j;var k=window.gbar.logger._aem(a,c);E(k)}}catch(s){}}var I=function(a){return a.length>=2E3},ma=function(a,b){return b};function J(a){A=a;n("_itl",I,F);n("_aem",ma,F);n("ml",A,F);a={};p.er=a}if(_tvv(""))J(function(a){throw a;});else _tvv("1")&&Math.random()<G&&J(_mlToken);var _E="left",N=function(a,b){var c=a.className;K(a,b)||(a.className+=(c!=""?" ":"")+b)},O=function(a,b){var c=a.className,d=RegExp("\\s?\\b"+b+"\\b");if(c&&c.match(d))a.className=c.replace(d,"")},K=function(a,b){var c=RegExp("\\b"+b+"\\b"),d=a.className;return!!(d&&d.match(c))};n("ca",N);n("cr",O);n("cc",K);var na=["gb_71","gb_155"],P;function oa(a){P=a}function pa(a){var b=P&&!a.href.match(/.*\/accounts\/ClearSID[?]/)&&encodeURIComponent(P());if(b)a.href=a.href.replace(/([?&]continue=)[^&]*/,"$1"+b)}function qa(a){try{var b=(document.forms[0].q||"").value;if(b)a.href=a.href.replace(/([?&])q=[^&]*|$/,function(d,g){return(g||"&")+"q="+encodeURIComponent(b)})}catch(c){A(c)}} | |
var ra=function(){for(var a=[],b=0,c;c=na[b];++b)(c=document.getElementById(c))&&a.push(c);return a},sa=function(){var a=ra();return a.length>0?a[0]:null},ta=function(){return document.getElementById("gb_70")},Q={},R={},S={},T=undefined,ya=function(a,b){try{var c=document.getElementById("gb");N(c,"gbpdjs");U();ua(document.body)&&N(c,"gbrtl");if(b&&b.getAttribute){var d=b.getAttribute("aria-owns");if(d.length){var g=document.getElementById(d);if(g){var f=b.parentNode;if(T==d){T=undefined;O(f,"gbto")}else{if(T){var h= | |
document.getElementById(T);if(h&&h.getAttribute){var l=h.getAttribute("aria-owner");if(l.length){var j=document.getElementById(l);j&&j.parentNode&&O(j.parentNode,"gbto")}}}va(g)&&wa(g);T=d;N(f,"gbto")}}}}u(function(){m.tg(a,b,e)});xa(a)}catch(k){A(k)}},za=function(a){u(function(){m.close(a)})},ua=function(a){var b,c="direction",d=document.defaultView;if(d&&d.getComputedStyle){if(a=d.getComputedStyle(a,""))b=a[c]}else b=a.currentStyle?a.currentStyle[c]:a.style[c];return b=="rtl"},Ba=function(a,b,c){if(a)try{var d= | |
document.getElementById("gbd5");if(d){var g=d.firstChild,f=g.firstChild,h=document.createElement("li");h.className=b+" gbmtc";h.id=c;a.className="gbmt";h.appendChild(a);if(f.hasChildNodes()){c=[["gbkc"],["gbf","gbe","gbn"],["gbkp"],["gbnd"]];d=0;var l=f.childNodes.length;g=i;for(var j=-1,k=0,s;s=c[k];k++){for(var ea=0,L;L=s[ea];ea++){for(;d<l&&K(f.childNodes[d],L);)d++;if(L==b){f.insertBefore(h,f.childNodes[d]||null);g=e;break}}if(g){if(d+1<f.childNodes.length){var fa=f.childNodes[d+1];if(!K(fa.firstChild, | |
"gbmh")&&!Aa(fa,s))j=d+1}else if(d-1>=0){var ha=f.childNodes[d-1];if(!K(ha.firstChild,"gbmh")&&!Aa(ha,s))j=d}break}d>0&&d+1<l&&d++}if(j>=0){var M=document.createElement("li"),ia=document.createElement("div");M.className="gbmtc";ia.className="gbmt gbmh";M.appendChild(ia);f.insertBefore(M,f.childNodes[j])}m.addHover&&m.addHover(a)}else f.appendChild(h)}}catch(Ja){A(Ja)}},Aa=function(a,b){for(var c=b.length,d=0;d<c;d++)if(K(a,b[d]))return e;return i},Ca=function(a,b,c){Ba(a,b,c)},Da=function(a,b){Ba(a, | |
"gbe",b)},Ea=function(){u(function(){m.pcm&&m.pcm()})},Fa=function(a,b,c,d,g,f,h,l){u(function(){m.paa&&m.paa(a,b,c,d,g,f,h,l)})},Ga=function(a,b){Q[a]||(Q[a]=[]);Q[a].push(b)},Ha=function(a,b){R[a]||(R[a]=[]);R[a].push(b)},Ia=function(a,b){S[a]||(S[a]=[]);S[a].push(b)},xa=function(a){a.preventDefault&&a.preventDefault();a.returnValue=i;a.cancelBubble=e},V=null,wa=function(a,b){U();if(a){W(a,"Opening…");X(a,e);var c=typeof b!="undefined"?b:1E4,d=function(){Ka(a)};V=window.setTimeout(d, | |
c)}},La=function(a){U();if(a){X(a,i);W(a,"")}},Ka=function(a){try{U();var b=a||document.getElementById(T);if(b){W(b,"This service is currently unavailable.%1$sPlease try again later.","%1$s");X(b,e)}}catch(c){A(c)}},W=function(a,b,c){if(a&&b){var d=va(a);if(d){if(c){d.innerHTML="";b=b.split(c);c=0;for(var g;g=b[c];c++){var f=document.createElement("div");f.innerHTML=g;d.appendChild(f)}}else d.innerHTML=b;X(a,e)}}},X=function(a,b){var c=b!==undefined?b:e;c?N(a,"gbmsgo"):O(a,"gbmsgo")},va=function(a){for(var b=0,c;c=a.childNodes[b];b++)if(K(c, | |
"gbmsg"))return c},U=function(){V&&window.clearTimeout(V)};n("so",sa);n("sos",ra);n("si",ta);n("tg",ya);n("close",za);n("addLink",Ca);n("addExtraLink",Da);n("pcm",Ea);n("paa",Fa);n("ddld",wa);n("ddrd",La);n("dderr",Ka);n("rtl",ua);n("bh",Q);n("abh",Ga);n("dh",R);n("adh",Ha);n("ch",S);n("ach",Ia);n("qs",qa);n("setContinueCb",oa);n("pc",pa);var Ma={};p.base=Ma;q.push(["m",{url:"//ssl.gstatic.com/gb/js/sem_728e1cab3e01f4b707f65ca7ca9abe9a.js"}]);var Na=_tvn("1",0),Oa=/\bgbmt\b/,Pa=function(a){if(Oa.test(a.className))return"gbm0l";return"gbz0l"},Qa=function(a){try{var b=document.getElementById("gb_"+Na),c=document.getElementById("gb_"+a);b&&O(b,Pa(b));c&&N(c,Pa(c))}catch(d){A(d)}Na=a},Ra=m.qs,Sa=function(a){var b;b=a.href;var c=window.location.href.match(/.*?:\/\/[^\/]*/)[0];c=RegExp("^"+c+"/search\\?");if(b=c.test(b))if(!/(^|\\?|&)ei=/.test(a.href))if((b=window.google)&&b.kEXPI)a.href+="&ei="+b.kEI},Ta=function(a){Ra(a); | |
Sa(a)};n("slp",Qa);n("qs",Ta);n("qsi",Sa);if(_tvv("1")){var Ua=_tvv("");q.push(["gc",{auto:Ua,url:"https://ssl.gstatic.com/gb/js/abc/gcm_e9b1c8ddbdbba9ea5c035548a0320af1.js"}]);var Va={version:"gcm_e9b1c8ddbdbba9ea5c035548a0320af1.js",index:"",lang:"en"};p.gc=Va;var Y=function(a){if(window.googleapis)a&&a();else{a&&y(a);x("gc")}};n("lGC",Y);_tvv("1")&&n("lPWF",Y)};window.__PVT="";var Wa=_tvf("0.5",1.0E-4),Xa=_tvf("0.5",1),Z=aa;function Ya(a){if(a<=Z.i){if(a==Z.a||a==Z.h||a==Z.j)return i;return e}else if(a>=Z.c)return e;return i} | |
function Za(a,b){var c=Wa;if(Ya(a))c=Xa;if(_tvv("1")&&Math.random()<=c){var d=encodeURIComponent;c=["//www.google.com/gen_204?atyp=i&zx=",(new Date).getTime(),"&oge=",a,"&ogex=",d("35387"),"&ogf=",m.bv.f,"&ogp=",d("1"),"&ogsr=",Math.round(1/c),"&ogv=",d("1324001618.1324332217"),"&ogd=",d("com"),"&ogl=",d("en")];if(b){if("ogw"in b){c.push("&ogw="+b.ogw);delete b.ogw}var g,f=b,h=[];for(g in f){h.length!= | |
0&&h.push(",");h.push(g);h.push(".");h.push(f[g])}g=h.join("");if(g!=""){c.push("&ogad=");c.push(d(g))}}E(c.join(""))}}B=Za;n("il",B,F);var $a={};p.il=$a;var ab=function(){m.prm&&m.prm()},bb=function(a){t("m",function(){m.spn(a)})},cb=function(a){t("m",function(){m.spp(a)})},db=function(){t("m",function(){m.spd()})};n("spn",bb);n("spp",cb);n("spd",db);Ga("gbd4",ab);if(_tvv("")){var eb={g:_tvv(""),d:_tvv(""),e:"",m:"",p:"//ssl.gstatic.com/gb/images/avatar_b96.png",xp:_tvv("1"),mg:"%1$s (delegated)",md:"%1$s (default)"};p.prf=eb};if(_tvv("1")&&_tvv("1")){var $=function(a){Y(function(){t("pw",a);x("pw")})};n("lPW",$);q.push(["pw",{url:"https://ssl.gstatic.com/gb/js/abc/pwm_4e7edac1f189ab82bc4091ff7bfe6f4b.js"}]);var fb=[],gb=function(a){fb[0]=a},hb=function(a,b){var c=b||{};c._sn="pw";A(a,c)},ib={signed:fb,elog:hb,base:"https://plusone.google.com/u/0",loadTime:(new Date).getTime()};p.pw=ib;var jb=function(a,b){for(var c=b.split("."),d=function(){var l=arguments;a(function(){for(var j=m,k=0,s=c.length-1;k<s;++k)j=j[c[k]];j[c[k]].apply(j,l)})},g=m,f=0,h=c.length- | |
1;f<h;++f)g=g[c[f]]=g[c[f]]||{};return g[c[f]]=d};jb($,"pw.clk");jb($,"pw.hvr");n("su",gb,m.pw)};function kb(){function a(){for(var k;k=f[h++];)if(k[0]=="m"||k[1].auto)break;if(k){w(2,k[0]);v(k[1].url)}h<f.length&&setTimeout(a,0)}function b(){g-- >0?setTimeout(b,0):a()}var c=_tvv("1"),d=_tvv(""),g=3,f=q,h=0,l=window.gbarOnReady;if(l)try{l()}catch(j){A(j)}if(d)n("ldb",a);else if(c)window.addEventListener?window.addEventListener("load",b,i):window.attachEvent("onload",b);else b()}n("rdl",kb);}catch(e){window.gbar&&gbar.logger&&gbar.logger.ml(e);}})(); | |
(function(){try{var b=window.gbar,c=function(a,d){b[a]=function(){if(window.navigator&&window.navigator.userAgent)return d(window.navigator.userAgent);return false}},e=function(a){return!(/AppleWebKit\/.+(?:Version\/[35]\.|Chrome\/[01]\.)/.test(a)||a.indexOf("Firefox/3.5.")!=-1)},f=function(a){return a.indexOf("iPad")==-1};c("bs_w",e);c("bs_s",f);}catch(e){window.gbar&&gbar.logger&&gbar.logger.ml(e);}})(); | |
(function(){try{var a=window.gbar;a.mcf("sf",{});}catch(e){window.gbar&&gbar.logger&&gbar.logger.ml(e);}})(); | |
(function(){try{var c=window.gbar,e,h,k=function(a,b){c.logger.ml(a,{_sn:"cfg.es."+b})},o=function(a){return parseInt(a,10)},p=function(a){return document.getElementById(a)};function _tvv(a){return!!a}var s=function(a){var b=Array.prototype.slice.call(arguments,1);return function(){var f=Array.prototype.slice.call(arguments);f.unshift.apply(f,b);return a.apply(this,f)}},t=undefined,x=undefined,y=undefined,z={},A={},F={},G=o("4");z.h=o("98")+G;z.m=o("44"); | |
z.f=o("220");A.h=o("98")+G;A.m=o("28");A.f=o("160");F.h=o("98")+G;F.m=o("16");F.f=o("140"); | |
var H=o("572"),I=o("572"),J=o("220"),K=o("160"),L=o("140"),M=o("15"),N=o("15"),aa=o("6"),ba=o("44"),ca=o("28"),da=o("16"),ea=o("15"),fa=o("980"), | |
ga=["gb","gbq","gbu","gbn","gbpr","gbq2","gbqf","gbq3","gbq1","gbqlw","gbql","gbmail","gbx1","gbx2","gbg1","gbg3","gbg4","gbd1","gbd3","gbd4","gbs","gbwc"],O=[],P=true,R=function(a){try{if(a=="lg")Q("");else if(a=="md")Q("gbem");else a=="sm"&&Q("gbes")}catch(b){k(b,"stem")}},ha=s(R,"lg"),ia=s(R,"md"),ja=s(R,"sm"),W=function(a){try{R(a);var b=T("Height"),f=T("Width"),d=z;if(a=="sm")d=F;else if(a=="md")d=A;U(b,f,a,d);V()}catch(l){k(l,"seme")}},ka=function(a){try{O.push(a)}catch(b){k(b,"roec")}},X=function(){try{for(var a= | |
0,b;b=O[a];++a)b(e)}catch(f){k(f,"eoec")}},la=function(a){try{return P=a}catch(b){k(b,"ear")}},T=function(a){var b="inner"+a;a="offset"+a;if(window[b])return window[b];else if(document.documentElement&&document.documentElement[a])return document.documentElement[a];return 0},Y=function(){var a=T("Height"),b=T("Width"),f=z,d="lg";if(b<1060||a<590){d="sm";f=F}else if(b<1252||a<640){d="md";f=A}U(a,b,d,f);return d},V=function(){try{var a=p("gbx1");if(a){var b=c.rtl(document.body),f=a.clientWidth;a=f<= | |
fa;var d=p("gb_70");if(!t)if(d)t=d.clientWidth;else{var l=p("gbg6");if(l)t=l.clientWidth;else{var i=p("gbg4");if(i)t=i.clientWidth;else return}}if(!x){var m=p("gbg3");if(m)x=m.clientWidth}var g=e.mo;l=ba;i=M;var u=J;if(g=="md"){l=ca;i=N;u=K}else if(g=="sm"){l=da;i=aa;u=L}var n=c.snw&&c.snw();if(n)u+=n+i;n=t;var q=p("gbg1");if(q)n+=q.clientWidth+i;if(m=p("gbg3"))n+=x+i;var v=p("gbg4"),w=p("gbgs4dn");if(v&&!w)n+=v.clientWidth+i;n=Math.min(304,n);u+=l;var D=p("gbqfbw");if(D){D.style.display="";u+=D.clientWidth+ | |
ea*2}g=f-u;var j=p("gbqf"),r=c.gpcc&&c.gpcc();if(j&&!r){r=f-n-u;r=Math.min(r,I);r=Math.max(r,H);j.style.maxWidth=r+"px";g-=r}var B=p("gbi3");if(B)if(j=g<=236){j=b;if(!y)y=B.innerHTML;B.innerHTML="";j="padding"+(j?"Right":"Left");B.style[j]="7px"}else{j=b;if(y){B.innerHTML=y;j="padding"+(j?"Right":"Left");B.style[j]=""}}if(q){q.style.display="";g-=q.clientWidth+i}if(m){m.style.display="";g-=m.clientWidth+i}if(v&&!w)g-=v.clientWidth+i;v=w?0:35;var E=w||p("gbi4t");if(E&&!d){if(g>v){E.style.display=""; | |
E.style.maxWidth=g+"px"}else E.style.display="none";var S=p("gbg6");if(S)S.style.width=g<t&&g>v?g+"px":"";w="left";if(t>g^b)w="right";E.style.textAlign=w}if(m)if(g<0){g+=m.clientWidth;m.style.display="none"}if(q)if(g<0){g+=q.clientWidth;q.style.display="none"}if(D)if(g<0||d&&g<d.clientWidth)D.style.display="none";d=b?"right":"left";b=b?"left":"right";var C=p("gbu"),ma=C.style[d]!="";if(a){C.style[d]=f-C.clientWidth-l+"px";C.style[b]="auto"}else{C.style[d]="";C.style[b]=""}a!=ma&&c.swsc&&c.swsc(a)}}catch(na){k(na, | |
"cb")}},U=function(a,b,f,d){e={};e.mo=f;e.vh=a;e.vw=b;e.es=d;f!=h&&X()},oa=function(a){z.h+=a;A.h+=a;F.h+=a},pa=function(){return e},qa=function(){try{if(P==true){var a=h;h=Y();if(a!=h){switch(h){case "sm":ja();break;case "md":ia();break;default:ha()}c.close()}}V()}catch(b){k(b,"sem")}},Q=function(a){var b=p("gb");if(b){c.cr(b,"");c.cr(b,"gbemi");c.cr(b,"gbesi")}b=[];for(var f=0,d;d=ga[f];f++)if(d=p(d)){if(a=="gbem"){c.cr(d,"");c.cr(d,"gbes");c.ca(d,a)}if(a=="gbes"){c.cr(d,"");c.cr(d,"gbem");c.ca(d, | |
a)}if(a==""){c.cr(d,"gbem");c.cr(d,"gbes");c.ca(d,a)}b.push(d)}return b},$=function(){try{if(P==true){h=Y();switch(h){case "sm":Z("gbesi");break;case "md":Z("gbemi");break;default:Z("")}}V()}catch(a){k(a,"semol")}},Z=function(a){var b=p("gb");b&&c.ca(b,a)};c.eli=$;c.elg=qa;c.ell=s(W,"lg");c.elm=s(W,"md");c.els=s(W,"sm");c.elr=pa;c.elc=ka;c.elx=X;c.elh=oa;c.ela=la;c.elp=V;c.upel=s(W,"lg");c.upes=s(W,"md");c.upet=s(W,"sm");$();c.mcf("el",{});}catch(e){window.gbar&&gbar.logger&&gbar.logger.ml(e);}})(); | |
(function(){try{var a=window.gbar;a.mcf("as",{});}catch(e){window.gbar&&gbar.logger&&gbar.logger.ml(e);}})(); | |
(function(){try{var a=window.gbar,d=function(){return document.getElementById("gbqfqw")},h=function(){return document.getElementById("gbqfq")},i=function(){return document.getElementById("gbqf")},j=function(){return document.getElementById("gbqfb")},l=function(b){var c=document.getElementById("gbqfaa");c.appendChild(b);k()},m=function(b){var c=document.getElementById("gbqfab");c.appendChild(b);k()},k=function(){var b=document.getElementById("gbqfqwb");if(b){var c=document.getElementById("gbqfaa"),e=document.getElementById("gbqfab"); | |
if(c||e){var f="left",g="right";if(a.rtl(document.body)){f="right";g="left"}if(c)b.style[f]=c.offsetWidth+"px";if(e)b.style[g]=e.offsetWidth+"px"}}},n=function(b){a.qm(function(){a.qfhi(b)})};a.qfgw=d;a.qfgq=h;a.qfgf=i;a.qfas=l;a.qfae=m;a.qfau=k;a.qfhi=n;a.qfsb=j;}catch(e){window.gbar&&gbar.logger&&gbar.logger.ml(e);}})(); | |
(function(){try{var a=window.gbar,d=a.logger.ml,f=["gbq1","gbq2","gbpr","gbqfbwa","gbn","gbx1","gbx2"],h=true,i=function(b){var c=document.getElementById("gbqld");if(c){c.style.display=b?"none":"block";if(c=document.getElementById("gbql"))c.style.display=b?"block":"none"}},j=function(){try{for(var b=0,c;c=f[b];b++){var e=document.getElementById(c);e&&a.ca(e,"gbqfh")}h&&a.gpoas();a.elp&&a.elp();i(true)}catch(g){d(g)}},k=function(){try{for(var b=0,c;c=f[b];b++){var e=document.getElementById(c);e&&a.cr(e,"gbqfh")}h&& | |
a.gpcas();a.elp&&a.elp();i(false)}catch(g){d(g)}},l=function(b){var c=document.getElementById("gbq1");if(c){a[b](c,"gbto");a[b](c,"gbtoc")}},m=function(){try{l("ca");a.qm(function(){a.gpoas()})}catch(b){d(b)}},n=function(){try{l("cr");a.qm(function(){a.gpcas()})}catch(b){d(b)}},o=function(){try{var b=document.getElementById(f[0]);return b&&a.cc(b,"gbqfh")}catch(c){d(c)}};a.gpca=j;a.gpcr=k;a.gpcc=o;a.gpoas=m;a.gpcas=n;}catch(e){window.gbar&&gbar.logger&&gbar.logger.ml(e);}})(); | |
(function(){try{var a=window.gbar,c=a.logger.ml,f=function(d){try{var b=document.getElementById("gbom");b&&d.appendChild(b.cloneNode(true))}catch(e){c(e)}};a.aomc=f;}catch(e){window.gbar&&gbar.logger&&gbar.logger.ml(e);}})(); | |
(function(){try{window.gbar.rdl();}catch(e){window.gbar&&gbar.logger&&gbar.logger.ml(e);}})(); | |
</script><script src="http://box2dweb.googlecode.com/svn/trunk/Box2D.js"></script><script src="https://raw.github.com/gist/1579671/rAF.js"></script><script src="https://raw.github.com/gist/3225993/loop.js"></script><script src="http://code.jquery.com/jquery-latest.js"></script></head><body id=gsr bgcolor=#ffffff text=#222222 link=#1122cc vlink=#6611cc alink=#d14836 onload="try{if(!google.j.b){document.f&&document.f.q.focus();document.gbqf&&document.gbqf.q.focus()}}catch(e){};if(document.images)new Image().src='/images/nav_logo99.png'" ><div id=pocs style=visibility:hidden;position:absolute><div id=pocs0>Google Instant is unavailable. Press Enter to search. <a href="/support/websearch/bin/answer.py?answer=186645&hl=en&form=bb">Learn more</a></div><div id=pocs1>Google Instant is off due to connection speed. Press Enter to search.</div><div id=pocs2>Press Enter to search.</div></div> <a href="/setprefs?prev=https://www.google.com/&sig=0_kI5SExEl5OpdmWpm8-69ERgEQ5A%3D&suggon=2" style="left:-1000em;position:absolute">Screen reader users, click here to turn off Google Instant.</a> <textarea id=csi style=display:none name=csi></textarea><script>if(google.j.b)document.body.style.visibility='hidden';</script><div id=mngb><div id=gb><script>window.gbar&&gbar.eli&&gbar.eli()</script><div id=gbw><div id=gbq><div id=gbq1 class="gbt gbqfh gbto gbtoc"><script>window.google&&google.j&&google.j.b&&gbar.gpcas&&gbar.gpcas()</script><div id=gbqla><span class=gbmab></span><span class=gbmac></span></div><a id=gbqlw class=gbgt href="javascript:void(0)" aria-owns=gbz aria-haspopup=true aria-label='Google Application Switcher' role=button><img id=gbqld src=https://www.google.com/logos/2011/holiday11-sr.png alt="" width=114 height=41><span id=gbql></span><span id=gbmail class=gbmai></span></a><div id=gbz class=gbm aria-owner=gbqlw><div id=gbzb></div><span class=gbtcb></span><ol id=gbzc class=gbtc><li class=gbt><a onclick=gbar.logger.il(1,{t:119}); id=gb_119 href="https://plus.google.com/?tab=wX" class=gbzt><span style="background-position:-111px 0" class=gbtb2></span><span class=gbts>+You</span></a></li><li class=gbt><a onclick=gbar.logger.il(1,{t:1}); id=gb_1 href="https://www.google.com/webhp?hl=en&tab=ww" class="gbzt gbz0l gbp1"><span style="background-position:-266px -124px" class=gbtb2></span><span class=gbts>Search</span></a></li><li class=gbt><a onclick=gbar.qs(this);gbar.logger.il(1,{t:2}); id=gb_2 href="https://www.google.com/imghp?hl=en&tab=wi" class=gbzt><span style="background-position:-37px -207px" class=gbtb2></span><span class=gbts>Images</span></a></li><li class=gbt><a onclick=gbar.qs(this);gbar.logger.il(1,{t:8}); id=gb_8 href="http://maps.google.com/maps?hl=en&tab=wl" class=gbzt><span style="background-position:-148px -267px" class=gbtb2></span><span class=gbts>Maps</span></a></li><li class=gbt><a onclick=gbar.qs(this);gbar.logger.il(1,{t:36}); id=gb_36 href="http://www.youtube.com/?tab=w1" class=gbzt><span style="background-position:-185px -267px" class=gbtb2></span><span class=gbts>YouTube</span></a></li><li class=gbt><a onclick=gbar.logger.il(1,{t:5}); id=gb_5 href="http://news.google.com/nwshp?hl=en&tab=wn" class=gbzt><span style="background-position:-111px -37px" class=gbtb2></span><span class=gbts>News</span></a></li><li class=gbt><a onclick=gbar.logger.il(1,{t:23}); id=gb_23 href="https://mail.google.com/mail/?tab=wm" class=gbzt><span style="background-position:-185px -37px" class=gbtb2></span><span class=gbts>Gmail</span></a></li><li class=gbt><a onclick=gbar.logger.il(1,{t:25}); id=gb_25 href="https://docs.google.com/?tab=wo" class=gbzt><span style="background-position:-192px 0" class=gbtb2></span><span class=gbts>Documents</span></a></li><li class=gbt id=gbtm><a class=gbgt id=gbztm href="http://www.google.com/intl/en/options/" aria-haspopup=true aria-owns=gbd><span id=gbztms class="gbts gbtsa"><span id=gbztms1>More</span></span></a><div class=gbm id=gbd aria-owner=gbztm><div class=gbmc id=gbdi><div id=gbmb></div><div id=gbm1 class=gbmasc><span class=gbmtc><a onclick=gbar.logger.il(1,{t:24}); id=gb_24 href="https://www.google.com/calendar?tab=wc" class=gbmt><span style="background-position:-148px -37px" class=gbtb2></span><span class=gbts>Calendar</span></a></span><span class=gbmtc><a onclick=gbar.qs(this);gbar.logger.il(1,{t:51}); id=gb_51 href="http://translate.google.com/?hl=en&tab=wT" class=gbmt><span style="background-position:-37px 0" class=gbtb2></span><span class=gbts>Translate</span></a></span><span class=gbmtc><a onclick=gbar.logger.il(1,{t:17}); id=gb_17 href="http://www.google.com/mobile/" class=gbmt><span style="background-position:0 0" class=gbtb2></span><span class=gbts>Mobile</span></a></span><span class=gbmtc><a onclick=gbar.qs(this);gbar.logger.il(1,{t:10}); id=gb_10 href="http://books.google.com/bkshp?hl=en&tab=wp" class=gbmt><span style="background-position:-259px -267px" class=gbtb2></span><span class=gbts>Books</span></a></span><span class=gbmtc><a onclick=gbar.logger.il(1,{t:166}); id=gb_166 href="http://music.google.com/" class=gbmt><span style="background-position:0 -244px" class=gbtb2></span><span class=gbts>Music</span></a></span><span class=gbmtc><a onclick=gbar.logger.il(1,{t:172}); id=gb_172 href="https://www.google.com/offers" class=gbmt><span style="background-position:-222px -267px" class=gbtb2></span><span class=gbts>Offers</span></a></span><span class=gbmtc><a onclick=gbar.logger.il(1,{t:212}); id=gb_212 href="https://wallet.google.com/manage/" class=gbmt><span style="background-position:-30px -37px" class=gbtb2></span><span class=gbts>Wallet</span></a></span><span class=gbmtc><a onclick=gbar.qs(this);gbar.logger.il(1,{t:6}); id=gb_6 href="http://www.google.com/prdhp?hl=en&tab=wf" class=gbmt><span style="background-position:-229px -124px" class=gbtb2></span><span class=gbts>Shopping</span></a></span><span class=gbmtc><a onclick=gbar.logger.il(1,{t:30}); id=gb_30 href="http://www.blogger.com/?tab=wj" class=gbmt><span style="background-position:0 -207px" class=gbtb2></span><span class=gbts>Blogger</span></a></span><span class=gbmtc><a onclick=gbar.logger.il(1,{t:32}); id=gb_32 href="http://www.google.com/reader/?hl=en&tab=wy" class=gbmt><span style="background-position:-143px -74px" class=gbtb2></span><span class=gbts>Reader</span></a></span><span class=gbmtc><a onclick=gbar.qs(this);gbar.logger.il(1,{t:27}); id=gb_27 href="http://www.google.com/finance?tab=we" class=gbmt><span style="background-position:-74px -207px" class=gbtb2></span><span class=gbts>Finance</span></a></span><span class=gbmtc><a onclick=gbar.qs(this);gbar.logger.il(1,{t:31}); id=gb_31 href="http://picasaweb.google.com/home?hl=en&tab=wq" class=gbmt><span style="background-position:-111px -267px" class=gbtb2></span><span class=gbts>Photos</span></a></span><span class=gbmtc><a onclick=gbar.qs(this);gbar.logger.il(1,{t:12}); id=gb_12 href="http://video.google.com/?hl=en&tab=wv" class=gbmt><span style="background-position:-67px -37px" class=gbtb2></span><span class=gbts>Videos</span></a></span></div><div class=gbmtc id=gbtem><a onclick=gbar.logger.il(1,{t:66}); href="http://www.google.com/intl/en/options/" class=gbmt><span class=gbts>Even more</span></a></div></div></div></li></ol></div></div><div id=gbq2 class="gbt gbqfh"><div id=gbqfw ><form id=gbqf name=gbqf method=get action="/search" onsubmit="gbar.logger.il(31);"><fieldset id=gbqffh class=gbxx><legend class=gbxx>Hidden fields</legend><div id=gbqffd><input type=hidden name="hl" value="en"><input type=hidden name="output" value="search"><input type=hidden name="sclient" value="psy-ab"></div></fieldset><fieldset id=gbqff><legend id=gbqfl class=gbxx></legend><div id=gbqfqw class=gbqfqw><div id=gbqfqwb><input id=gbqfq class=gbqfif name=q type=text autocomplete=off value="" placeholder=""></div></div><div id=gbqfbw><button id=gbqfb aria-label="Google Search" class=gbqfb name=btnG><span id=gbqfi></span></button></div></fieldset><div id=gbqfbwa class=jsb><button id=gbqfba aria-label="Google Search" name=btnK class="gbqfb gbqfba"><span id=gbqfsa>Google Search</span></button><button id=gbqfbb aria-label="I'm Feeling Lucky" name=btnI class="gbqfb gbqfba" onclick="if(this.form.q.value)this.checked=1;else window.top.location='/logos/'"><span id=gbqfsb>I'm Feeling Lucky</span></button></div></form></div></div></div><div id=gbu><div id=gbvg class=gbvg><h2 class=gbxx>Account Options</h2><span class=gbtcb></span><ol class=gbtc><li class=gbt></li><li class=gbt><a href="https://accounts.google.com/ServiceLogin?hl=en&continue=https://www.google.com/" onclick="gbar.logger.il(9,{l:'i'})" id=gb_70 class=gbgt><span id=gbgs4><span id=gbi4t>Sign in</span></span></a></li><div style="display:none"><div class=gbm id=gbd5 aria-owner=gbg5><div class=gbmc><ol id=gbom class=gbmcc><li class="gbkc gbmtc"><a class=gbmt href="/preferences?hl=en">Search settings</a></li><li class=gbmtc><div class="gbmt gbmh"></div></li><li class="gbe gbmtc"><a id=gmlas class=gbmt href="/advanced_search?hl=en">Advanced search</a></li><li class="gbe gbmtc"><a class=gbmt href="/language_tools?hl=en">Language tools</a></li><li class="gbe gbmtc"><a class=gbmt href="/url?sa=p&pref=ig&pval=3&q=http://www.google.com/ig%3Fhl%3Den%26source%3Diglk&usg=AFQjCNFA18XPfgb7dKnXfKz7x7g1GDH1tg">iGoogle</a></li><li class=gbmtc><div class="gbmt gbmh"></div></li><li class="gbkp gbmtc"><a class=gbmt href="http://www.google.com/history/optout?hl=en">Web History</a></li></ol></div></div></div></ol></div></div></div><div id=gbx1 class="gbqfh"></div><div id=gbx2 class="gbqfh"></div><div id=gbx3></div><div id=gbx4></div><script>window.gbar&&gbar.elp&&gbar.elp()</script></div><div id=searchform style="display:none"><span id=tophf></span><span id=ss-bar></span></div></div><iframe name=wgjf style=display:none src="/blank.html" onload="google.j.l()" onerror="google.j.e()"></iframe><textarea id=wgjc style=display:none name=wgjc></textarea><textarea id=wwcache style=display:none name=wwcache></textarea><textarea id=csi style=display:none name=csi></textarea><textarea id=hcache style=display:none name=hcache></textarea><div id=gac_scont></div><div id=main><span class=ctr-p id=body><center><div id=lga style="height:242px"><div id="hplogo" style="width:500px;height:270px;position:relative;padding-top:28px;background:url(/images/srpr/logo3w.png) center no-repeat"></div><noscript><style>#hplogo{background:url('/images/srpr/logo3w.png')}</style></noscript><script>(function(){google.doodle=google.doodle||{};google.doodle.url="/search?q=Joyeuses+f%C3%AAtes&ct=holiday11-hp&oi=ddle";var a=document.createElement("script");a.src="/logos/2011/holiday11_init.js";a.async=!0;document.body.appendChild(a);})();</script></div><div style="height:102px"></div><div style="font-size:83%;min-height:3.5em"><br></div><div id=res></div></center></span> <div id=footer style="display:none" class=ctr-p><div> <div id=ftby><div id=fll ><div><a href="/intl/en/ads/">Advertising Programs</a><a href="/services/">Business Solutions</a><a href="/intl/en/privacy.html">Privacy</a></div><div><a href="https://plus.google.com/116899029375914044550" rel="publisher">+Google</a><a href="/intl/en/about.html">About Google</a><b><a href="http://www.google.fr/">Go to Google France</a></b></div></div><div id=flci><a href="/url?sa=p&pref=ig&pval=3&q=http://www.google.com/ig%3Fhl%3Den%26source%3Diglk&usg=AFQjCNFA18XPfgb7dKnXfKz7x7g1GDH1tg">iGoogle</a><a href="javascript:void(0)" id=cp-sol>Change background image</a></div> </div> </div> </div> </div> <script>function _gjp(){!(location.hash&&_gjuc())&&setTimeout(_gjp,500);}google.j[1]={cc:[],co:['body','footer','xjsi'],pc:[],css:document.getElementById('gstyle').innerHTML,main:'<span class=ctr-p id=body></span>'+'<span class=ctr-p id=footer></span>'+'<span id=xjsi></span>',bl:['mngb','gb_']};</script><script>function wgjp(){var xjs=document.createElement('script');xjs.src='/extern_chrome/84de2a5c5244427.js';(document.getElementById('xjsd')||document.body).appendChild(xjs)};</script><div id=xjsd></div><div id=xjsi><script>if(google.y)google.y.first=[];google.dlj=function(b){window.setTimeout(function(){var a=document.createElement("script");a.src=b;document.getElementById("xjsd").appendChild(a)},0)}; | |
if(google.y)google.y.first=[];if(!google.xjs){google.dstr=[];google.rein=[];if(google.timers&&google.timers.load.t){google.timers.load.t.xjsls=new Date().getTime();}google.dlj('/extern_js/f/CgJlbiswRTgALCswWjgALCswDjgALCswFzgALCswPDgALCswUTgALCswWTgALCswCjgAmgICY2MsKzCYATgALCswFjgALCswGTgALCswKjgALCswKzgAmgIJc3NscmVmX25xLCswNTgALCswQTgALCswTTgALCswTjgALCswUzgAmgIGc2VhcmNoLCswVDgALCswYzgALCswaTgALCswkAE4ACwrMJIBOAAsKzCXATgALCswowE4ACwrMKcBOAAsKzCsATgALCswdDgALCswHTgALCswXDgALCswGDgALCswJjgALIACY5ACXQ/YZbu7umImbk.js');google.xjs=1}(function(){ | |
var a=document.getElementById("cp-sol");if(a&&!a.onclick)a.onclick=function(){var b="https://accounts.google.com/ServiceLogin?continue\x3dhttps://www.google.com/webhp%3Fcplp%3D\x26hl\x3den\x26service\x3dig\x26ltmpl\x3daddphoto";document.location=b.indexOf("%3Fcplp%3D")<0?b.replace("%26cplp%3D","%26cplp%3D"+(new Date).getTime()):b.replace("%3Fcplp%3D","%3Fcplp%3D"+(new Date).getTime())}; | |
})(); | |
;google.neegg=1;(function(){ | |
function a(){if(document.documentElement&&document.documentElement.clientHeight)return document.documentElement.clientHeight;else if(document.body&&document.body.clientHeight)return document.body.clientHeight;return 0}function b(d,k,e){var l=d.offsetHeight?e-d.offsetHeight:e+10,m=k-l-10,f=Math.max(m,0);d.style.height=f+"px";return f}var c=false,g;function h(){if(google.sn=="web"){i();return}if(g)b(g,a(),document.body.offsetHeight)}function j(){if(google.sn=="web"||c)return;g=document.getElementById("footer"); | |
if(!g)return;if(window.addEventListener)window.addEventListener("resize",h,false);else window.attachEvent("onresize",h);g.style.display="block";h();c=true}function i(){if(!c)return;if(window.removeEventListener)window.removeEventListener("resize",h,false);else window.detachEvent("onresize",h);c=false;g=document.getElementById("footer");g&&(g.style.display="none")}if(google.rein&&google.dstr){google.rein.push(function(){j()});google.dstr.push(function(){i()})}j(); | |
})(); | |
;google.mc=[];google.mc=google.mc.concat([[69,{}],[14,{}],[60,{}],[81,{}],[10,{"client":"hp","dh":true,"ds":"","fl":true,"host":"google.com","jsonp":true,"msgs":{"lcky":"I\u0026#39;m Feeling Lucky","lml":"Learn more","psrc":"This search was removed from your \u003Ca href=\"/history\"\u003EWeb History\u003C/a\u003E","psrl":"Remove","srch":"Google Search"},"ovr":{"da":1,"ep":1,"l":1,"mc":1,"o":1,"p":1,"ps":1,"sp":1,"sw":1},"pq":"","psy":"p","scd":10,"sce":4}],[152,{}],[42,{}],[43,{}],[83,{"bih":662,"biw":1050}],[78,{}],[25,{"g":28,"k":true,"m":{"app":true,"bks":true,"blg":true,"dsc":true,"evn":true,"flm":true,"frm":true,"isch":true,"klg":true,"mbl":true,"nws":true,"plcs":true,"ppl":true,"prc":true,"pts":true,"rcp":true,"shop":true,"vid":true},"t":null}],[172,{}],[105,{}],[22,{"db":false,"m_errors":{"32":"Sorry, no more results to show.","default":"\u003Cfont color=red\u003EError:\u003C/font\u003E The server could not complete your request. Try again in 30 seconds."},"m_tip":"Click for more information","nlpm":"-153px -84px","nlpp":"-153px -70px","utp":false}],[77,{}],[167,{"MESSAGES":{"msg_img_from":"Image from %1$s","msg_ms":"More sizes","msg_si":"Similar"}}],[146,{}],[99,{}],[144,{}],[84,{"cm_hov":true,"uab":true}],[151,{"ab":{"on":true,"strobePinned":true,"sug4":true},"ajax":{"gl":"us","gwsHost":"","hl":"en","maxPrefetchConnections":2,"prefetchTotal":5,"q":"","requestPrefix":"/ajax/rd?"},"css":{"def":false},"elastic":{"js":true,"rhs4Col":1088,"rhs5Col":1176,"rhsOn":true},"kfe":{"adsClientId":33,"clientId":29,"kfeHost":"clients1.google.com","kfeUrlPrefix":"/webpagethumbnail?r=4\u0026f=3\u0026s=400:585\u0026query=\u0026hl=en\u0026gl=us","vsH":585,"vsW":400},"logging":{"csiFraction":0.050},"msgs":{"details":"Result details","loading":"Still loading...","mute":"Mute","noPreview":"Preview not available","unmute":"Unmute"},"nokjs":{"on":true},"time":{"hOff":300,"hOn":300,"hSwitch":200,"loading":100,"timeout":2500}}],[116,{"bd":[],"bk":[],"bu":[],"gl":"","mb":500,"msgs":{"a":"Block all %1$s results","b":"\u003Cb\u003ENot helpful?\u003C/b\u003E You can block \u003Cb\u003E%1$s\u003C/b\u003E results when you\u0026#39;re signed in to search.","c":"We will not show you results from \u003Cb\u003E%1$s\u003C/b\u003E again.","d":"Manage blocked sites","e":"Undo","f":"Unblock %1$s","g":"Unblocked %1$s"},"q":""}],[29,{"cspd":0,"jck":true,"mcr":5}],[92,{"ae":true,"avgTtfc":2000,"bpe":false,"brba":false,"dlen":24,"dper":1,"fbdc":500,"fbdu":3000,"fbh":true,"fd":1000,"fl":true,"focus":true,"fs":true,"hiue":true,"hpt":299,"kn":true,"knrt":true,"mds":"clir,clue,dfn,evn,frim,klg,prc,rl,show,sp,sts,mbl_he,mbl_hs,mbl_re,mbl_rs,mbl_sv","msg":{"dym":"Did you mean:","gs":"Google Search","kntt":"Use the up and down arrow keys to select each result. Press Enter to go to the selection.","sif":"Search instead for","srf":"Showing results for"},"odef":true,"ophe":true,"pq":true,"rpt":50,"scd":10,"sce":4,"tct":" \\u3000?","tdur":50}],[24,{}],[38,{}]]);(function(){var r=(function(){google.y.first.push(function(){if(google.med){google.med('init');google.initHistory();google.med('history');}google.History&&google.History.initialize('/')});});r();var l=window.location.hash?window.location.href.substr(window.location.href.indexOf('#')):'#';if(l=='#'&&google.defre){google.defre=1;google.y.first.push(function(){if(google.j&&google.j.init){google.rein&&google.rein.push(r);}});}})();if(google.j&&google.j.en&&google.j.xi){window.setTimeout(google.j.xi,0);}</script></div><script>(function(){ | |
var b,d,e,f;function g(a,c){if(a.removeEventListener){a.removeEventListener("load",c,false);a.removeEventListener("error",c,false)}else{a.detachEvent("onload",c);a.detachEvent("onerror",c)}}function h(a){f=(new Date).getTime();++d;a=a||window.event;var c=a.target||a.srcElement;g(c,h)}var i=document.getElementsByTagName("img");b=i.length;d=0;for(var j=0,k;j<b;++j){k=i[j];if(k.complete||typeof k.src!="string"||!k.src)++d;else if(k.addEventListener){k.addEventListener("load",h,false);k.addEventListener("error", | |
h,false)}else{k.attachEvent("onload",h);k.attachEvent("onerror",h)}}e=b-d;function l(){if(!google.timers.load.t)return;google.timers.load.t.ol=(new Date).getTime();google.timers.load.t.iml=f;google.kCSI.imc=d;google.kCSI.imn=b;google.kCSI.imp=e;if(google.stt!==undefined)google.kCSI.stt=google.stt;google.timers.load.t.xjs&&google.report&&google.report(google.timers.load,google.kCSI)}if(window.addEventListener)window.addEventListener("load", | |
l,false);else if(window.attachEvent)window.attachEvent("onload",l);google.timers.load.t.prt=(f=(new Date).getTime()); | |
})(); | |
</script> | |
<script> | |
// Flatten Box2d (ugly but handy!) | |
(function b2(o) { | |
for (k in o) { | |
if (o.hasOwnProperty(k)) { | |
if ($.isPlainObject(o[k])) { | |
b2(o[k]); | |
} else if (/^b2/.test(k)) { | |
window[k] = o[k]; | |
} | |
} | |
} | |
}(Box2D)); | |
// Inheritance utility | |
function inherit(child, parent) { | |
for (var key in parent) { | |
if (parent.hasOwnProperty(key)) { | |
child[key] = parent[key]; | |
} | |
} | |
function ctor() {this.constructor = child;} | |
ctor.prototype = parent.prototype; | |
child.prototype = new ctor(); | |
child.uber = parent.prototype; | |
return child; | |
}; | |
// Fake require | |
function require(path) { | |
var module; | |
try { | |
module = eval(path); | |
} catch (e) { | |
throw(e); | |
} | |
return module; | |
} | |
window.require = require; | |
// | |
// Shims (to add) | |
// | |
// Function.prototype.bind | |
// Array.prototype.indexOf | |
var SCALE = 30; | |
function Real(options) { | |
options || (options = {}); | |
options = $.extend(true, { | |
debug: false | |
}, options); | |
//this.clock = new Real.Timer(); | |
this.world = new b2World( | |
new b2Vec2(0, 0), // gravity | |
true // allow sleep | |
); | |
this.updateLoop = new Loop(this.updateLoop.bind(this), 1000/30); | |
this.drawLoop = new Loop(this.drawLoop.bind(this)); | |
this.elements = []; | |
// debug | |
this.debug = !!options.debug; | |
var $window = $('html'); | |
var debugDraw = new b2DebugDraw(); | |
debugDraw.SetSprite($('<canvas width="' + ($window.width()) + '" height="' + ($window.height()) + '"/>').css({ | |
position: 'fixed', | |
left: 0, | |
top: 0, | |
zIndex: -1 | |
}).appendTo($window).get(0).getContext("2d")); | |
debugDraw.SetDrawScale(SCALE); | |
debugDraw.SetFillAlpha(0.8); | |
debugDraw.SetLineThickness(0.5); | |
debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit | b2DebugDraw.e_centerOfMassBit/* | b2DebugDraw.e_aabbBit | b2DebugDraw.e_pairBit | b2DebugDraw.e_controllerBit*/); | |
this.world.SetDebugDraw(debugDraw); | |
} | |
Real.prototype.updateLoop = function () { | |
//this.time = this.clock.tick(); | |
var i = this.elements.length; | |
while (i--) { | |
this.elements[i].update(); | |
} | |
this.world.Step( | |
(this.updateLoop.interval || 60) / 1000, //frame-rate | |
10, //velocity iterations | |
10 //position iterations | |
); | |
if (this.debug) { | |
this.world.DrawDebugData(); | |
} | |
this.world.ClearForces(); | |
}; | |
Real.prototype.drawLoop = function () { | |
//this.time = this.clock.tick(); | |
var i = this.elements.length; | |
while (i--) { | |
this.elements[i].draw(); | |
} | |
}; | |
Real.prototype.start = function () { | |
this.updateLoop.start(); | |
this.drawLoop.start(); | |
} | |
Real.prototype.stop = function () { | |
this.updateLoop.stop(); | |
this.drawLoop.stop(); | |
} | |
Real.prototype.addElement = function (element) { | |
this.elements.push(element); | |
return element; | |
} | |
Real.prototype.removeElement = function (element) { | |
this.world.DestroyBody(this.elements[i].body); | |
this.elements.splice(this.element.indexOf(element), 1); | |
} | |
Real.prototype.findElement = function (el) { | |
var i = this.elements.length; | |
while (i--) { | |
if (this.elements[i].el === el) { | |
return this.elements[i]; | |
} | |
} | |
} | |
/*function Timer() { | |
this.t = 0; | |
this.t0 = this.t; | |
this.dtMax = 0.05; | |
} | |
Timer.prototype.tick = function () { | |
var now = new Date().getTime(); | |
var dt = now - t0; | |
this.t0 = this.t; | |
}*/ | |
function Element(el, world, options) { | |
options || (options = {}); | |
this.$el = $(el); | |
this.el = this.$el[0]; | |
// Defaults | |
options = $.extend(true, { | |
body: { | |
type: b2Body.b2_dynamicBody, | |
}, | |
fixture: { | |
density: 1, | |
friction: 0.5, | |
restitution: 0.2, | |
shape: b2PolygonShape | |
} | |
}, options); | |
// Fixture | |
var fixDef = new b2FixtureDef; | |
fixDef.density = options.fixture.density; | |
fixDef.friction = options.fixture.friction; | |
fixDef.restitution = options.fixture.restitution; | |
// Shape | |
if (options.fixture.shape === b2PolygonShape) { | |
fixDef.shape = new b2PolygonShape; | |
fixDef.shape.SetAsBox( | |
this.$el.outerWidth() / 2 / SCALE, //half width | |
this.$el.outerHeight() / 2 / SCALE //half height | |
); | |
} else { | |
fixDef.shape = new b2CircleShape(this.$el.outerWidth() / 2 / SCALE); | |
} | |
// Body | |
var bodyDef = new b2BodyDef; | |
bodyDef.type = options.body.type; | |
this.origPos = { | |
left: this.$el.offset().left, | |
top: this.$el.offset().top, | |
width: this.$el.outerWidth(), | |
height: this.$el.outerHeight() | |
}; | |
bodyDef.position.x = (this.origPos.left + this.origPos.width / 2) / SCALE; | |
bodyDef.position.y = (this.origPos.top + this.origPos.height / 2) / SCALE; | |
// Add to world | |
this.body = world.CreateBody(bodyDef); | |
this.body.CreateFixture(fixDef); | |
} | |
Element.prototype.update = function () {}; | |
Element.prototype.draw = function () { | |
var pos = this.body.GetPosition(); | |
var ang = this.body.GetAngle() * 180 / Math.PI; | |
var origPos = this.origPos; | |
this.$el.css('transform', 'translate3d(' + ~~(pos.x*SCALE - origPos.left - origPos.width / 2) + 'px, ' + ~~(pos.y*SCALE - origPos.top - origPos.height / 2) + 'px, 0) rotate3d(0,0,1,' + ~~ang + 'deg)'); | |
}; | |
Real.Element = Element; | |
function Joint(real, elA, elB) { | |
elementA = real.findElement(elA); | |
elementB = real.findElement(elB); | |
if (!elementA || !elementB) { | |
return; | |
} | |
var springDef; | |
springDef = new b2DistanceJointDef(); | |
springDef.bodyA = elementA.body; | |
springDef.bodyB = elementB.body; | |
springDef.localAnchorA = springDef.bodyA.GetLocalCenter(); | |
springDef.localAnchorB = springDef.bodyB.GetLocalCenter(); | |
springDef.collideConnected = true; | |
//springDef.dampingRatio = .2; | |
//springDef.frequencyHz = .5 | |
springDef.length = (function () { | |
var v = springDef.bodyB.GetWorldPoint(springDef.localAnchorB); | |
v.Subtract(springDef.bodyA.GetWorldPoint(springDef.localAnchorA)) | |
return v.Length(); | |
}()) | |
real.world.CreateJoint(springDef) | |
} | |
Real.Joint = Joint; | |
// | |
// Ground | |
// | |
BallElement = (function(uber) { | |
inherit(BallElement, uber); | |
function BallElement() { | |
BallElement.uber.constructor.apply(this, arguments); | |
} | |
BallElement.prototype.draw = function () { | |
BallElement.uber.draw.call(this); | |
function angleVV(v1, v2) { | |
var n1 = v1.Length(); | |
var n2 = v2.Length(); | |
return Math.atan2(v1.y/n1, v1.x/n1) - Math.atan2(v2.y/n2, v2.x/n2); | |
} | |
var vel = this.body.GetLinearVelocityFromLocalPoint(new b2Vec2(0,0)); | |
this.$el.find('b') | |
.parent().css('transform', 'rotate3d(0,0,1,' + ~~((-this.body.GetAngle() + angleVV(vel, new b2Vec2(0, 1)) - Math.PI / 2) * 180 / Math.PI) + 'deg)') | |
.end() | |
.css({ | |
width: vel.Length() * 10 + '%', | |
opacity: vel.Length() / 10 | |
}); | |
}; | |
return BallElement; | |
})(Element); | |
var real = new Real(); | |
window.real = real; | |
$('#hplogo, #gbqfq, #gbqfba, #gbqfbb').each(function (i, el) { | |
real.addElement(new Real.Element(this, real.world)); | |
}); | |
// | |
// MouseJoint | |
// | |
var mouse = new b2Vec2(); | |
$(window).mousemove(function (e) { | |
mouse.Set(e.pageX / SCALE, e.pageY / SCALE); | |
}); | |
window.mouse = mouse; | |
(function (mouse) { | |
var mouseJointDef = new b2MouseJointDef(); | |
mouseJointDef.target = mouse; | |
mouseJointDef.bodyA = real.world.GetGroundBody(); | |
mouseJointDef.collideConnected = true; | |
var mouseJoint; | |
$('*').on({ | |
mousedown: function (e) { | |
var element = real.findElement(this); | |
var body = element && element.body; | |
if (!body) { | |
return; | |
} | |
mouseJointDef.bodyB = body; | |
mouseJointDef.maxForce = 300 * body.GetMass(); | |
mouseJoint = real.world.CreateJoint(mouseJointDef); | |
mouseJoint.SetTarget(mouse); | |
function mouseup(e) { | |
real.world.DestroyJoint(mouseJoint); | |
} | |
$(window).one('mouseup', mouseup); | |
} | |
}); | |
}(mouse)); | |
real.start(); | |
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Hammer.JS | |
* version 0.6.1 | |
* author: Eight Media | |
* https://github.com/EightMedia/hammer.js | |
*/ | |
function Hammer(element, options, undefined) | |
{ | |
var self = this; | |
var defaults = { | |
// prevent the default event or not... might be buggy when false | |
prevent_default : false, | |
css_hacks : true, | |
cancel_event : true, | |
swipe : true, | |
swipe_time : 200, // ms | |
swipe_min_distance : 20, // pixels | |
drag : true, | |
drag_vertical : true, | |
drag_horizontal : true, | |
// minimum distance before the drag event starts | |
drag_min_distance : 20, // pixels | |
// pinch zoom and rotation | |
transform : true, | |
scale_treshold : 0.1, | |
rotation_treshold : 15, // degrees | |
tap : true, | |
tap_double : true, | |
tap_max_interval : 300, | |
tap_max_distance : 10, | |
tap_double_distance: 20, | |
hold : true, | |
hold_timeout : 500 | |
}; | |
options = mergeObject(defaults, options); | |
// some css hacks | |
(function() { | |
if(!options.css_hacks) { | |
return false; | |
} | |
var vendors = ['webkit','moz','ms','o','']; | |
var css_props = { | |
"userSelect": "none", | |
"touchCallout": "none", | |
"userDrag": "none", | |
"tapHighlightColor": "rgba(0,0,0,0)" | |
}; | |
var prop = ''; | |
for(var i = 0; i < vendors.length; i++) { | |
for(var p in css_props) { | |
prop = p; | |
if(vendors[i]) { | |
prop = vendors[i] + prop.substring(0, 1).toUpperCase() + prop.substring(1); | |
} | |
element.style[ prop ] = css_props[p]; | |
} | |
} | |
})(); | |
// holds the distance that has been moved | |
var _distance = 0; | |
// holds the exact angle that has been moved | |
var _angle = 0; | |
// holds the diraction that has been moved | |
var _direction = 0; | |
// holds position movement for sliding | |
var _pos = { }; | |
// how many fingers are on the screen | |
var _fingers = 0; | |
var _first = false; | |
var _gesture = null; | |
var _prev_gesture = null; | |
var _touch_start_time = null; | |
var _prev_tap_pos = {x: 0, y: 0}; | |
var _prev_tap_end_time = null; | |
var _hold_timer = null; | |
var _offset = {}; | |
// keep track of the mouse status | |
var _mousedown = false; | |
var _event_start; | |
var _event_move; | |
var _event_end; | |
var _has_touch = ('ontouchstart' in window); | |
/** | |
* option setter/getter | |
* @param string key | |
* @param mixed value | |
* @return mixed value | |
*/ | |
this.option = function(key, val) { | |
if(val != undefined) { | |
options[key] = val; | |
} | |
return options[key]; | |
}; | |
/** | |
* angle to direction define | |
* @param float angle | |
* @return string direction | |
*/ | |
this.getDirectionFromAngle = function( angle ) | |
{ | |
var directions = { | |
down: angle >= 45 && angle < 135, //90 | |
left: angle >= 135 || angle <= -135, //180 | |
up: angle < -45 && angle > -135, //270 | |
right: angle >= -45 && angle <= 45 //0 | |
}; | |
var direction, key; | |
for(key in directions){ | |
if(directions[key]){ | |
direction = key; | |
break; | |
} | |
} | |
return direction; | |
}; | |
/** | |
* count the number of fingers in the event | |
* when no fingers are detected, one finger is returned (mouse pointer) | |
* @param event | |
* @return int fingers | |
*/ | |
function countFingers( event ) | |
{ | |
// there is a bug on android (until v4?) that touches is always 1, | |
// so no multitouch is supported, e.g. no, zoom and rotation... | |
return event.touches ? event.touches.length : 1; | |
} | |
/** | |
* get the x and y positions from the event object | |
* @param event | |
* @return array [{ x: int, y: int }] | |
*/ | |
function getXYfromEvent( event ) | |
{ | |
event = event || window.event; | |
// no touches, use the event pageX and pageY | |
if(!_has_touch) { | |
var doc = document, | |
body = doc.body; | |
return [{ | |
x: event.pageX || event.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && doc.clientLeft || 0 ), | |
y: event.pageY || event.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && doc.clientTop || 0 ) | |
}]; | |
} | |
// multitouch, return array with positions | |
else { | |
var pos = [], src, touches = event.touches.length > 0 ? event.touches : event.changedTouches; | |
for(var t=0, len=touches.length; t<len; t++) { | |
src = touches[t]; | |
pos.push({ x: src.pageX, y: src.pageY }); | |
} | |
return pos; | |
} | |
} | |
/** | |
* calculate the angle between two points | |
* @param object pos1 { x: int, y: int } | |
* @param object pos2 { x: int, y: int } | |
*/ | |
function getAngle( pos1, pos2 ) | |
{ | |
return Math.atan2(pos2.y - pos1.y, pos2.x - pos1.x) * 180 / Math.PI; | |
} | |
/** | |
* calculate the scale size between two fingers | |
* @param object pos_start | |
* @param object pos_move | |
* @return float scale | |
*/ | |
function calculateScale(pos_start, pos_move) | |
{ | |
if(pos_start.length == 2 && pos_move.length == 2) { | |
var x, y; | |
x = pos_start[0].x - pos_start[1].x; | |
y = pos_start[0].y - pos_start[1].y; | |
var start_distance = Math.sqrt((x*x) + (y*y)); | |
x = pos_move[0].x - pos_move[1].x; | |
y = pos_move[0].y - pos_move[1].y; | |
var end_distance = Math.sqrt((x*x) + (y*y)); | |
return end_distance / start_distance; | |
} | |
return 0; | |
} | |
/** | |
* calculate the rotation degrees between two fingers | |
* @param object pos_start | |
* @param object pos_move | |
* @return float rotation | |
*/ | |
function calculateRotation(pos_start, pos_move) | |
{ | |
if(pos_start.length == 2 && pos_move.length == 2) { | |
var x, y; | |
x = pos_start[0].x - pos_start[1].x; | |
y = pos_start[0].y - pos_start[1].y; | |
var start_rotation = Math.atan2(y, x) * 180 / Math.PI; | |
x = pos_move[0].x - pos_move[1].x; | |
y = pos_move[0].y - pos_move[1].y; | |
var end_rotation = Math.atan2(y, x) * 180 / Math.PI; | |
return end_rotation - start_rotation; | |
} | |
return 0; | |
} | |
/** | |
* trigger an event/callback by name with params | |
* @param string name | |
* @param array params | |
*/ | |
function triggerEvent( eventName, params ) | |
{ | |
// return touches object | |
params.touches = getXYfromEvent(params.originalEvent); | |
params.type = eventName; | |
// trigger callback | |
if(isFunction(self["on"+ eventName])) { | |
self["on"+ eventName].call(self, params); | |
} | |
} | |
/** | |
* cancel event | |
* @param object event | |
* @return void | |
*/ | |
function cancelEvent(event) | |
{ | |
if (!options.cancel_event) { return; }; | |
event = event || window.event; | |
if(event.preventDefault){ | |
event.preventDefault(); | |
event.stopPropagation(); | |
}else{ | |
event.returnValue = false; | |
event.cancelBubble = true; | |
} | |
} | |
/** | |
* reset the internal vars to the start values | |
*/ | |
function reset() | |
{ | |
_pos = {}; | |
_first = false; | |
_fingers = 0; | |
_distance = 0; | |
_angle = 0; | |
_gesture = null; | |
} | |
var gestures = { | |
// hold gesture | |
// fired on touchstart | |
hold : function(event) | |
{ | |
// only when one finger is on the screen | |
if(options.hold) { | |
_gesture = 'hold'; | |
clearTimeout(_hold_timer); | |
_hold_timer = setTimeout(function() { | |
if(_gesture == 'hold') { | |
triggerEvent("hold", { | |
originalEvent : event, | |
position : _pos.start | |
}); | |
} | |
}, options.hold_timeout); | |
} | |
}, | |
// swipe gesture | |
// fired on touchend | |
swipe : function(event) | |
{ | |
if(!_pos.move) { | |
return; | |
} | |
// get the distance we moved | |
var _distance_x = _pos.move[0].x - _pos.start[0].x; | |
var _distance_y = _pos.move[0].y - _pos.start[0].y; | |
_distance = Math.sqrt(_distance_x*_distance_x + _distance_y*_distance_y); | |
// compare the kind of gesture by time | |
var now = new Date().getTime(); | |
var touch_time = now - _touch_start_time; | |
if(options.swipe && (options.swipe_time > touch_time) && (_distance > options.swipe_min_distance)) { | |
// calculate the angle | |
_angle = getAngle(_pos.start[0], _pos.move[0]); | |
_direction = self.getDirectionFromAngle(_angle); | |
_gesture = 'swipe'; | |
var position = { x: _pos.move[0].x - _offset.left, | |
y: _pos.move[0].y - _offset.top }; | |
var event_obj = { | |
originalEvent : event, | |
position : position, | |
direction : _direction, | |
distance : _distance, | |
distanceX : _distance_x, | |
distanceY : _distance_y, | |
angle : _angle | |
}; | |
// normal slide event | |
triggerEvent("swipe", event_obj); | |
} | |
}, | |
// drag gesture | |
// fired on mousemove | |
drag : function(event) | |
{ | |
// get the distance we moved | |
var _distance_x = _pos.move[0].x - _pos.start[0].x; | |
var _distance_y = _pos.move[0].y - _pos.start[0].y; | |
_distance = Math.sqrt(_distance_x * _distance_x + _distance_y * _distance_y); | |
// drag | |
// minimal movement required | |
if(options.drag && (_distance > options.drag_min_distance) || _gesture == 'drag') { | |
// calculate the angle | |
_angle = getAngle(_pos.start[0], _pos.move[0]); | |
_direction = self.getDirectionFromAngle(_angle); | |
// check the movement and stop if we go in the wrong direction | |
var is_vertical = (_direction == 'up' || _direction == 'down'); | |
if(((is_vertical && !options.drag_vertical) || (!is_vertical && !options.drag_horizontal)) | |
&& (_distance > options.drag_min_distance)) { | |
return; | |
} | |
var interim_angle = getAngle(_pos.interim || _pos.start[0], _pos.move[0]), | |
interim_direction = self.getDirectionFromAngle(interim_angle); | |
_pos.interim = _pos.move[0]; | |
_gesture = 'drag'; | |
var position = { x: _pos.move[0].x - _offset.left, | |
y: _pos.move[0].y - _offset.top }; | |
var event_obj = { | |
originalEvent : event, | |
position : position, | |
direction : _direction, | |
distance : _distance, | |
distanceX : _distance_x, | |
distanceY : _distance_y, | |
angle : _angle, | |
interim_angle: interim_angle, | |
interim_direction: interim_direction | |
}; | |
// on the first time trigger the start event | |
if(_first) { | |
triggerEvent("dragstart", event_obj); | |
_first = false; | |
} | |
// normal slide event | |
triggerEvent("drag", event_obj); | |
cancelEvent(event); | |
} | |
}, | |
// transform gesture | |
// fired on touchmove | |
transform : function(event) | |
{ | |
if(options.transform) { | |
if(countFingers(event) != 2) { | |
return false; | |
} | |
var rotation = calculateRotation(_pos.start, _pos.move); | |
var scale = calculateScale(_pos.start, _pos.move); | |
if(_gesture != 'drag' && | |
(_gesture == 'transform' || Math.abs(1-scale) > options.scale_treshold || Math.abs(rotation) > options.rotation_treshold)) { | |
_gesture = 'transform'; | |
_pos.center = { x: ((_pos.move[0].x + _pos.move[1].x) / 2) - _offset.left, | |
y: ((_pos.move[0].y + _pos.move[1].y) / 2) - _offset.top }; | |
var event_obj = { | |
originalEvent : event, | |
position : _pos.center, | |
scale : scale, | |
rotation : rotation | |
}; | |
// on the first time trigger the start event | |
if(_first) { | |
triggerEvent("transformstart", event_obj); | |
_first = false; | |
} | |
triggerEvent("transform", event_obj); | |
cancelEvent(event); | |
return true; | |
} | |
} | |
return false; | |
}, | |
// tap and double tap gesture | |
// fired on touchend | |
tap : function(event) | |
{ | |
// compare the kind of gesture by time | |
var now = new Date().getTime(); | |
var touch_time = now - _touch_start_time; | |
// dont fire when hold is fired | |
if(options.hold && !(options.hold && options.hold_timeout > touch_time)) { | |
return; | |
} | |
// when previous event was tap and the tap was max_interval ms ago | |
var is_double_tap = (function(){ | |
if (_prev_tap_pos && | |
options.tap_double && | |
_prev_gesture == 'tap' && | |
(_touch_start_time - _prev_tap_end_time) < options.tap_max_interval) | |
{ | |
var x_distance = Math.abs(_prev_tap_pos[0].x - _pos.start[0].x); | |
var y_distance = Math.abs(_prev_tap_pos[0].y - _pos.start[0].y); | |
return (_prev_tap_pos && _pos.start && Math.max(x_distance, y_distance) < options.tap_double_distance); | |
} | |
return false; | |
})(); | |
if(is_double_tap) { | |
_gesture = 'double_tap'; | |
_prev_tap_end_time = null; | |
triggerEvent("doubletap", { | |
originalEvent : event, | |
position : _pos.start | |
}); | |
cancelEvent(event); | |
} | |
// single tap is single touch | |
else { | |
var x_distance = (_pos.move) ? Math.abs(_pos.move[0].x - _pos.start[0].x) : 0; | |
var y_distance = (_pos.move) ? Math.abs(_pos.move[0].y - _pos.start[0].y) : 0; | |
_distance = Math.max(x_distance, y_distance); | |
if(_distance < options.tap_max_distance) { | |
_gesture = 'tap'; | |
_prev_tap_end_time = now; | |
_prev_tap_pos = _pos.start; | |
if(options.tap) { | |
triggerEvent("tap", { | |
originalEvent : event, | |
position : _pos.start | |
}); | |
cancelEvent(event); | |
} | |
} | |
} | |
} | |
}; | |
function handleEvents(event) | |
{ | |
switch(event.type) | |
{ | |
case 'mousedown': | |
case 'touchstart': | |
_pos.start = getXYfromEvent(event); | |
_touch_start_time = new Date().getTime(); | |
_fingers = countFingers(event); | |
_first = true; | |
_event_start = event; | |
// borrowed from jquery offset https://github.com/jquery/jquery/blob/master/src/offset.js | |
var box = element.getBoundingClientRect(); | |
var clientTop = element.clientTop || document.body.clientTop || 0; | |
var clientLeft = element.clientLeft || document.body.clientLeft || 0; | |
var scrollTop = window.pageYOffset || element.scrollTop || document.body.scrollTop; | |
var scrollLeft = window.pageXOffset || element.scrollLeft || document.body.scrollLeft; | |
_offset = { | |
top: box.top + scrollTop - clientTop, | |
left: box.left + scrollLeft - clientLeft | |
}; | |
_mousedown = true; | |
// hold gesture | |
gestures.hold(event); | |
if(options.prevent_default) { | |
cancelEvent(event); | |
} | |
break; | |
case 'mousemove': | |
case 'touchmove': | |
if(!_mousedown) { | |
return false; | |
} | |
_event_move = event; | |
_pos.move = getXYfromEvent(event); | |
if(!gestures.transform(event)) { | |
gestures.drag(event); | |
} | |
break; | |
case 'mouseup': | |
case 'mouseout': | |
case 'touchcancel': | |
case 'touchend': | |
if(!_mousedown || (_gesture != 'transform' && event.touches && event.touches.length > 0)) { | |
return false; | |
} | |
_mousedown = false; | |
_event_end = event; | |
var dragging = _gesture == 'drag'; | |
// swipe gesture | |
gestures.swipe(event); | |
// drag gesture | |
// dragstart is triggered, so dragend is possible | |
if(dragging) { | |
triggerEvent("dragend", { | |
originalEvent : event, | |
direction : _direction, | |
distance : _distance, | |
angle : _angle | |
}); | |
} | |
// transform | |
// transformstart is triggered, so transformed is possible | |
else if(_gesture == 'transform') { | |
triggerEvent("transformend", { | |
originalEvent : event, | |
position : _pos.center, | |
scale : calculateScale(_pos.start, _pos.move), | |
rotation : calculateRotation(_pos.start, _pos.move) | |
}); | |
} | |
else { | |
gestures.tap(_event_start); | |
} | |
_prev_gesture = _gesture; | |
// trigger release event | |
triggerEvent("release", { | |
originalEvent : event, | |
gesture : _gesture | |
}); | |
// reset vars | |
reset(); | |
break; | |
} | |
} | |
// bind events for touch devices | |
// except for windows phone 7.5, it doesnt support touch events..! | |
if(_has_touch) { | |
addEvent(element, "touchstart touchmove touchend touchcancel", handleEvents); | |
} | |
// for non-touch | |
else { | |
addEvent(element, "mouseup mousedown mousemove", handleEvents); | |
addEvent(element, "mouseout", function(event) { | |
if(!isInsideHammer(element, event.relatedTarget)) { | |
handleEvents(event); | |
} | |
}); | |
} | |
/** | |
* find if element is (inside) given parent element | |
* @param object element | |
* @param object parent | |
* @return bool inside | |
*/ | |
function isInsideHammer(parent, child) { | |
// get related target for IE | |
if(!child && window.event && window.event.toElement){ | |
child = window.event.toElement; | |
} | |
if(parent === child){ | |
return true; | |
} | |
// loop over parentNodes of child until we find hammer element | |
if(child){ | |
var node = child.parentNode; | |
while(node !== null){ | |
if(node === parent){ | |
return true; | |
}; | |
node = node.parentNode; | |
} | |
} | |
return false; | |
} | |
/** | |
* merge 2 objects into a new object | |
* @param object obj1 | |
* @param object obj2 | |
* @return object merged object | |
*/ | |
function mergeObject(obj1, obj2) { | |
var output = {}; | |
if(!obj2) { | |
return obj1; | |
} | |
for (var prop in obj1) { | |
if (prop in obj2) { | |
output[prop] = obj2[prop]; | |
} else { | |
output[prop] = obj1[prop]; | |
} | |
} | |
return output; | |
} | |
/** | |
* check if object is a function | |
* @param object obj | |
* @return bool is function | |
*/ | |
function isFunction( obj ){ | |
return Object.prototype.toString.call( obj ) == "[object Function]"; | |
} | |
/** | |
* attach event | |
* @param node element | |
* @param string types | |
* @param object callback | |
*/ | |
function addEvent(element, types, callback) { | |
types = types.split(" "); | |
for(var t= 0,len=types.length; t<len; t++) { | |
if(element.addEventListener){ | |
element.addEventListener(types[t], callback, false); | |
} | |
else if(document.attachEvent){ | |
element.attachEvent("on"+ types[t], callback); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
html, body {height:100%;} | |
/*html {display:table; width:100%;} | |
body {display:table-cell; text-align:center; vertical-align:middle;}*/ | |
html {overflow:hidden; -moz-touch-action:none;-webkit-touch-action:none;-ms-touch-action:none;touch-action:none;} | |
* {-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none; -webkit-user-drag:none;-moz-user-drag:none;-ms-user-drag:none;-o-user-drag:none;user-drag:none;} | |
*, | |
*:before, | |
*:after {-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-ms-box-sizing:border-box;-o-box-sizing:border-box;box-sizing:border-box;} | |
body {font-size:250%; text-align:center; margin:0; padding-top:1em;} | |
.by {margin:0; position:absolute; bottom:1em; right:1em; font-size:50%; margin:1em;} | |
a.chromexperiment {margin:0; position:absolute; bottom:1em; left:1em; font-size:50%; margin:1em;} | |
a.chromexperiment img {vertical-align:bottom;} | |
.ball, | |
.ball b, | |
.crate, | |
.ground {vertical-align:bottom;} | |
.ball {display:inline-block; width:3em; height:3em; border-radius:100%; border:.4em solid; color:#dc3132; position:relative;} | |
.ball b {display:block; width:100%; border:.2em solid; border-radius:.2em;} | |
.ball {padding:.4em 0;} | |
.ball > div {width:100%; height:100%; position:relative;} | |
.ball b {position:absolute; left:100%; top:50%;margin-top:-.2em; margin-left:.45em;} | |
.ball b:first-child, | |
.ball b:last-child {margin-left:.3em;} | |
.ball b:first-child {top:0;} | |
.ball b:last-child {top:auto;margin-top:auto;bottom:0;margin-bottom:-.2em;} | |
.crate {display:inline-block; width:1em; height:1em; border:.13em solid #30aebf; border-radius:.05em;} | |
.ground {display:inline-block; width:12em; border:.2em solid; color:#8cc924; border-radius:.15em;} | |
.wall {position:absolute; background-color:rgba(0,0,0,.1);} | |
.wall.left, | |
.wall.right {height:100%; width:.5em; top:0;} | |
.wall.top, | |
.wall.bottom {width:100%; height:.5em; left:0;} | |
.wall.left {left:0;} | |
.wall.top {top:0;} | |
.wall.right {right:0;} | |
.wall.bottom {bottom:0;} | |
.ball, | |
.ball+.crate, | |
.ground {display:block; margin:0 auto;} | |
/* Debug */ | |
#stats {position:fixed; left:0; top:0;} | |
#stats + #stats {left:80px;} | |
@media (max-width:700px) { | |
@-webkit-viewport { | |
orientation:portrait; | |
} | |
@viewport { | |
orientation:portrait; | |
} | |
.ball {font-size:50%} | |
.dg {display:none;} | |
.ground {width:4em;} | |
a.chromexperiment img {height:3em;} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset=utf-8> | |
<meta name="viewport" content="width=device-width,minimum-scale=1,maximum-scale=1,initial-scale=1,user-scalable=no"> | |
<title>box2d</title> | |
<link rel="stylesheet" href="index.css"> | |
</head> | |
<body> | |
<div class="ball"> | |
<div> | |
<b></b> | |
<b></b> | |
<b></b> | |
</div> | |
</div> | |
<div class="crate"></div> | |
<div class="crate"></div><div class="crate"></div> | |
<!--<div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div><div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div>--> | |
<div class="ground"></div> | |
<div class="wall left"></div> | |
<div class="wall top"></div> | |
<div class="wall right"></div> | |
<div class="wall bottom"></div> | |
<p class="by"> | |
— by <a href="http://abernier.name">abernier</a> | |
</p> | |
<a class="chromexperiment" href="http://www.chromeexperiments.com/detail/box2d-mobile/"><img src="http://1-ps.googleusercontent.com/x/s.chromexperiments-hrd.appspot.com/www.chromeexperiments.com/img/xbadge-black_white.png.pagespeed.ic.hWVg32DNYM.png" alt></a> | |
<!--<script src="http://box2dweb.googlecode.com/svn/trunk/Box2D.js"></script> | |
<script src="https://raw.github.com/gist/1579671/rAF.js"></script> | |
<script src="https://raw.github.com/gist/3225993/loop.js"></script> | |
<script src="http://code.jquery.com/jquery-latest.js"></script> | |
<script src="http://dat-gui.googlecode.com/git/build/dat.gui.js"></script>--> | |
<script src="Box2D.js"></script> | |
<script src="rAF.js"></script> | |
<script src="loop.js"></script> | |
<script src="underscore.js"></script> | |
<script src="backbone.js"></script> | |
<script src="jquery-latest.js"></script> | |
<script src="dat.gui.js"></script> | |
<script src="stats.min.js"></script> | |
<script src="jquery.hotkeys.js"></script> | |
<script src="index.js"></script> | |
<script> | |
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ | |
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), | |
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) | |
})(window,document,'script','//www.google-analytics.com/analytics.js','ga'); | |
ga('create', 'UA-13126287-1', 'abernier.name'); | |
ga('send', 'pageview'); | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function () { | |
// Flatten Box2d (ugly but handy!) | |
(function b2(o) { | |
for (k in o) { | |
if (o.hasOwnProperty(k)) { | |
if ($.isPlainObject(o[k])) { | |
b2(o[k]); | |
} else if (/^b2/.test(k)) { | |
window[k] = o[k]; | |
} | |
} | |
} | |
}(Box2D)); | |
// Inheritance utility (see: http://coffeescript.org/#try:class%20A%0Aclass%20B%20extends%20A) | |
function inherit(child, parent) { | |
for (var key in parent) { | |
if (parent.hasOwnProperty(key)) { | |
child[key] = parent[key]; | |
} | |
} | |
function ctor() {this.constructor = child;} | |
ctor.prototype = parent.prototype; | |
child.prototype = new ctor(); | |
child.uber = parent.prototype; | |
return child; | |
}; | |
// | |
// TODO Shims (to add) | |
// | |
// Function.prototype.bind | |
// Array.prototype.indexOf | |
var SCALE = 150; | |
function Real(options) { | |
options || (options = {}); | |
options = $.extend(true, { | |
debug: false | |
}, options); | |
this.clock = new Real.Timer(); | |
this.world = new b2World( | |
new b2Vec2(0, 9.81), // gravity | |
true // allow sleep | |
); | |
this.loop = new Loop(this.loop.bind(this)/*, 1000/10*/); | |
//this.drawLoop = new Loop(this.drawLoop.bind(this)); | |
this.elements = []; | |
// debug | |
this.debug = !!options.debug; | |
if (this.debug) { | |
this.setDebugDraw(); | |
} | |
this.updatePerf = new Stats(); | |
$('body').append(this.updatePerf.domElement); | |
this.drawPerf = new Stats(); | |
$('body').append(this.drawPerf.domElement); | |
} | |
Real.prototype.setDebugDraw = function () { | |
if ($('canvas.debugDraw').length > 0) return; | |
var $window = $('html'); | |
var debugDraw = new b2DebugDraw(); | |
this.debugDraw = debugDraw; | |
debugDraw.SetSprite($('<canvas class="debugDraw" width="' + ($window.width()) + '" height="' + ($window.height()) + '"/>').css({ | |
position: 'fixed', | |
left: 0, | |
top: 0, | |
width: '100%', | |
height: '100%', | |
zIndex: -1 | |
}).appendTo('body').get(0).getContext("2d")); | |
debugDraw.SetDrawScale(SCALE); | |
debugDraw.SetFillAlpha(0.8); | |
debugDraw.SetLineThickness(0.5); | |
debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit | b2DebugDraw.e_centerOfMassBit); | |
this.world.SetDebugDraw(debugDraw); | |
}; | |
Real.prototype.unsetDebugDraw = function () { | |
real.world.SetDebugDraw(null); | |
$('canvas.debugDraw').remove(); | |
}; | |
Real.prototype.step = function (dt) { | |
this.updatePerf.begin(); | |
this.world.Step( | |
dt / 1000, //frame-rate | |
8, //velocity iterations | |
3 //position iterations | |
); | |
if (this.debug) { | |
this.world.DrawDebugData(); | |
} | |
var i = this.elements.length; | |
while (i--) { | |
this.elements[i].update(); | |
} | |
this.updatePerf.end(); | |
}; | |
Real.prototype.draw = function (smooth) { | |
this.drawPerf.begin(); | |
var i = this.elements.length; | |
while (i--) { | |
this.elements[i].draw(smooth); | |
} | |
this.drawPerf.end(); | |
}; | |
Real.prototype.start = function () { | |
this.clock.start(); | |
this.loop.start(); | |
//this.drawLoop.start(); | |
}; | |
Real.prototype.loop = function () { | |
// http://gafferongames.com/game-physics/fix-your-timestep/ | |
// http://www.koonsolo.com/news/dewitters-gameloop/ | |
// http://www.unagames.com/blog/daniele/2010/06/fixed-time-step-implementation-box2d | |
// http://codeincomplete.com/posts/2011/10/25/javascript_boulderdash/ | |
// http://actionsnippet.com/swfs/qbox_FRIM.html | |
// http://gamesfromwithin.com/casey-and-the-clearly-deterministic-contraptions | |
this.clock.tick(); | |
while (this.clock.accumulator >= this.clock.dt) { | |
//console.log('update'); | |
this.step(this.clock.dt); | |
this.clock.subtick(); | |
} | |
this.world.ClearForces(); | |
this.draw(true); | |
}; | |
Real.prototype.stop = function () { | |
this.loop.stop(); | |
this.clock.stop(); | |
//this.drawLoop.stop(); | |
}; | |
Real.prototype.addElement = function (element) { | |
this.elements.push(element); | |
return element; | |
}; | |
Real.prototype.removeElement = function (element) { | |
this.world.DestroyBody(this.elements[i].body); | |
this.elements.splice(this.element.indexOf(element), 1); | |
}; | |
Real.prototype.findElement = function (el) { | |
var i = this.elements.length; | |
while (i--) { | |
if (this.elements[i].el === el) { | |
return this.elements[i]; | |
} | |
} | |
}; | |
function Timer() { | |
this.t = 0; | |
this.dt = 1000/60; // Max FPS | |
this.currentTime = void 0; | |
this.accumulator = void 0; | |
this.dtMax = 1000/4; // Min FPS | |
} | |
Timer.prototype.start = function () { | |
if (this.currentTime) { | |
return; | |
} | |
this.currentTime = new Date().getTime(); | |
this.accumulator = 0; | |
return this; | |
}; | |
Timer.prototype.stop = function () { | |
if (!this.currentTime) { | |
return; | |
} | |
this.currentTime = void 0; | |
this.accumulator = void 0; | |
return this; | |
}; | |
Timer.prototype.tick = function () { | |
if (!this.currentTime) { | |
throw "Timer not started!"; | |
} | |
var newTime = new Date().getTime(); | |
var frameTime = newTime - this.currentTime; | |
frameTime = Math.min(frameTime, this.dtMax); | |
this.currentTime = newTime; | |
this.accumulator += frameTime; | |
return this; | |
}; | |
Timer.prototype.subtick = function () { | |
this.t += this.dt; | |
this.accumulator -= this.dt; | |
}; | |
Real.Timer = Timer; | |
function State() { | |
this.set.apply(this, arguments); | |
} | |
State.prototype.set = function (x, y, a) { | |
this.x = x; | |
this.y = y; | |
this.a = a; | |
return this; | |
}; | |
function Element(el, real, options) { | |
options || (options = {}); | |
this.$el = $(el); | |
this.el = this.$el[0]; | |
// Defaults | |
options = $.extend(true, { | |
body: { | |
type: b2Body.b2_dynamicBody, | |
}, | |
fixture: { | |
density: 1, | |
friction: 0.5, | |
restitution: 0.2, | |
shape: b2PolygonShape | |
} | |
}, options); | |
this.$el.addClass('element'); | |
this.real = real; | |
// Fixture | |
var fixDef = new b2FixtureDef; | |
fixDef.density = options.fixture.density; | |
fixDef.friction = options.fixture.friction; | |
fixDef.restitution = options.fixture.restitution; | |
// Shape | |
if (options.fixture.shape === b2PolygonShape) { | |
fixDef.shape = new b2PolygonShape; | |
fixDef.shape.SetAsBox( | |
this.$el.outerWidth() / 2 / SCALE, //half width | |
this.$el.outerHeight() / 2 / SCALE //half height | |
); | |
} else { | |
fixDef.shape = new b2CircleShape(this.$el.outerWidth() / 2 / SCALE); | |
} | |
// Body | |
var bodyDef = new b2BodyDef; | |
bodyDef.type = options.body.type; | |
this.origPos = { | |
left: this.$el.offset().left, | |
top: this.$el.offset().top, | |
width: this.$el.outerWidth(), | |
height: this.$el.outerHeight() | |
}; | |
bodyDef.position.x = (this.origPos.left + this.origPos.width / 2) / SCALE; | |
bodyDef.position.y = (this.origPos.top + this.origPos.height / 2) / SCALE; | |
// Add to world | |
this.body = real.world.CreateBody(bodyDef); | |
this.body.CreateFixture(fixDef); | |
var pos = this.body.GetPosition(); | |
var ang = this.body.GetAngle(); | |
this.state = new State(pos.x, pos.y, ang); | |
} | |
Element.prototype.update = function () { | |
var pos = this.body.GetPosition(); | |
var ang = this.body.GetAngle(); | |
var x = pos.x; | |
var y = pos.y; | |
var a = ang; | |
this.previousState = this.state; // backup previous state | |
this.state = new State(x, y, a); | |
}; | |
Element.prototype.draw = function (smooth) { | |
if (this.body.GetType() === b2Body.b2_staticBody) { | |
return; | |
} | |
var state; | |
// Interpolate with previous state | |
if (false && smooth && this.previousState) { | |
/*var accumulator = this.real.clock.accumulator/1000 | |
var v = this.body.GetLinearVelocity(); | |
var w = this.body.GetAngularVelocity(); | |
x += v.x * accumulator; | |
y += v.y * accumulator; | |
a += w * accumulator;*/ | |
var fixedTimestepAccumulatorRatio = this.real.clock.accumulator / this.real.clock.dt; | |
var oneMinusRatio = 1 - fixedTimestepAccumulatorRatio; | |
var x = this.state.x * fixedTimestepAccumulatorRatio + oneMinusRatio * this.previousState.x; | |
var y = this.state.y * fixedTimestepAccumulatorRatio + oneMinusRatio * this.previousState.y; | |
var a = this.state.a * fixedTimestepAccumulatorRatio + oneMinusRatio * this.previousState.a; | |
state = new State(x, y, a); | |
} else { | |
state = this.state; | |
} | |
var origPos = this.origPos; | |
this.$el.css('transform', 'translate3d(' + ~~(state.x*SCALE - origPos.left - origPos.width / 2) + 'px, ' + ~~(state.y*SCALE - origPos.top - origPos.height / 2) + 'px, 0) rotate3d(0,0,1,' + ~~(state.a * 180 / Math.PI) + 'deg)'); | |
//this.el.style.webkitTransform = 'translate3d(' + ~~(state.x*SCALE - origPos.left - origPos.width / 2) + 'px, ' + ~~(state.y*SCALE - origPos.top - origPos.height / 2) + 'px, 0) rotate3d(0,0,1,' + ~~(state.a * 180 / Math.PI) + 'deg)'; | |
}; | |
Real.Element = Element; | |
function Joint(real, elA, elB) { | |
elementA = real.findElement(elA); | |
elementB = real.findElement(elB); | |
if (!elementA || !elementB) { | |
return; | |
} | |
var springDef; | |
springDef = new b2DistanceJointDef(); | |
springDef.bodyA = elementA.body; | |
springDef.bodyB = elementB.body; | |
springDef.localAnchorA = springDef.bodyA.GetLocalCenter(); | |
springDef.localAnchorB = springDef.bodyB.GetLocalCenter(); | |
springDef.collideConnected = true; | |
//springDef.dampingRatio = .2; | |
//springDef.frequencyHz = .5 | |
springDef.length = (function () { | |
var v = springDef.bodyB.GetWorldPoint(springDef.localAnchorB); | |
v.Subtract(springDef.bodyA.GetWorldPoint(springDef.localAnchorA)) | |
return v.Length(); | |
}()) | |
real.world.CreateJoint(springDef) | |
}; | |
Real.Joint = Joint; | |
// | |
// Ground | |
// | |
BallElement = (function(uber) { | |
inherit(BallElement, uber); | |
function angleVV(v1, v2) { | |
var n1 = v1.Length(); | |
var n2 = v2.Length(); | |
return Math.atan2(v1.y/n1, v1.x/n1) - Math.atan2(v2.y/n2, v2.x/n2); | |
} | |
function BallElement() { | |
BallElement.uber.constructor.apply(this, arguments); | |
this.$tails = this.$el.find('b'); | |
this.$tailsContainer = this.$tails.parent(); | |
} | |
BallElement.prototype.draw = function (smooth) { | |
BallElement.uber.draw.apply(this, arguments); | |
var state = this.state; | |
var vel = this.body.GetLinearVelocityFromLocalPoint(new b2Vec2(0,0)); | |
//$tails.parent().css('transform', 'rotate3d(0,0,1,' + ~~((-this.body.GetAngle() + angleVV(vel, new b2Vec2(0, 1)) - Math.PI / 2) * 180 / Math.PI) + 'deg)') | |
this.$tailsContainer.css('transform', 'rotate3d(0,0,1,' + ((-state.a + angleVV(vel, new b2Vec2(0, 1)) - Math.PI / 2) * 180 / Math.PI) + 'deg)'); | |
//this.$tailsContainer[0].style.webkitTransform = 'rotate3d(0,0,1,' + ((-state.a + angleVV(vel, new b2Vec2(0, 1)) - Math.PI / 2) * 180 / Math.PI) + 'deg)'; | |
(function ($tails) { | |
var i = $tails.length; | |
var velocity = vel.Length(); | |
while (i--) { | |
var tailStyle = $tails[i].style; | |
tailStyle.width = velocity * 10 + '%'; | |
tailStyle.opacity = velocity / 10; | |
} | |
}(this.$tails)); | |
}; | |
return BallElement; | |
})(Element); | |
var real = new Real(); | |
window.real = real; | |
real.addElement(new Real.Element($('.ground'), real, {body: {type: b2Body.b2_staticBody}})); | |
real.addElement(new BallElement($('.ball'), real, {fixture: {shape: b2CircleShape}}, BallElement)); | |
$('.crate').each(function () { | |
real.addElement(new Real.Element(this, real)); | |
}); | |
$(document.body).on('click touchstart', function (e) { | |
if (e.target !== document.body) return; | |
e = (~e.type.indexOf('touch') ? e.originalEvent.targetTouches[0] : e); | |
var $el = $('<div class="crate" style="position:absolute;left:' + e.pageX + 'px; top:' + e.pageY + 'px;"/>').appendTo('body'); | |
real.addElement(new Real.Element($el[0], real)); | |
}); | |
$('.wall').each(function () { | |
real.addElement(new Real.Element(this, real, {body: {type: b2Body.b2_staticBody}})); | |
}); | |
real.addElement(new Real.Element($('.by')[0], real)); | |
real.addElement(new Real.Element($('.chromexperiment')[0], real)); | |
//new Real.Joint(real, $('.crate').get(0), $('.crate').get(1)); | |
//new Real.Joint(real, $('.crate').get(1), $('.crate').get(2)); | |
// | |
// MouseJoint | |
// | |
var mouse = new b2Vec2(); | |
window.mouse = mouse; | |
var mouseJointDef = new b2MouseJointDef(); | |
mouseJointDef.target = mouse; | |
mouseJointDef.bodyA = real.world.GetGroundBody(); | |
mouseJointDef.collideConnected = true; | |
var mouseJoint; | |
var $elements = $(real.elements.map(function (element) { | |
return element.el; | |
})); | |
function setMouse(e) { | |
e = (~e.type.indexOf('touch') ? e.originalEvent.targetTouches[0] : e); | |
mouse.Set(e.pageX / SCALE, e.pageY / SCALE); | |
} | |
function mousedown(e) { | |
setMouse(e); | |
$(document.body).undelegate('.element', 'mousedown touchstart', mousedown); | |
$(window).one('mouseup touchend', mouseup); | |
var element = real.findElement(this); | |
var body = element && element.body; | |
mouseJointDef.bodyB = body; | |
mouseJointDef.maxForce = 100 * body.GetMass(); | |
mouseJoint = real.world.CreateJoint(mouseJointDef); | |
mouseJoint.SetTarget(mouse); | |
$(document).on('mousemove touchmove', mousemove); | |
} | |
function mouseup(e) { | |
if (mouseJoint) { | |
real.world.DestroyJoint(mouseJoint); | |
} | |
$(document.body).delegate('.element', 'mousedown touchstart', mousedown); | |
$(window).off('mousemove touchmove', mousemove); | |
} | |
function mousemove(e) { | |
e.preventDefault(); // http://stackoverflow.com/questions/11204460/the-touchmove-event-on-android-system-transformer-prime | |
setMouse(e); | |
mouseJointDef.bodyB.SetAwake(true); | |
} | |
$(document.body).delegate('.element', 'mousedown touchstart', mousedown); | |
// | |
$(window).load(function () { | |
real.start(); | |
if (window.DeviceMotionEvent) { | |
real.world.m_allowSleep = false; | |
function ondevicemotion(e) { | |
real.world.SetGravity(new b2Vec2(-e.accelerationIncludingGravity.x, e.accelerationIncludingGravity.y)); | |
} | |
window.addEventListener('devicemotion', ondevicemotion, false); | |
} | |
// prevent scroll | |
document.ontouchstart = function(e){ | |
e.preventDefault(); // http://stackoverflow.com/questions/2890361/disable-scrolling-in-an-iphone-web-application#answer-2890530 | |
} | |
// GUI | |
var gui = new dat.GUI; | |
gui.add(real, 'debug').onChange(function(value) { | |
if (value) { | |
real.setDebugDraw(); | |
} else { | |
real.unsetDebugDraw(); | |
} | |
}); | |
$(window).bind('keydown', 'space', function () { | |
console.log('space', real.started); | |
if (real.loop.id) { | |
real.stop(); | |
} else { | |
real.start() | |
} | |
}); | |
}); | |
}(jQuery, Box2D)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset=utf-8> | |
<title>box2d</title> | |
<link rel="stylesheet" href="index.css"> | |
</head> | |
<body> | |
<div class="ball"> | |
<div> | |
<b></b> | |
<b></b> | |
<b></b> | |
</div> | |
</div><br> | |
<div class="crate"></div><br> | |
<div class="crate"></div><div class="crate"></div><br> | |
<!--<div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div><div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div> <div class="crate"></div><div class="crate"></div>--> | |
<div class="ground"></div> | |
<div class="wall left"></div> | |
<div class="wall top"></div> | |
<div class="wall right"></div> | |
<div class="wall bottom"></div> | |
<!--<script src="http://box2dweb.googlecode.com/svn/trunk/Box2D.js"></script> | |
<script src="https://raw.github.com/gist/1579671/rAF.js"></script> | |
<script src="https://raw.github.com/gist/3225993/loop.js"></script> | |
<script src="http://code.jquery.com/jquery-latest.js"></script> | |
<script src="http://dat-gui.googlecode.com/git/build/dat.gui.js"></script>--> | |
<script src="Box2D.js"></script> | |
<script src="rAF.js"></script> | |
<script src="loop.js"></script> | |
<script src="jquery-latest.js"></script> | |
<script src="underscore.js"></script> | |
<script src="backbone.js"></script> | |
<script src="dat.gui.js"></script> | |
<script src="stats.min.js"></script> | |
<script src="jquery.hotkeys.js"></script> | |
<script src="index2.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Flatten Box2d (ugly but handy!) | |
(function b2(o) { | |
for (k in o) { | |
if (o.hasOwnProperty(k)) { | |
if ($.isPlainObject(o[k])) { | |
b2(o[k]); | |
} else if (/^b2/.test(k)) { | |
window[k] = o[k]; | |
} | |
} | |
} | |
}(Box2D)); | |
// Inheritance utility | |
function inherit(child, parent) { | |
for (var key in parent) { | |
if (parent.hasOwnProperty(key)) { | |
child[key] = parent[key]; | |
} | |
} | |
function ctor() {this.constructor = child;} | |
ctor.prototype = parent.prototype; | |
child.prototype = new ctor(); | |
child.uber = parent.prototype; | |
return child; | |
}; | |
var Real = {}; | |
var State = Backbone.Model.extend({}); | |
Real.Element = Backbone.View.extend({ | |
initialize: function () { | |
var origPos = (function () { | |
var $el = this.$el; | |
var offset = $el.offset(); | |
return { | |
left: offset.left, | |
top: offset.top, | |
width: $el.outerWidth(), | |
height: $el.outerHeight() | |
}; | |
}).call(this); | |
this.origPos = origPos; | |
this.state = new State({ | |
x: origPos.left, | |
y: origPos.top, | |
a: 0 | |
}); | |
this.state.on('change', this.render.bind(this)); | |
}, | |
render: function () { | |
var state = this.state; | |
var origPos = this.origPos; | |
this.el.style.webkitTransform = 'translate3d(' + ~~(state.get('x') - origPos.left - origPos.width / 2) + 'px, ' + ~~(state.get('y') - origPos.top - origPos.height / 2) + 'px, 0) rotate3d(0,0,1,' + ~~(state.get('a') * 180 / Math.PI) + 'deg)'; | |
} | |
}); |
This file has been truncated, but you can view the full file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* jQuery JavaScript Library v1.8.0 | |
* http://jquery.com/ | |
* | |
* Includes Sizzle.js | |
* http://sizzlejs.com/ | |
* | |
* Copyright 2012 jQuery Foundation and other contributors | |
* Released under the MIT license | |
* http://jquery.org/license | |
* | |
* Date: Thu Aug 09 2012 16:24:48 GMT-0400 (Eastern Daylight Time) | |
*/ | |
(function( window, undefined ) { | |
var | |
// A central reference to the root jQuery(document) | |
rootjQuery, | |
// The deferred used on DOM ready | |
readyList, | |
// Use the correct document accordingly with window argument (sandbox) | |
document = window.document, | |
location = window.location, | |
navigator = window.navigator, | |
// Map over jQuery in case of overwrite | |
_jQuery = window.jQuery, | |
// Map over the $ in case of overwrite | |
_$ = window.$, | |
// Save a reference to some core methods | |
core_push = Array.prototype.push, | |
core_slice = Array.prototype.slice, | |
core_indexOf = Array.prototype.indexOf, | |
core_toString = Object.prototype.toString, | |
core_hasOwn = Object.prototype.hasOwnProperty, | |
core_trim = String.prototype.trim, | |
// Define a local copy of jQuery | |
jQuery = function( selector, context ) { | |
// The jQuery object is actually just the init constructor 'enhanced' | |
return new jQuery.fn.init( selector, context, rootjQuery ); | |
}, | |
// Used for matching numbers | |
core_pnum = /[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source, | |
// Used for detecting and trimming whitespace | |
core_rnotwhite = /\S/, | |
core_rspace = /\s+/, | |
// IE doesn't match non-breaking spaces with \s | |
rtrim = core_rnotwhite.test("\xA0") ? (/^[\s\xA0]+|[\s\xA0]+$/g) : /^\s+|\s+$/g, | |
// A simple way to check for HTML strings | |
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521) | |
rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, | |
// Match a standalone tag | |
rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, | |
// JSON RegExp | |
rvalidchars = /^[\],:{}\s]*$/, | |
rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, | |
rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, | |
rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g, | |
// Matches dashed string for camelizing | |
rmsPrefix = /^-ms-/, | |
rdashAlpha = /-([\da-z])/gi, | |
// Used by jQuery.camelCase as callback to replace() | |
fcamelCase = function( all, letter ) { | |
return ( letter + "" ).toUpperCase(); | |
}, | |
// The ready event handler and self cleanup method | |
DOMContentLoaded = function() { | |
if ( document.addEventListener ) { | |
document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); | |
jQuery.ready(); | |
} else if ( document.readyState === "complete" ) { | |
// we're here because readyState === "complete" in oldIE | |
// which is good enough for us to call the dom ready! | |
document.detachEvent( "onreadystatechange", DOMContentLoaded ); | |
jQuery.ready(); | |
} | |
}, | |
// [[Class]] -> type pairs | |
class2type = {}; | |
jQuery.fn = jQuery.prototype = { | |
constructor: jQuery, | |
init: function( selector, context, rootjQuery ) { | |
var match, elem, ret, doc; | |
// Handle $(""), $(null), $(undefined), $(false) | |
if ( !selector ) { | |
return this; | |
} | |
// Handle $(DOMElement) | |
if ( selector.nodeType ) { | |
this.context = this[0] = selector; | |
this.length = 1; | |
return this; | |
} | |
// Handle HTML strings | |
if ( typeof selector === "string" ) { | |
if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { | |
// Assume that strings that start and end with <> are HTML and skip the regex check | |
match = [ null, selector, null ]; | |
} else { | |
match = rquickExpr.exec( selector ); | |
} | |
// Match html or make sure no context is specified for #id | |
if ( match && (match[1] || !context) ) { | |
// HANDLE: $(html) -> $(array) | |
if ( match[1] ) { | |
context = context instanceof jQuery ? context[0] : context; | |
doc = ( context && context.nodeType ? context.ownerDocument || context : document ); | |
// scripts is true for back-compat | |
selector = jQuery.parseHTML( match[1], doc, true ); | |
if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { | |
this.attr.call( selector, context, true ); | |
} | |
return jQuery.merge( this, selector ); | |
// HANDLE: $(#id) | |
} else { | |
elem = document.getElementById( match[2] ); | |
// Check parentNode to catch when Blackberry 4.6 returns | |
// nodes that are no longer in the document #6963 | |
if ( elem && elem.parentNode ) { | |
// Handle the case where IE and Opera return items | |
// by name instead of ID | |
if ( elem.id !== match[2] ) { | |
return rootjQuery.find( selector ); | |
} | |
// Otherwise, we inject the element directly into the jQuery object | |
this.length = 1; | |
this[0] = elem; | |
} | |
this.context = document; | |
this.selector = selector; | |
return this; | |
} | |
// HANDLE: $(expr, $(...)) | |
} else if ( !context || context.jquery ) { | |
return ( context || rootjQuery ).find( selector ); | |
// HANDLE: $(expr, context) | |
// (which is just equivalent to: $(context).find(expr) | |
} else { | |
return this.constructor( context ).find( selector ); | |
} | |
// HANDLE: $(function) | |
// Shortcut for document ready | |
} else if ( jQuery.isFunction( selector ) ) { | |
return rootjQuery.ready( selector ); | |
} | |
if ( selector.selector !== undefined ) { | |
this.selector = selector.selector; | |
this.context = selector.context; | |
} | |
return jQuery.makeArray( selector, this ); | |
}, | |
// Start with an empty selector | |
selector: "", | |
// The current version of jQuery being used | |
jquery: "1.8.0", | |
// The default length of a jQuery object is 0 | |
length: 0, | |
// The number of elements contained in the matched element set | |
size: function() { | |
return this.length; | |
}, | |
toArray: function() { | |
return core_slice.call( this ); | |
}, | |
// Get the Nth element in the matched element set OR | |
// Get the whole matched element set as a clean array | |
get: function( num ) { | |
return num == null ? | |
// Return a 'clean' array | |
this.toArray() : | |
// Return just the object | |
( num < 0 ? this[ this.length + num ] : this[ num ] ); | |
}, | |
// Take an array of elements and push it onto the stack | |
// (returning the new matched element set) | |
pushStack: function( elems, name, selector ) { | |
// Build a new jQuery matched element set | |
var ret = jQuery.merge( this.constructor(), elems ); | |
// Add the old object onto the stack (as a reference) | |
ret.prevObject = this; | |
ret.context = this.context; | |
if ( name === "find" ) { | |
ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; | |
} else if ( name ) { | |
ret.selector = this.selector + "." + name + "(" + selector + ")"; | |
} | |
// Return the newly-formed element set | |
return ret; | |
}, | |
// Execute a callback for every element in the matched set. | |
// (You can seed the arguments with an array of args, but this is | |
// only used internally.) | |
each: function( callback, args ) { | |
return jQuery.each( this, callback, args ); | |
}, | |
ready: function( fn ) { | |
// Add the callback | |
jQuery.ready.promise().done( fn ); | |
return this; | |
}, | |
eq: function( i ) { | |
i = +i; | |
return i === -1 ? | |
this.slice( i ) : | |
this.slice( i, i + 1 ); | |
}, | |
first: function() { | |
return this.eq( 0 ); | |
}, | |
last: function() { | |
return this.eq( -1 ); | |
}, | |
slice: function() { | |
return this.pushStack( core_slice.apply( this, arguments ), | |
"slice", core_slice.call(arguments).join(",") ); | |
}, | |
map: function( callback ) { | |
return this.pushStack( jQuery.map(this, function( elem, i ) { | |
return callback.call( elem, i, elem ); | |
})); | |
}, | |
end: function() { | |
return this.prevObject || this.constructor(null); | |
}, | |
// For internal use only. | |
// Behaves like an Array's method, not like a jQuery method. | |
push: core_push, | |
sort: [].sort, | |
splice: [].splice | |
}; | |
// Give the init function the jQuery prototype for later instantiation | |
jQuery.fn.init.prototype = jQuery.fn; | |
jQuery.extend = jQuery.fn.extend = function() { | |
var options, name, src, copy, copyIsArray, clone, | |
target = arguments[0] || {}, | |
i = 1, | |
length = arguments.length, | |
deep = false; | |
// Handle a deep copy situation | |
if ( typeof target === "boolean" ) { | |
deep = target; | |
target = arguments[1] || {}; | |
// skip the boolean and the target | |
i = 2; | |
} | |
// Handle case when target is a string or something (possible in deep copy) | |
if ( typeof target !== "object" && !jQuery.isFunction(target) ) { | |
target = {}; | |
} | |
// extend jQuery itself if only one argument is passed | |
if ( length === i ) { | |
target = this; | |
--i; | |
} | |
for ( ; i < length; i++ ) { | |
// Only deal with non-null/undefined values | |
if ( (options = arguments[ i ]) != null ) { | |
// Extend the base object | |
for ( name in options ) { | |
src = target[ name ]; | |
copy = options[ name ]; | |
// Prevent never-ending loop | |
if ( target === copy ) { | |
continue; | |
} | |
// Recurse if we're merging plain objects or arrays | |
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { | |
if ( copyIsArray ) { | |
copyIsArray = false; | |
clone = src && jQuery.isArray(src) ? src : []; | |
} else { | |
clone = src && jQuery.isPlainObject(src) ? src : {}; | |
} | |
// Never move original objects, clone them | |
target[ name ] = jQuery.extend( deep, clone, copy ); | |
// Don't bring in undefined values | |
} else if ( copy !== undefined ) { | |
target[ name ] = copy; | |
} | |
} | |
} | |
} | |
// Return the modified object | |
return target; | |
}; | |
jQuery.extend({ | |
noConflict: function( deep ) { | |
if ( window.$ === jQuery ) { | |
window.$ = _$; | |
} | |
if ( deep && window.jQuery === jQuery ) { | |
window.jQuery = _jQuery; | |
} | |
return jQuery; | |
}, | |
// Is the DOM ready to be used? Set to true once it occurs. | |
isReady: false, | |
// A counter to track how many items to wait for before | |
// the ready event fires. See #6781 | |
readyWait: 1, | |
// Hold (or release) the ready event | |
holdReady: function( hold ) { | |
if ( hold ) { | |
jQuery.readyWait++; | |
} else { | |
jQuery.ready( true ); | |
} | |
}, | |
// Handle when the DOM is ready | |
ready: function( wait ) { | |
// Abort if there are pending holds or we're already ready | |
if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { | |
return; | |
} | |
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). | |
if ( !document.body ) { | |
return setTimeout( jQuery.ready, 1 ); | |
} | |
// Remember that the DOM is ready | |
jQuery.isReady = true; | |
// If a normal DOM Ready event fired, decrement, and wait if need be | |
if ( wait !== true && --jQuery.readyWait > 0 ) { | |
return; | |
} | |
// If there are functions bound, to execute | |
readyList.resolveWith( document, [ jQuery ] ); | |
// Trigger any bound ready events | |
if ( jQuery.fn.trigger ) { | |
jQuery( document ).trigger("ready").off("ready"); | |
} | |
}, | |
// See test/unit/core.js for details concerning isFunction. | |
// Since version 1.3, DOM methods and functions like alert | |
// aren't supported. They return false on IE (#2968). | |
isFunction: function( obj ) { | |
return jQuery.type(obj) === "function"; | |
}, | |
isArray: Array.isArray || function( obj ) { | |
return jQuery.type(obj) === "array"; | |
}, | |
isWindow: function( obj ) { | |
return obj != null && obj == obj.window; | |
}, | |
isNumeric: function( obj ) { | |
return !isNaN( parseFloat(obj) ) && isFinite( obj ); | |
}, | |
type: function( obj ) { | |
return obj == null ? | |
String( obj ) : | |
class2type[ core_toString.call(obj) ] || "object"; | |
}, | |
isPlainObject: function( obj ) { | |
// Must be an Object. | |
// Because of IE, we also have to check the presence of the constructor property. | |
// Make sure that DOM nodes and window objects don't pass through, as well | |
if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { | |
return false; | |
} | |
try { | |
// Not own constructor property must be Object | |
if ( obj.constructor && | |
!core_hasOwn.call(obj, "constructor") && | |
!core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { | |
return false; | |
} | |
} catch ( e ) { | |
// IE8,9 Will throw exceptions on certain host objects #9897 | |
return false; | |
} | |
// Own properties are enumerated firstly, so to speed up, | |
// if last one is own, then all properties are own. | |
var key; | |
for ( key in obj ) {} | |
return key === undefined || core_hasOwn.call( obj, key ); | |
}, | |
isEmptyObject: function( obj ) { | |
var name; | |
for ( name in obj ) { | |
return false; | |
} | |
return true; | |
}, | |
error: function( msg ) { | |
throw new Error( msg ); | |
}, | |
// data: string of html | |
// context (optional): If specified, the fragment will be created in this context, defaults to document | |
// scripts (optional): If true, will include scripts passed in the html string | |
parseHTML: function( data, context, scripts ) { | |
var parsed; | |
if ( !data || typeof data !== "string" ) { | |
return null; | |
} | |
if ( typeof context === "boolean" ) { | |
scripts = context; | |
context = 0; | |
} | |
context = context || document; | |
// Single tag | |
if ( (parsed = rsingleTag.exec( data )) ) { | |
return [ context.createElement( parsed[1] ) ]; | |
} | |
parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] ); | |
return jQuery.merge( [], | |
(parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes ); | |
}, | |
parseJSON: function( data ) { | |
if ( !data || typeof data !== "string") { | |
return null; | |
} | |
// Make sure leading/trailing whitespace is removed (IE can't handle it) | |
data = jQuery.trim( data ); | |
// Attempt to parse using the native JSON parser first | |
if ( window.JSON && window.JSON.parse ) { | |
return window.JSON.parse( data ); | |
} | |
// Make sure the incoming data is actual JSON | |
// Logic borrowed from http://json.org/json2.js | |
if ( rvalidchars.test( data.replace( rvalidescape, "@" ) | |
.replace( rvalidtokens, "]" ) | |
.replace( rvalidbraces, "")) ) { | |
return ( new Function( "return " + data ) )(); | |
} | |
jQuery.error( "Invalid JSON: " + data ); | |
}, | |
// Cross-browser xml parsing | |
parseXML: function( data ) { | |
var xml, tmp; | |
if ( !data || typeof data !== "string" ) { | |
return null; | |
} | |
try { | |
if ( window.DOMParser ) { // Standard | |
tmp = new DOMParser(); | |
xml = tmp.parseFromString( data , "text/xml" ); | |
} else { // IE | |
xml = new ActiveXObject( "Microsoft.XMLDOM" ); | |
xml.async = "false"; | |
xml.loadXML( data ); | |
} | |
} catch( e ) { | |
xml = undefined; | |
} | |
if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { | |
jQuery.error( "Invalid XML: " + data ); | |
} | |
return xml; | |
}, | |
noop: function() {}, | |
// Evaluates a script in a global context | |
// Workarounds based on findings by Jim Driscoll | |
// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context | |
globalEval: function( data ) { | |
if ( data && core_rnotwhite.test( data ) ) { | |
// We use execScript on Internet Explorer | |
// We use an anonymous function so that context is window | |
// rather than jQuery in Firefox | |
( window.execScript || function( data ) { | |
window[ "eval" ].call( window, data ); | |
} )( data ); | |
} | |
}, | |
// Convert dashed to camelCase; used by the css and data modules | |
// Microsoft forgot to hump their vendor prefix (#9572) | |
camelCase: function( string ) { | |
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); | |
}, | |
nodeName: function( elem, name ) { | |
return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); | |
}, | |
// args is for internal usage only | |
each: function( obj, callback, args ) { | |
var name, | |
i = 0, | |
length = obj.length, | |
isObj = length === undefined || jQuery.isFunction( obj ); | |
if ( args ) { | |
if ( isObj ) { | |
for ( name in obj ) { | |
if ( callback.apply( obj[ name ], args ) === false ) { | |
break; | |
} | |
} | |
} else { | |
for ( ; i < length; ) { | |
if ( callback.apply( obj[ i++ ], args ) === false ) { | |
break; | |
} | |
} | |
} | |
// A special, fast, case for the most common use of each | |
} else { | |
if ( isObj ) { | |
for ( name in obj ) { | |
if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) { | |
break; | |
} | |
} | |
} else { | |
for ( ; i < length; ) { | |
if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) { | |
break; | |
} | |
} | |
} | |
} | |
return obj; | |
}, | |
// Use native String.trim function wherever possible | |
trim: core_trim ? | |
function( text ) { | |
return text == null ? | |
"" : | |
core_trim.call( text ); | |
} : | |
// Otherwise use our own trimming functionality | |
function( text ) { | |
return text == null ? | |
"" : | |
text.toString().replace( rtrim, "" ); | |
}, | |
// results is for internal usage only | |
makeArray: function( arr, results ) { | |
var type, | |
ret = results || []; | |
if ( arr != null ) { | |
// The window, strings (and functions) also have 'length' | |
// Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 | |
type = jQuery.type( arr ); | |
if ( arr.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( arr ) ) { | |
core_push.call( ret, arr ); | |
} else { | |
jQuery.merge( ret, arr ); | |
} | |
} | |
return ret; | |
}, | |
inArray: function( elem, arr, i ) { | |
var len; | |
if ( arr ) { | |
if ( core_indexOf ) { | |
return core_indexOf.call( arr, elem, i ); | |
} | |
len = arr.length; | |
i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; | |
for ( ; i < len; i++ ) { | |
// Skip accessing in sparse arrays | |
if ( i in arr && arr[ i ] === elem ) { | |
return i; | |
} | |
} | |
} | |
return -1; | |
}, | |
merge: function( first, second ) { | |
var l = second.length, | |
i = first.length, | |
j = 0; | |
if ( typeof l === "number" ) { | |
for ( ; j < l; j++ ) { | |
first[ i++ ] = second[ j ]; | |
} | |
} else { | |
while ( second[j] !== undefined ) { | |
first[ i++ ] = second[ j++ ]; | |
} | |
} | |
first.length = i; | |
return first; | |
}, | |
grep: function( elems, callback, inv ) { | |
var retVal, | |
ret = [], | |
i = 0, | |
length = elems.length; | |
inv = !!inv; | |
// Go through the array, only saving the items | |
// that pass the validator function | |
for ( ; i < length; i++ ) { | |
retVal = !!callback( elems[ i ], i ); | |
if ( inv !== retVal ) { | |
ret.push( elems[ i ] ); | |
} | |
} | |
return ret; | |
}, | |
// arg is for internal usage only | |
map: function( elems, callback, arg ) { | |
var value, key, | |
ret = [], | |
i = 0, | |
length = elems.length, | |
// jquery objects are treated as arrays | |
isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; | |
// Go through the array, translating each of the items to their | |
if ( isArray ) { | |
for ( ; i < length; i++ ) { | |
value = callback( elems[ i ], i, arg ); | |
if ( value != null ) { | |
ret[ ret.length ] = value; | |
} | |
} | |
// Go through every key on the object, | |
} else { | |
for ( key in elems ) { | |
value = callback( elems[ key ], key, arg ); | |
if ( value != null ) { | |
ret[ ret.length ] = value; | |
} | |
} | |
} | |
// Flatten any nested arrays | |
return ret.concat.apply( [], ret ); | |
}, | |
// A global GUID counter for objects | |
guid: 1, | |
// Bind a function to a context, optionally partially applying any | |
// arguments. | |
proxy: function( fn, context ) { | |
var tmp, args, proxy; | |
if ( typeof context === "string" ) { | |
tmp = fn[ context ]; | |
context = fn; | |
fn = tmp; | |
} | |
// Quick check to determine if target is callable, in the spec | |
// this throws a TypeError, but we will just return undefined. | |
if ( !jQuery.isFunction( fn ) ) { | |
return undefined; | |
} | |
// Simulated bind | |
args = core_slice.call( arguments, 2 ); | |
proxy = function() { | |
return fn.apply( context, args.concat( core_slice.call( arguments ) ) ); | |
}; | |
// Set the guid of unique handler to the same of original handler, so it can be removed | |
proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; | |
return proxy; | |
}, | |
// Multifunctional method to get and set values of a collection | |
// The value/s can optionally be executed if it's a function | |
access: function( elems, fn, key, value, chainable, emptyGet, pass ) { | |
var exec, | |
bulk = key == null, | |
i = 0, | |
length = elems.length; | |
// Sets many values | |
if ( key && typeof key === "object" ) { | |
for ( i in key ) { | |
jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); | |
} | |
chainable = 1; | |
// Sets one value | |
} else if ( value !== undefined ) { | |
// Optionally, function values get executed if exec is true | |
exec = pass === undefined && jQuery.isFunction( value ); | |
if ( bulk ) { | |
// Bulk operations only iterate when executing function values | |
if ( exec ) { | |
exec = fn; | |
fn = function( elem, key, value ) { | |
return exec.call( jQuery( elem ), value ); | |
}; | |
// Otherwise they run against the entire set | |
} else { | |
fn.call( elems, value ); | |
fn = null; | |
} | |
} | |
if ( fn ) { | |
for (; i < length; i++ ) { | |
fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); | |
} | |
} | |
chainable = 1; | |
} | |
return chainable ? | |
elems : | |
// Gets | |
bulk ? | |
fn.call( elems ) : | |
length ? fn( elems[0], key ) : emptyGet; | |
}, | |
now: function() { | |
return ( new Date() ).getTime(); | |
} | |
}); | |
jQuery.ready.promise = function( obj ) { | |
if ( !readyList ) { | |
readyList = jQuery.Deferred(); | |
// Catch cases where $(document).ready() is called after the | |
// browser event has already occurred. | |
if ( document.readyState === "complete" || ( document.readyState !== "loading" && document.addEventListener ) ) { | |
// Handle it asynchronously to allow scripts the opportunity to delay ready | |
setTimeout( jQuery.ready, 1 ); | |
// Standards-based browsers support DOMContentLoaded | |
} else if ( document.addEventListener ) { | |
// Use the handy event callback | |
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); | |
// A fallback to window.onload, that will always work | |
window.addEventListener( "load", jQuery.ready, false ); | |
// If IE event model is used | |
} else { | |
// Ensure firing before onload, maybe late but safe also for iframes | |
document.attachEvent( "onreadystatechange", DOMContentLoaded ); | |
// A fallback to window.onload, that will always work | |
window.attachEvent( "onload", jQuery.ready ); | |
// If IE and not a frame | |
// continually check to see if the document is ready | |
var top = false; | |
try { | |
top = window.frameElement == null && document.documentElement; | |
} catch(e) {} | |
if ( top && top.doScroll ) { | |
(function doScrollCheck() { | |
if ( !jQuery.isReady ) { | |
try { | |
// Use the trick by Diego Perini | |
// http://javascript.nwbox.com/IEContentLoaded/ | |
top.doScroll("left"); | |
} catch(e) { | |
return setTimeout( doScrollCheck, 50 ); | |
} | |
// and execute any waiting functions | |
jQuery.ready(); | |
} | |
})(); | |
} | |
} | |
} | |
return readyList.promise( obj ); | |
}; | |
// Populate the class2type map | |
jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { | |
class2type[ "[object " + name + "]" ] = name.toLowerCase(); | |
}); | |
// All jQuery objects should point back to these | |
rootjQuery = jQuery(document); | |
// String to Object options format cache | |
var optionsCache = {}; | |
// Convert String-formatted options into Object-formatted ones and store in cache | |
function createOptions( options ) { | |
var object = optionsCache[ options ] = {}; | |
jQuery.each( options.split( core_rspace ), function( _, flag ) { | |
object[ flag ] = true; | |
}); | |
return object; | |
} | |
/* | |
* Create a callback list using the following parameters: | |
* | |
* options: an optional list of space-separated options that will change how | |
* the callback list behaves or a more traditional option object | |
* | |
* By default a callback list will act like an event callback list and can be | |
* "fired" multiple times. | |
* | |
* Possible options: | |
* | |
* once: will ensure the callback list can only be fired once (like a Deferred) | |
* | |
* memory: will keep track of previous values and will call any callback added | |
* after the list has been fired right away with the latest "memorized" | |
* values (like a Deferred) | |
* | |
* unique: will ensure a callback can only be added once (no duplicate in the list) | |
* | |
* stopOnFalse: interrupt callings when a callback returns false | |
* | |
*/ | |
jQuery.Callbacks = function( options ) { | |
// Convert options from String-formatted to Object-formatted if needed | |
// (we check in cache first) | |
options = typeof options === "string" ? | |
( optionsCache[ options ] || createOptions( options ) ) : | |
jQuery.extend( {}, options ); | |
var // Last fire value (for non-forgettable lists) | |
memory, | |
// Flag to know if list was already fired | |
fired, | |
// Flag to know if list is currently firing | |
firing, | |
// First callback to fire (used internally by add and fireWith) | |
firingStart, | |
// End of the loop when firing | |
firingLength, | |
// Index of currently firing callback (modified by remove if needed) | |
firingIndex, | |
// Actual callback list | |
list = [], | |
// Stack of fire calls for repeatable lists | |
stack = !options.once && [], | |
// Fire callbacks | |
fire = function( data ) { | |
memory = options.memory && data; | |
fired = true; | |
firingIndex = firingStart || 0; | |
firingStart = 0; | |
firingLength = list.length; | |
firing = true; | |
for ( ; list && firingIndex < firingLength; firingIndex++ ) { | |
if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { | |
memory = false; // To prevent further calls using add | |
break; | |
} | |
} | |
firing = false; | |
if ( list ) { | |
if ( stack ) { | |
if ( stack.length ) { | |
fire( stack.shift() ); | |
} | |
} else if ( memory ) { | |
list = []; | |
} else { | |
self.disable(); | |
} | |
} | |
}, | |
// Actual Callbacks object | |
self = { | |
// Add a callback or a collection of callbacks to the list | |
add: function() { | |
if ( list ) { | |
// First, we save the current length | |
var start = list.length; | |
(function add( args ) { | |
jQuery.each( args, function( _, arg ) { | |
if ( jQuery.isFunction( arg ) && ( !options.unique || !self.has( arg ) ) ) { | |
list.push( arg ); | |
} else if ( arg && arg.length ) { | |
// Inspect recursively | |
add( arg ); | |
} | |
}); | |
})( arguments ); | |
// Do we need to add the callbacks to the | |
// current firing batch? | |
if ( firing ) { | |
firingLength = list.length; | |
// With memory, if we're not firing then | |
// we should call right away | |
} else if ( memory ) { | |
firingStart = start; | |
fire( memory ); | |
} | |
} | |
return this; | |
}, | |
// Remove a callback from the list | |
remove: function() { | |
if ( list ) { | |
jQuery.each( arguments, function( _, arg ) { | |
var index; | |
while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { | |
list.splice( index, 1 ); | |
// Handle firing indexes | |
if ( firing ) { | |
if ( index <= firingLength ) { | |
firingLength--; | |
} | |
if ( index <= firingIndex ) { | |
firingIndex--; | |
} | |
} | |
} | |
}); | |
} | |
return this; | |
}, | |
// Control if a given callback is in the list | |
has: function( fn ) { | |
return jQuery.inArray( fn, list ) > -1; | |
}, | |
// Remove all callbacks from the list | |
empty: function() { | |
list = []; | |
return this; | |
}, | |
// Have the list do nothing anymore | |
disable: function() { | |
list = stack = memory = undefined; | |
return this; | |
}, | |
// Is it disabled? | |
disabled: function() { | |
return !list; | |
}, | |
// Lock the list in its current state | |
lock: function() { | |
stack = undefined; | |
if ( !memory ) { | |
self.disable(); | |
} | |
return this; | |
}, | |
// Is it locked? | |
locked: function() { | |
return !stack; | |
}, | |
// Call all callbacks with the given context and arguments | |
fireWith: function( context, args ) { | |
args = args || []; | |
args = [ context, args.slice ? args.slice() : args ]; | |
if ( list && ( !fired || stack ) ) { | |
if ( firing ) { | |
stack.push( args ); | |
} else { | |
fire( args ); | |
} | |
} | |
return this; | |
}, | |
// Call all the callbacks with the given arguments | |
fire: function() { | |
self.fireWith( this, arguments ); | |
return this; | |
}, | |
// To know if the callbacks have already been called at least once | |
fired: function() { | |
return !!fired; | |
} | |
}; | |
return self; | |
}; | |
jQuery.extend({ | |
Deferred: function( func ) { | |
var tuples = [ | |
// action, add listener, listener list, final state | |
[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], | |
[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], | |
[ "notify", "progress", jQuery.Callbacks("memory") ] | |
], | |
state = "pending", | |
promise = { | |
state: function() { | |
return state; | |
}, | |
always: function() { | |
deferred.done( arguments ).fail( arguments ); | |
return this; | |
}, | |
then: function( /* fnDone, fnFail, fnProgress */ ) { | |
var fns = arguments; | |
return jQuery.Deferred(function( newDefer ) { | |
jQuery.each( tuples, function( i, tuple ) { | |
var action = tuple[ 0 ], | |
fn = fns[ i ]; | |
// deferred[ done | fail | progress ] for forwarding actions to newDefer | |
deferred[ tuple[1] ]( jQuery.isFunction( fn ) ? | |
function() { | |
var returned = fn.apply( this, arguments ); | |
if ( returned && jQuery.isFunction( returned.promise ) ) { | |
returned.promise() | |
.done( newDefer.resolve ) | |
.fail( newDefer.reject ) | |
.progress( newDefer.notify ); | |
} else { | |
newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); | |
} | |
} : | |
newDefer[ action ] | |
); | |
}); | |
fns = null; | |
}).promise(); | |
}, | |
// Get a promise for this deferred | |
// If obj is provided, the promise aspect is added to the object | |
promise: function( obj ) { | |
return typeof obj === "object" ? jQuery.extend( obj, promise ) : promise; | |
} | |
}, | |
deferred = {}; | |
// Keep pipe for back-compat | |
promise.pipe = promise.then; | |
// Add list-specific methods | |
jQuery.each( tuples, function( i, tuple ) { | |
var list = tuple[ 2 ], | |
stateString = tuple[ 3 ]; | |
// promise[ done | fail | progress ] = list.add | |
promise[ tuple[1] ] = list.add; | |
// Handle state | |
if ( stateString ) { | |
list.add(function() { | |
// state = [ resolved | rejected ] | |
state = stateString; | |
// [ reject_list | resolve_list ].disable; progress_list.lock | |
}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); | |
} | |
// deferred[ resolve | reject | notify ] = list.fire | |
deferred[ tuple[0] ] = list.fire; | |
deferred[ tuple[0] + "With" ] = list.fireWith; | |
}); | |
// Make the deferred a promise | |
promise.promise( deferred ); | |
// Call given func if any | |
if ( func ) { | |
func.call( deferred, deferred ); | |
} | |
// All done! | |
return deferred; | |
}, | |
// Deferred helper | |
when: function( subordinate /* , ..., subordinateN */ ) { | |
var i = 0, | |
resolveValues = core_slice.call( arguments ), | |
length = resolveValues.length, | |
// the count of uncompleted subordinates | |
remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, | |
// the master Deferred. If resolveValues consist of only a single Deferred, just use that. | |
deferred = remaining === 1 ? subordinate : jQuery.Deferred(), | |
// Update function for both resolve and progress values | |
updateFunc = function( i, contexts, values ) { | |
return function( value ) { | |
contexts[ i ] = this; | |
values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; | |
if( values === progressValues ) { | |
deferred.notifyWith( contexts, values ); | |
} else if ( !( --remaining ) ) { | |
deferred.resolveWith( contexts, values ); | |
} | |
}; | |
}, | |
progressValues, progressContexts, resolveContexts; | |
// add listeners to Deferred subordinates; treat others as resolved | |
if ( length > 1 ) { | |
progressValues = new Array( length ); | |
progressContexts = new Array( length ); | |
resolveContexts = new Array( length ); | |
for ( ; i < length; i++ ) { | |
if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { | |
resolveValues[ i ].promise() | |
.done( updateFunc( i, resolveContexts, resolveValues ) ) | |
.fail( deferred.reject ) | |
.progress( updateFunc( i, progressContexts, progressValues ) ); | |
} else { | |
--remaining; | |
} | |
} | |
} | |
// if we're not waiting on anything, resolve the master | |
if ( !remaining ) { | |
deferred.resolveWith( resolveContexts, resolveValues ); | |
} | |
return deferred.promise(); | |
} | |
}); | |
jQuery.support = (function() { | |
var support, | |
all, | |
a, | |
select, | |
opt, | |
input, | |
fragment, | |
eventName, | |
i, | |
isSupported, | |
clickFn, | |
div = document.createElement("div"); | |
// Preliminary tests | |
div.setAttribute( "className", "t" ); | |
div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>"; | |
all = div.getElementsByTagName("*"); | |
a = div.getElementsByTagName("a")[ 0 ]; | |
a.style.cssText = "top:1px;float:left;opacity:.5"; | |
// Can't get basic test support | |
if ( !all || !all.length || !a ) { | |
return {}; | |
} | |
// First batch of supports tests | |
select = document.createElement("select"); | |
opt = select.appendChild( document.createElement("option") ); | |
input = div.getElementsByTagName("input")[ 0 ]; | |
support = { | |
// IE strips leading whitespace when .innerHTML is used | |
leadingWhitespace: ( div.firstChild.nodeType === 3 ), | |
// Make sure that tbody elements aren't automatically inserted | |
// IE will insert them into empty tables | |
tbody: !div.getElementsByTagName("tbody").length, | |
// Make sure that link elements get serialized correctly by innerHTML | |
// This requires a wrapper element in IE | |
htmlSerialize: !!div.getElementsByTagName("link").length, | |
// Get the style information from getAttribute | |
// (IE uses .cssText instead) | |
style: /top/.test( a.getAttribute("style") ), | |
// Make sure that URLs aren't manipulated | |
// (IE normalizes it by default) | |
hrefNormalized: ( a.getAttribute("href") === "/a" ), | |
// Make sure that element opacity exists | |
// (IE uses filter instead) | |
// Use a regex to work around a WebKit issue. See #5145 | |
opacity: /^0.5/.test( a.style.opacity ), | |
// Verify style float existence | |
// (IE uses styleFloat instead of cssFloat) | |
cssFloat: !!a.style.cssFloat, | |
// Make sure that if no value is specified for a checkbox | |
// that it defaults to "on". | |
// (WebKit defaults to "" instead) | |
checkOn: ( input.value === "on" ), | |
// Make sure that a selected-by-default option has a working selected property. | |
// (WebKit defaults to false instead of true, IE too, if it's in an optgroup) | |
optSelected: opt.selected, | |
// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) | |
getSetAttribute: div.className !== "t", | |
// Tests for enctype support on a form(#6743) | |
enctype: !!document.createElement("form").enctype, | |
// Makes sure cloning an html5 element does not cause problems | |
// Where outerHTML is undefined, this still works | |
html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>", | |
// jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode | |
boxModel: ( document.compatMode === "CSS1Compat" ), | |
// Will be defined later | |
submitBubbles: true, | |
changeBubbles: true, | |
focusinBubbles: false, | |
deleteExpando: true, | |
noCloneEvent: true, | |
inlineBlockNeedsLayout: false, | |
shrinkWrapBlocks: false, | |
reliableMarginRight: true, | |
boxSizingReliable: true, | |
pixelPosition: false | |
}; | |
// Make sure checked status is properly cloned | |
input.checked = true; | |
support.noCloneChecked = input.cloneNode( true ).checked; | |
// Make sure that the options inside disabled selects aren't marked as disabled | |
// (WebKit marks them as disabled) | |
select.disabled = true; | |
support.optDisabled = !opt.disabled; | |
// Test to see if it's possible to delete an expando from an element | |
// Fails in Internet Explorer | |
try { | |
delete div.test; | |
} catch( e ) { | |
support.deleteExpando = false; | |
} | |
if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { | |
div.attachEvent( "onclick", clickFn = function() { | |
// Cloning a node shouldn't copy over any | |
// bound event handlers (IE does this) | |
support.noCloneEvent = false; | |
}); | |
div.cloneNode( true ).fireEvent("onclick"); | |
div.detachEvent( "onclick", clickFn ); | |
} | |
// Check if a radio maintains its value | |
// after being appended to the DOM | |
input = document.createElement("input"); | |
input.value = "t"; | |
input.setAttribute( "type", "radio" ); | |
support.radioValue = input.value === "t"; | |
input.setAttribute( "checked", "checked" ); | |
// #11217 - WebKit loses check when the name is after the checked attribute | |
input.setAttribute( "name", "t" ); | |
div.appendChild( input ); | |
fragment = document.createDocumentFragment(); | |
fragment.appendChild( div.lastChild ); | |
// WebKit doesn't clone checked state correctly in fragments | |
support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; | |
// Check if a disconnected checkbox will retain its checked | |
// value of true after appended to the DOM (IE6/7) | |
support.appendChecked = input.checked; | |
fragment.removeChild( input ); | |
fragment.appendChild( div ); | |
// Technique from Juriy Zaytsev | |
// http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ | |
// We only care about the case where non-standard event systems | |
// are used, namely in IE. Short-circuiting here helps us to | |
// avoid an eval call (in setAttribute) which can cause CSP | |
// to go haywire. See: https://developer.mozilla.org/en/Security/CSP | |
if ( div.attachEvent ) { | |
for ( i in { | |
submit: true, | |
change: true, | |
focusin: true | |
}) { | |
eventName = "on" + i; | |
isSupported = ( eventName in div ); | |
if ( !isSupported ) { | |
div.setAttribute( eventName, "return;" ); | |
isSupported = ( typeof div[ eventName ] === "function" ); | |
} | |
support[ i + "Bubbles" ] = isSupported; | |
} | |
} | |
// Run tests that need a body at doc ready | |
jQuery(function() { | |
var container, div, tds, marginDiv, | |
divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;", | |
body = document.getElementsByTagName("body")[0]; | |
if ( !body ) { | |
// Return for frameset docs that don't have a body | |
return; | |
} | |
container = document.createElement("div"); | |
container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px"; | |
body.insertBefore( container, body.firstChild ); | |
// Construct the test element | |
div = document.createElement("div"); | |
container.appendChild( div ); | |
// Check if table cells still have offsetWidth/Height when they are set | |
// to display:none and there are still other visible table cells in a | |
// table row; if so, offsetWidth/Height are not reliable for use when | |
// determining if an element has been hidden directly using | |
// display:none (it is still safe to use offsets if a parent element is | |
// hidden; don safety goggles and see bug #4512 for more information). | |
// (only IE 8 fails this test) | |
div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>"; | |
tds = div.getElementsByTagName("td"); | |
tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; | |
isSupported = ( tds[ 0 ].offsetHeight === 0 ); | |
tds[ 0 ].style.display = ""; | |
tds[ 1 ].style.display = "none"; | |
// Check if empty table cells still have offsetWidth/Height | |
// (IE <= 8 fail this test) | |
support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); | |
// Check box-sizing and margin behavior | |
div.innerHTML = ""; | |
div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; | |
support.boxSizing = ( div.offsetWidth === 4 ); | |
support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 ); | |
// NOTE: To any future maintainer, window.getComputedStyle was used here | |
// instead of getComputedStyle because it gave a better gzip size. | |
// The difference between window.getComputedStyle and getComputedStyle is | |
// 7 bytes | |
if ( window.getComputedStyle ) { | |
support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; | |
support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; | |
// Check if div with explicit width and no margin-right incorrectly | |
// gets computed margin-right based on width of container. For more | |
// info see bug #3333 | |
// Fails in WebKit before Feb 2011 nightlies | |
// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right | |
marginDiv = document.createElement("div"); | |
marginDiv.style.cssText = div.style.cssText = divReset; | |
marginDiv.style.marginRight = marginDiv.style.width = "0"; | |
div.style.width = "1px"; | |
div.appendChild( marginDiv ); | |
support.reliableMarginRight = | |
!parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); | |
} | |
if ( typeof div.style.zoom !== "undefined" ) { | |
// Check if natively block-level elements act like inline-block | |
// elements when setting their display to 'inline' and giving | |
// them layout | |
// (IE < 8 does this) | |
div.innerHTML = ""; | |
div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; | |
support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); | |
// Check if elements with layout shrink-wrap their children | |
// (IE 6 does this) | |
div.style.display = "block"; | |
div.style.overflow = "visible"; | |
div.innerHTML = "<div></div>"; | |
div.firstChild.style.width = "5px"; | |
support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); | |
container.style.zoom = 1; | |
} | |
// Null elements to avoid leaks in IE | |
body.removeChild( container ); | |
container = div = tds = marginDiv = null; | |
}); | |
// Null elements to avoid leaks in IE | |
fragment.removeChild( div ); | |
all = a = select = opt = input = fragment = div = null; | |
return support; | |
})(); | |
var rbrace = /^(?:\{.*\}|\[.*\])$/, | |
rmultiDash = /([A-Z])/g; | |
jQuery.extend({ | |
cache: {}, | |
deletedIds: [], | |
// Please use with caution | |
uuid: 0, | |
// Unique for each copy of jQuery on the page | |
// Non-digits removed to match rinlinejQuery | |
expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), | |
// The following elements throw uncatchable exceptions if you | |
// attempt to add expando properties to them. | |
noData: { | |
"embed": true, | |
// Ban all objects except for Flash (which handle expandos) | |
"object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", | |
"applet": true | |
}, | |
hasData: function( elem ) { | |
elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; | |
return !!elem && !isEmptyDataObject( elem ); | |
}, | |
data: function( elem, name, data, pvt /* Internal Use Only */ ) { | |
if ( !jQuery.acceptData( elem ) ) { | |
return; | |
} | |
var thisCache, ret, | |
internalKey = jQuery.expando, | |
getByName = typeof name === "string", | |
// We have to handle DOM nodes and JS objects differently because IE6-7 | |
// can't GC object references properly across the DOM-JS boundary | |
isNode = elem.nodeType, | |
// Only DOM nodes need the global jQuery cache; JS object data is | |
// attached directly to the object so GC can occur automatically | |
cache = isNode ? jQuery.cache : elem, | |
// Only defining an ID for JS objects if its cache already exists allows | |
// the code to shortcut on the same path as a DOM node with no cache | |
id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; | |
// Avoid doing any more work than we need to when trying to get data on an | |
// object that has no data at all | |
if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) { | |
return; | |
} | |
if ( !id ) { | |
// Only DOM nodes need a new unique ID for each element since their data | |
// ends up in the global cache | |
if ( isNode ) { | |
elem[ internalKey ] = id = jQuery.deletedIds.pop() || ++jQuery.uuid; | |
} else { | |
id = internalKey; | |
} | |
} | |
if ( !cache[ id ] ) { | |
cache[ id ] = {}; | |
// Avoids exposing jQuery metadata on plain JS objects when the object | |
// is serialized using JSON.stringify | |
if ( !isNode ) { | |
cache[ id ].toJSON = jQuery.noop; | |
} | |
} | |
// An object can be passed to jQuery.data instead of a key/value pair; this gets | |
// shallow copied over onto the existing cache | |
if ( typeof name === "object" || typeof name === "function" ) { | |
if ( pvt ) { | |
cache[ id ] = jQuery.extend( cache[ id ], name ); | |
} else { | |
cache[ id ].data = jQuery.extend( cache[ id ].data, name ); | |
} | |
} | |
thisCache = cache[ id ]; | |
// jQuery data() is stored in a separate object inside the object's internal data | |
// cache in order to avoid key collisions between internal data and user-defined | |
// data. | |
if ( !pvt ) { | |
if ( !thisCache.data ) { | |
thisCache.data = {}; | |
} | |
thisCache = thisCache.data; | |
} | |
if ( data !== undefined ) { | |
thisCache[ jQuery.camelCase( name ) ] = data; | |
} | |
// Check for both converted-to-camel and non-converted data property names | |
// If a data property was specified | |
if ( getByName ) { | |
// First Try to find as-is property data | |
ret = thisCache[ name ]; | |
// Test for null|undefined property data | |
if ( ret == null ) { | |
// Try to find the camelCased property | |
ret = thisCache[ jQuery.camelCase( name ) ]; | |
} | |
} else { | |
ret = thisCache; | |
} | |
return ret; | |
}, | |
removeData: function( elem, name, pvt /* Internal Use Only */ ) { | |
if ( !jQuery.acceptData( elem ) ) { | |
return; | |
} | |
var thisCache, i, l, | |
isNode = elem.nodeType, | |
// See jQuery.data for more information | |
cache = isNode ? jQuery.cache : elem, | |
id = isNode ? elem[ jQuery.expando ] : jQuery.expando; | |
// If there is already no cache entry for this object, there is no | |
// purpose in continuing | |
if ( !cache[ id ] ) { | |
return; | |
} | |
if ( name ) { | |
thisCache = pvt ? cache[ id ] : cache[ id ].data; | |
if ( thisCache ) { | |
// Support array or space separated string names for data keys | |
if ( !jQuery.isArray( name ) ) { | |
// try the string as a key before any manipulation | |
if ( name in thisCache ) { | |
name = [ name ]; | |
} else { | |
// split the camel cased version by spaces unless a key with the spaces exists | |
name = jQuery.camelCase( name ); | |
if ( name in thisCache ) { | |
name = [ name ]; | |
} else { | |
name = name.split(" "); | |
} | |
} | |
} | |
for ( i = 0, l = name.length; i < l; i++ ) { | |
delete thisCache[ name[i] ]; | |
} | |
// If there is no data left in the cache, we want to continue | |
// and let the cache object itself get destroyed | |
if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { | |
return; | |
} | |
} | |
} | |
// See jQuery.data for more information | |
if ( !pvt ) { | |
delete cache[ id ].data; | |
// Don't destroy the parent cache unless the internal data object | |
// had been the only thing left in it | |
if ( !isEmptyDataObject( cache[ id ] ) ) { | |
return; | |
} | |
} | |
// Destroy the cache | |
if ( isNode ) { | |
jQuery.cleanData( [ elem ], true ); | |
// Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) | |
} else if ( jQuery.support.deleteExpando || cache != cache.window ) { | |
delete cache[ id ]; | |
// When all else fails, null | |
} else { | |
cache[ id ] = null; | |
} | |
}, | |
// For internal use only. | |
_data: function( elem, name, data ) { | |
return jQuery.data( elem, name, data, true ); | |
}, | |
// A method for determining if a DOM node can handle the data expando | |
acceptData: function( elem ) { | |
var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; | |
// nodes accept data unless otherwise specified; rejection can be conditional | |
return !noData || noData !== true && elem.getAttribute("classid") === noData; | |
} | |
}); | |
jQuery.fn.extend({ | |
data: function( key, value ) { | |
var parts, part, attr, name, l, | |
elem = this[0], | |
i = 0, | |
data = null; | |
// Gets all values | |
if ( key === undefined ) { | |
if ( this.length ) { | |
data = jQuery.data( elem ); | |
if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { | |
attr = elem.attributes; | |
for ( l = attr.length; i < l; i++ ) { | |
name = attr[i].name; | |
if ( name.indexOf( "data-" ) === 0 ) { | |
name = jQuery.camelCase( name.substring(5) ); | |
dataAttr( elem, name, data[ name ] ); | |
} | |
} | |
jQuery._data( elem, "parsedAttrs", true ); | |
} | |
} | |
return data; | |
} | |
// Sets multiple values | |
if ( typeof key === "object" ) { | |
return this.each(function() { | |
jQuery.data( this, key ); | |
}); | |
} | |
parts = key.split( ".", 2 ); | |
parts[1] = parts[1] ? "." + parts[1] : ""; | |
part = parts[1] + "!"; | |
return jQuery.access( this, function( value ) { | |
if ( value === undefined ) { | |
data = this.triggerHandler( "getData" + part, [ parts[0] ] ); | |
// Try to fetch any internally stored data first | |
if ( data === undefined && elem ) { | |
data = jQuery.data( elem, key ); | |
data = dataAttr( elem, key, data ); | |
} | |
return data === undefined && parts[1] ? | |
this.data( parts[0] ) : | |
data; | |
} | |
parts[1] = value; | |
this.each(function() { | |
var self = jQuery( this ); | |
self.triggerHandler( "setData" + part, parts ); | |
jQuery.data( this, key, value ); | |
self.triggerHandler( "changeData" + part, parts ); | |
}); | |
}, null, value, arguments.length > 1, null, false ); | |
}, | |
removeData: function( key ) { | |
return this.each(function() { | |
jQuery.removeData( this, key ); | |
}); | |
} | |
}); | |
function dataAttr( elem, key, data ) { | |
// If nothing was found internally, try to fetch any | |
// data from the HTML5 data-* attribute | |
if ( data === undefined && elem.nodeType === 1 ) { | |
var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); | |
data = elem.getAttribute( name ); | |
if ( typeof data === "string" ) { | |
try { | |
data = data === "true" ? true : | |
data === "false" ? false : | |
data === "null" ? null : | |
// Only convert to a number if it doesn't change the string | |
+data + "" === data ? +data : | |
rbrace.test( data ) ? jQuery.parseJSON( data ) : | |
data; | |
} catch( e ) {} | |
// Make sure we set the data so it isn't changed later | |
jQuery.data( elem, key, data ); | |
} else { | |
data = undefined; | |
} | |
} | |
return data; | |
} | |
// checks a cache object for emptiness | |
function isEmptyDataObject( obj ) { | |
var name; | |
for ( name in obj ) { | |
// if the public data object is empty, the private is still empty | |
if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { | |
continue; | |
} | |
if ( name !== "toJSON" ) { | |
return false; | |
} | |
} | |
return true; | |
} | |
jQuery.extend({ | |
queue: function( elem, type, data ) { | |
var queue; | |
if ( elem ) { | |
type = ( type || "fx" ) + "queue"; | |
queue = jQuery._data( elem, type ); | |
// Speed up dequeue by getting out quickly if this is just a lookup | |
if ( data ) { | |
if ( !queue || jQuery.isArray(data) ) { | |
queue = jQuery._data( elem, type, jQuery.makeArray(data) ); | |
} else { | |
queue.push( data ); | |
} | |
} | |
return queue || []; | |
} | |
}, | |
dequeue: function( elem, type ) { | |
type = type || "fx"; | |
var queue = jQuery.queue( elem, type ), | |
fn = queue.shift(), | |
hooks = jQuery._queueHooks( elem, type ), | |
next = function() { | |
jQuery.dequeue( elem, type ); | |
}; | |
// If the fx queue is dequeued, always remove the progress sentinel | |
if ( fn === "inprogress" ) { | |
fn = queue.shift(); | |
} | |
if ( fn ) { | |
// Add a progress sentinel to prevent the fx queue from being | |
// automatically dequeued | |
if ( type === "fx" ) { | |
queue.unshift( "inprogress" ); | |
} | |
// clear up the last queue stop function | |
delete hooks.stop; | |
fn.call( elem, next, hooks ); | |
} | |
if ( !queue.length && hooks ) { | |
hooks.empty.fire(); | |
} | |
}, | |
// not intended for public consumption - generates a queueHooks object, or returns the current one | |
_queueHooks: function( elem, type ) { | |
var key = type + "queueHooks"; | |
return jQuery._data( elem, key ) || jQuery._data( elem, key, { | |
empty: jQuery.Callbacks("once memory").add(function() { | |
jQuery.removeData( elem, type + "queue", true ); | |
jQuery.removeData( elem, key, true ); | |
}) | |
}); | |
} | |
}); | |
jQuery.fn.extend({ | |
queue: function( type, data ) { | |
var setter = 2; | |
if ( typeof type !== "string" ) { | |
data = type; | |
type = "fx"; | |
setter--; | |
} | |
if ( arguments.length < setter ) { | |
return jQuery.queue( this[0], type ); | |
} | |
return data === undefined ? | |
this : | |
this.each(function() { | |
var queue = jQuery.queue( this, type, data ); | |
// ensure a hooks for this queue | |
jQuery._queueHooks( this, type ); | |
if ( type === "fx" && queue[0] !== "inprogress" ) { | |
jQuery.dequeue( this, type ); | |
} | |
}); | |
}, | |
dequeue: function( type ) { | |
return this.each(function() { | |
jQuery.dequeue( this, type ); | |
}); | |
}, | |
// Based off of the plugin by Clint Helfers, with permission. | |
// http://blindsignals.com/index.php/2009/07/jquery-delay/ | |
delay: function( time, type ) { | |
time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; | |
type = type || "fx"; | |
return this.queue( type, function( next, hooks ) { | |
var timeout = setTimeout( next, time ); | |
hooks.stop = function() { | |
clearTimeout( timeout ); | |
}; | |
}); | |
}, | |
clearQueue: function( type ) { | |
return this.queue( type || "fx", [] ); | |
}, | |
// Get a promise resolved when queues of a certain type | |
// are emptied (fx is the type by default) | |
promise: function( type, obj ) { | |
var tmp, | |
count = 1, | |
defer = jQuery.Deferred(), | |
elements = this, | |
i = this.length, | |
resolve = function() { | |
if ( !( --count ) ) { | |
defer.resolveWith( elements, [ elements ] ); | |
} | |
}; | |
if ( typeof type !== "string" ) { | |
obj = type; | |
type = undefined; | |
} | |
type = type || "fx"; | |
while( i-- ) { | |
if ( (tmp = jQuery._data( elements[ i ], type + "queueHooks" )) && tmp.empty ) { | |
count++; | |
tmp.empty.add( resolve ); | |
} | |
} | |
resolve(); | |
return defer.promise( obj ); | |
} | |
}); | |
var nodeHook, boolHook, fixSpecified, | |
rclass = /[\t\r\n]/g, | |
rreturn = /\r/g, | |
rtype = /^(?:button|input)$/i, | |
rfocusable = /^(?:button|input|object|select|textarea)$/i, | |
rclickable = /^a(?:rea|)$/i, | |
rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, | |
getSetAttribute = jQuery.support.getSetAttribute; | |
jQuery.fn.extend({ | |
attr: function( name, value ) { | |
return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); | |
}, | |
removeAttr: function( name ) { | |
return this.each(function() { | |
jQuery.removeAttr( this, name ); | |
}); | |
}, | |
prop: function( name, value ) { | |
return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); | |
}, | |
removeProp: function( name ) { | |
name = jQuery.propFix[ name ] || name; | |
return this.each(function() { | |
// try/catch handles cases where IE balks (such as removing a property on window) | |
try { | |
this[ name ] = undefined; | |
delete this[ name ]; | |
} catch( e ) {} | |
}); | |
}, | |
addClass: function( value ) { | |
var classNames, i, l, elem, | |
setClass, c, cl; | |
if ( jQuery.isFunction( value ) ) { | |
return this.each(function( j ) { | |
jQuery( this ).addClass( value.call(this, j, this.className) ); | |
}); | |
} | |
if ( value && typeof value === "string" ) { | |
classNames = value.split( core_rspace ); | |
for ( i = 0, l = this.length; i < l; i++ ) { | |
elem = this[ i ]; | |
if ( elem.nodeType === 1 ) { | |
if ( !elem.className && classNames.length === 1 ) { | |
elem.className = value; | |
} else { | |
setClass = " " + elem.className + " "; | |
for ( c = 0, cl = classNames.length; c < cl; c++ ) { | |
if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { | |
setClass += classNames[ c ] + " "; | |
} | |
} | |
elem.className = jQuery.trim( setClass ); | |
} | |
} | |
} | |
} | |
return this; | |
}, | |
removeClass: function( value ) { | |
var removes, className, elem, c, cl, i, l; | |
if ( jQuery.isFunction( value ) ) { | |
return this.each(function( j ) { | |
jQuery( this ).removeClass( value.call(this, j, this.className) ); | |
}); | |
} | |
if ( (value && typeof value === "string") || value === undefined ) { | |
removes = ( value || "" ).split( core_rspace ); | |
for ( i = 0, l = this.length; i < l; i++ ) { | |
elem = this[ i ]; | |
if ( elem.nodeType === 1 && elem.className ) { | |
className = (" " + elem.className + " ").replace( rclass, " " ); | |
// loop over each item in the removal list | |
for ( c = 0, cl = removes.length; c < cl; c++ ) { | |
// Remove until there is nothing to remove, | |
while ( className.indexOf(" " + removes[ c ] + " ") > -1 ) { | |
className = className.replace( " " + removes[ c ] + " " , " " ); | |
} | |
} | |
elem.className = value ? jQuery.trim( className ) : ""; | |
} | |
} | |
} | |
return this; | |
}, | |
toggleClass: function( value, stateVal ) { | |
var type = typeof value, | |
isBool = typeof stateVal === "boolean"; | |
if ( jQuery.isFunction( value ) ) { | |
return this.each(function( i ) { | |
jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); | |
}); | |
} | |
return this.each(function() { | |
if ( type === "string" ) { | |
// toggle individual class names | |
var className, | |
i = 0, | |
self = jQuery( this ), | |
state = stateVal, | |
classNames = value.split( core_rspace ); | |
while ( (className = classNames[ i++ ]) ) { | |
// check each className given, space separated list | |
state = isBool ? state : !self.hasClass( className ); | |
self[ state ? "addClass" : "removeClass" ]( className ); | |
} | |
} else if ( type === "undefined" || type === "boolean" ) { | |
if ( this.className ) { | |
// store className if set | |
jQuery._data( this, "__className__", this.className ); | |
} | |
// toggle whole className | |
this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; | |
} | |
}); | |
}, | |
hasClass: function( selector ) { | |
var className = " " + selector + " ", | |
i = 0, | |
l = this.length; | |
for ( ; i < l; i++ ) { | |
if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { | |
return true; | |
} | |
} | |
return false; | |
}, | |
val: function( value ) { | |
var hooks, ret, isFunction, | |
elem = this[0]; | |
if ( !arguments.length ) { | |
if ( elem ) { | |
hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; | |
if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { | |
return ret; | |
} | |
ret = elem.value; | |
return typeof ret === "string" ? | |
// handle most common string cases | |
ret.replace(rreturn, "") : | |
// handle cases where value is null/undef or number | |
ret == null ? "" : ret; | |
} | |
return; | |
} | |
isFunction = jQuery.isFunction( value ); | |
return this.each(function( i ) { | |
var val, | |
self = jQuery(this); | |
if ( this.nodeType !== 1 ) { | |
return; | |
} | |
if ( isFunction ) { | |
val = value.call( this, i, self.val() ); | |
} else { | |
val = value; | |
} | |
// Treat null/undefined as ""; convert numbers to string | |
if ( val == null ) { | |
val = ""; | |
} else if ( typeof val === "number" ) { | |
val += ""; | |
} else if ( jQuery.isArray( val ) ) { | |
val = jQuery.map(val, function ( value ) { | |
return value == null ? "" : value + ""; | |
}); | |
} | |
hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; | |
// If set returns undefined, fall back to normal setting | |
if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { | |
this.value = val; | |
} | |
}); | |
} | |
}); | |
jQuery.extend({ | |
valHooks: { | |
option: { | |
get: function( elem ) { | |
// attributes.value is undefined in Blackberry 4.7 but | |
// uses .value. See #6932 | |
var val = elem.attributes.value; | |
return !val || val.specified ? elem.value : elem.text; | |
} | |
}, | |
select: { | |
get: function( elem ) { | |
var value, i, max, option, | |
index = elem.selectedIndex, | |
values = [], | |
options = elem.options, | |
one = elem.type === "select-one"; | |
// Nothing was selected | |
if ( index < 0 ) { | |
return null; | |
} | |
// Loop through all the selected options | |
i = one ? index : 0; | |
max = one ? index + 1 : options.length; | |
for ( ; i < max; i++ ) { | |
option = options[ i ]; | |
// Don't return options that are disabled or in a disabled optgroup | |
if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && | |
(!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { | |
// Get the specific value for the option | |
value = jQuery( option ).val(); | |
// We don't need an array for one selects | |
if ( one ) { | |
return value; | |
} | |
// Multi-Selects return an array | |
values.push( value ); | |
} | |
} | |
// Fixes Bug #2551 -- select.val() broken in IE after form.reset() | |
if ( one && !values.length && options.length ) { | |
return jQuery( options[ index ] ).val(); | |
} | |
return values; | |
}, | |
set: function( elem, value ) { | |
var values = jQuery.makeArray( value ); | |
jQuery(elem).find("option").each(function() { | |
this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; | |
}); | |
if ( !values.length ) { | |
elem.selectedIndex = -1; | |
} | |
return values; | |
} | |
} | |
}, | |
// Unused in 1.8, left in so attrFn-stabbers won't die; remove in 1.9 | |
attrFn: {}, | |
attr: function( elem, name, value, pass ) { | |
var ret, hooks, notxml, | |
nType = elem.nodeType; | |
// don't get/set attributes on text, comment and attribute nodes | |
if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { | |
return; | |
} | |
if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) { | |
return jQuery( elem )[ name ]( value ); | |
} | |
// Fallback to prop when attributes are not supported | |
if ( typeof elem.getAttribute === "undefined" ) { | |
return jQuery.prop( elem, name, value ); | |
} | |
notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); | |
// All attributes are lowercase | |
// Grab necessary hook if one is defined | |
if ( notxml ) { | |
name = name.toLowerCase(); | |
hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); | |
} | |
if ( value !== undefined ) { | |
if ( value === null ) { | |
jQuery.removeAttr( elem, name ); | |
return; | |
} else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { | |
return ret; | |
} else { | |
elem.setAttribute( name, "" + value ); | |
return value; | |
} | |
} else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { | |
return ret; | |
} else { | |
ret = elem.getAttribute( name ); | |
// Non-existent attributes return null, we normalize to undefined | |
return ret === null ? | |
undefined : | |
ret; | |
} | |
}, | |
removeAttr: function( elem, value ) { | |
var propName, attrNames, name, isBool, | |
i = 0; | |
if ( value && elem.nodeType === 1 ) { | |
attrNames = value.split( core_rspace ); | |
for ( ; i < attrNames.length; i++ ) { | |
name = attrNames[ i ]; | |
if ( name ) { | |
propName = jQuery.propFix[ name ] || name; | |
isBool = rboolean.test( name ); | |
// See #9699 for explanation of this approach (setting first, then removal) | |
// Do not do this for boolean attributes (see #10870) | |
if ( !isBool ) { | |
jQuery.attr( elem, name, "" ); | |
} | |
elem.removeAttribute( getSetAttribute ? name : propName ); | |
// Set corresponding property to false for boolean attributes | |
if ( isBool && propName in elem ) { | |
elem[ propName ] = false; | |
} | |
} | |
} | |
} | |
}, | |
attrHooks: { | |
type: { | |
set: function( elem, value ) { | |
// We can't allow the type property to be changed (since it causes problems in IE) | |
if ( rtype.test( elem.nodeName ) && elem.parentNode ) { | |
jQuery.error( "type property can't be changed" ); | |
} else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { | |
// Setting the type on a radio button after the value resets the value in IE6-9 | |
// Reset value to it's default in case type is set after value | |
// This is for element creation | |
var val = elem.value; | |
elem.setAttribute( "type", value ); | |
if ( val ) { | |
elem.value = val; | |
} | |
return value; | |
} | |
} | |
}, | |
// Use the value property for back compat | |
// Use the nodeHook for button elements in IE6/7 (#1954) | |
value: { | |
get: function( elem, name ) { | |
if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { | |
return nodeHook.get( elem, name ); | |
} | |
return name in elem ? | |
elem.value : | |
null; | |
}, | |
set: function( elem, value, name ) { | |
if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { | |
return nodeHook.set( elem, value, name ); | |
} | |
// Does not return so that setAttribute is also used | |
elem.value = value; | |
} | |
} | |
}, | |
propFix: { | |
tabindex: "tabIndex", | |
readonly: "readOnly", | |
"for": "htmlFor", | |
"class": "className", | |
maxlength: "maxLength", | |
cellspacing: "cellSpacing", | |
cellpadding: "cellPadding", | |
rowspan: "rowSpan", | |
colspan: "colSpan", | |
usemap: "useMap", | |
frameborder: "frameBorder", | |
contenteditable: "contentEditable" | |
}, | |
prop: function( elem, name, value ) { | |
var ret, hooks, notxml, | |
nType = elem.nodeType; | |
// don't get/set properties on text, comment and attribute nodes | |
if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { | |
return; | |
} | |
notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); | |
if ( notxml ) { | |
// Fix name and attach hooks | |
name = jQuery.propFix[ name ] || name; | |
hooks = jQuery.propHooks[ name ]; | |
} | |
if ( value !== undefined ) { | |
if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { | |
return ret; | |
} else { | |
return ( elem[ name ] = value ); | |
} | |
} else { | |
if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { | |
return ret; | |
} else { | |
return elem[ name ]; | |
} | |
} | |
}, | |
propHooks: { | |
tabIndex: { | |
get: function( elem ) { | |
// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set | |
// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ | |
var attributeNode = elem.getAttributeNode("tabindex"); | |
return attributeNode && attributeNode.specified ? | |
parseInt( attributeNode.value, 10 ) : | |
rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? | |
0 : | |
undefined; | |
} | |
} | |
} | |
}); | |
// Hook for boolean attributes | |
boolHook = { | |
get: function( elem, name ) { | |
// Align boolean attributes with corresponding properties | |
// Fall back to attribute presence where some booleans are not supported | |
var attrNode, | |
property = jQuery.prop( elem, name ); | |
return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? | |
name.toLowerCase() : | |
undefined; | |
}, | |
set: function( elem, value, name ) { | |
var propName; | |
if ( value === false ) { | |
// Remove boolean attributes when set to false | |
jQuery.removeAttr( elem, name ); | |
} else { | |
// value is true since we know at this point it's type boolean and not false | |
// Set boolean attributes to the same name and set the DOM property | |
propName = jQuery.propFix[ name ] || name; | |
if ( propName in elem ) { | |
// Only set the IDL specifically if it already exists on the element | |
elem[ propName ] = true; | |
} | |
elem.setAttribute( name, name.toLowerCase() ); | |
} | |
return name; | |
} | |
}; | |
// IE6/7 do not support getting/setting some attributes with get/setAttribute | |
if ( !getSetAttribute ) { | |
fixSpecified = { | |
name: true, | |
id: true, | |
coords: true | |
}; | |
// Use this for any attribute in IE6/7 | |
// This fixes almost every IE6/7 issue | |
nodeHook = jQuery.valHooks.button = { | |
get: function( elem, name ) { | |
var ret; | |
ret = elem.getAttributeNode( name ); | |
return ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ? | |
ret.value : | |
undefined; | |
}, | |
set: function( elem, value, name ) { | |
// Set the existing or create a new attribute node | |
var ret = elem.getAttributeNode( name ); | |
if ( !ret ) { | |
ret = document.createAttribute( name ); | |
elem.setAttributeNode( ret ); | |
} | |
return ( ret.value = value + "" ); | |
} | |
}; | |
// Set width and height to auto instead of 0 on empty string( Bug #8150 ) | |
// This is for removals | |
jQuery.each([ "width", "height" ], function( i, name ) { | |
jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { | |
set: function( elem, value ) { | |
if ( value === "" ) { | |
elem.setAttribute( name, "auto" ); | |
return value; | |
} | |
} | |
}); | |
}); | |
// Set contenteditable to false on removals(#10429) | |
// Setting to empty string throws an error as an invalid value | |
jQuery.attrHooks.contenteditable = { | |
get: nodeHook.get, | |
set: function( elem, value, name ) { | |
if ( value === "" ) { | |
value = "false"; | |
} | |
nodeHook.set( elem, value, name ); | |
} | |
}; | |
} | |
// Some attributes require a special call on IE | |
if ( !jQuery.support.hrefNormalized ) { | |
jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { | |
jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { | |
get: function( elem ) { | |
var ret = elem.getAttribute( name, 2 ); | |
return ret === null ? undefined : ret; | |
} | |
}); | |
}); | |
} | |
if ( !jQuery.support.style ) { | |
jQuery.attrHooks.style = { | |
get: function( elem ) { | |
// Return undefined in the case of empty string | |
// Normalize to lowercase since IE uppercases css property names | |
return elem.style.cssText.toLowerCase() || undefined; | |
}, | |
set: function( elem, value ) { | |
return ( elem.style.cssText = "" + value ); | |
} | |
}; | |
} | |
// Safari mis-reports the default selected property of an option | |
// Accessing the parent's selectedIndex property fixes it | |
if ( !jQuery.support.optSelected ) { | |
jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { | |
get: function( elem ) { | |
var parent = elem.parentNode; | |
if ( parent ) { | |
parent.selectedIndex; | |
// Make sure that it also works with optgroups, see #5701 | |
if ( parent.parentNode ) { | |
parent.parentNode.selectedIndex; | |
} | |
} | |
return null; | |
} | |
}); | |
} | |
// IE6/7 call enctype encoding | |
if ( !jQuery.support.enctype ) { | |
jQuery.propFix.enctype = "encoding"; | |
} | |
// Radios and checkboxes getter/setter | |
if ( !jQuery.support.checkOn ) { | |
jQuery.each([ "radio", "checkbox" ], function() { | |
jQuery.valHooks[ this ] = { | |
get: function( elem ) { | |
// Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified | |
return elem.getAttribute("value") === null ? "on" : elem.value; | |
} | |
}; | |
}); | |
} | |
jQuery.each([ "radio", "checkbox" ], function() { | |
jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { | |
set: function( elem, value ) { | |
if ( jQuery.isArray( value ) ) { | |
return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); | |
} | |
} | |
}); | |
}); | |
var rformElems = /^(?:textarea|input|select)$/i, | |
rtypenamespace = /^([^\.]*|)(?:\.(.+)|)$/, | |
rhoverHack = /(?:^|\s)hover(\.\S+|)\b/, | |
rkeyEvent = /^key/, | |
rmouseEvent = /^(?:mouse|contextmenu)|click/, | |
rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, | |
hoverHack = function( events ) { | |
return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); | |
}; | |
/* | |
* Helper functions for managing events -- not part of the public interface. | |
* Props to Dean Edwards' addEvent library for many of the ideas. | |
*/ | |
jQuery.event = { | |
add: function( elem, types, handler, data, selector ) { | |
var elemData, eventHandle, events, | |
t, tns, type, namespaces, handleObj, | |
handleObjIn, handlers, special; | |
// Don't attach events to noData or text/comment nodes (allow plain objects tho) | |
if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { | |
return; | |
} | |
// Caller can pass in an object of custom data in lieu of the handler | |
if ( handler.handler ) { | |
handleObjIn = handler; | |
handler = handleObjIn.handler; | |
selector = handleObjIn.selector; | |
} | |
// Make sure that the handler has a unique ID, used to find/remove it later | |
if ( !handler.guid ) { | |
handler.guid = jQuery.guid++; | |
} | |
// Init the element's event structure and main handler, if this is the first | |
events = elemData.events; | |
if ( !events ) { | |
elemData.events = events = {}; | |
} | |
eventHandle = elemData.handle; | |
if ( !eventHandle ) { | |
elemData.handle = eventHandle = function( e ) { | |
// Discard the second event of a jQuery.event.trigger() and | |
// when an event is called after a page has unloaded | |
return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? | |
jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : | |
undefined; | |
}; | |
// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events | |
eventHandle.elem = elem; | |
} | |
// Handle multiple events separated by a space | |
// jQuery(...).bind("mouseover mouseout", fn); | |
types = jQuery.trim( hoverHack(types) ).split( " " ); | |
for ( t = 0; t < types.length; t++ ) { | |
tns = rtypenamespace.exec( types[t] ) || []; | |
type = tns[1]; | |
namespaces = ( tns[2] || "" ).split( "." ).sort(); | |
// If event changes its type, use the special event handlers for the changed type | |
special = jQuery.event.special[ type ] || {}; | |
// If selector defined, determine special event api type, otherwise given type | |
type = ( selector ? special.delegateType : special.bindType ) || type; | |
// Update special based on newly reset type | |
special = jQuery.event.special[ type ] || {}; | |
// handleObj is passed to all event handlers | |
handleObj = jQuery.extend({ | |
type: type, | |
origType: tns[1], | |
data: data, | |
handler: handler, | |
guid: handler.guid, | |
selector: selector, | |
namespace: namespaces.join(".") | |
}, handleObjIn ); | |
// Init the event handler queue if we're the first | |
handlers = events[ type ]; | |
if ( !handlers ) { | |
handlers = events[ type ] = []; | |
handlers.delegateCount = 0; | |
// Only use addEventListener/attachEvent if the special events handler returns false | |
if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { | |
// Bind the global event handler to the element | |
if ( elem.addEventListener ) { | |
elem.addEventListener( type, eventHandle, false ); | |
} else if ( elem.attachEvent ) { | |
elem.attachEvent( "on" + type, eventHandle ); | |
} | |
} | |
} | |
if ( special.add ) { | |
special.add.call( elem, handleObj ); | |
if ( !handleObj.handler.guid ) { | |
handleObj.handler.guid = handler.guid; | |
} | |
} | |
// Add to the element's handler list, delegates in front | |
if ( selector ) { | |
handlers.splice( handlers.delegateCount++, 0, handleObj ); | |
} else { | |
handlers.push( handleObj ); | |
} | |
// Keep track of which events have ever been used, for event optimization | |
jQuery.event.global[ type ] = true; | |
} | |
// Nullify elem to prevent memory leaks in IE | |
elem = null; | |
}, | |
global: {}, | |
// Detach an event or set of events from an element | |
remove: function( elem, types, handler, selector, mappedTypes ) { | |
var t, tns, type, origType, namespaces, origCount, | |
j, events, special, eventType, handleObj, | |
elemData = jQuery.hasData( elem ) && jQuery._data( elem ); | |
if ( !elemData || !(events = elemData.events) ) { | |
return; | |
} | |
// Once for each type.namespace in types; type may be omitted | |
types = jQuery.trim( hoverHack( types || "" ) ).split(" "); | |
for ( t = 0; t < types.length; t++ ) { | |
tns = rtypenamespace.exec( types[t] ) || []; | |
type = origType = tns[1]; | |
namespaces = tns[2]; | |
// Unbind all events (on this namespace, if provided) for the element | |
if ( !type ) { | |
for ( type in events ) { | |
jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); | |
} | |
continue; | |
} | |
special = jQuery.event.special[ type ] || {}; | |
type = ( selector? special.delegateType : special.bindType ) || type; | |
eventType = events[ type ] || []; | |
origCount = eventType.length; | |
namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.|)") + "(\\.|$)") : null; | |
// Remove matching events | |
for ( j = 0; j < eventType.length; j++ ) { | |
handleObj = eventType[ j ]; | |
if ( ( mappedTypes || origType === handleObj.origType ) && | |
( !handler || handler.guid === handleObj.guid ) && | |
( !namespaces || namespaces.test( handleObj.namespace ) ) && | |
( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { | |
eventType.splice( j--, 1 ); | |
if ( handleObj.selector ) { | |
eventType.delegateCount--; | |
} | |
if ( special.remove ) { | |
special.remove.call( elem, handleObj ); | |
} | |
} | |
} | |
// Remove generic event handler if we removed something and no more handlers exist | |
// (avoids potential for endless recursion during removal of special event handlers) | |
if ( eventType.length === 0 && origCount !== eventType.length ) { | |
if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { | |
jQuery.removeEvent( elem, type, elemData.handle ); | |
} | |
delete events[ type ]; | |
} | |
} | |
// Remove the expando if it's no longer used | |
if ( jQuery.isEmptyObject( events ) ) { | |
delete elemData.handle; | |
// removeData also checks for emptiness and clears the expando if empty | |
// so use it instead of delete | |
jQuery.removeData( elem, "events", true ); | |
} | |
}, | |
// Events that are safe to short-circuit if no handlers are attached. | |
// Native DOM events should not be added, they may have inline handlers. | |
customEvent: { | |
"getData": true, | |
"setData": true, | |
"changeData": true | |
}, | |
trigger: function( event, data, elem, onlyHandlers ) { | |
// Don't do events on text and comment nodes | |
if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { | |
return; | |
} | |
// Event object or event type | |
var cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType, | |
type = event.type || event, | |
namespaces = []; | |
// focus/blur morphs to focusin/out; ensure we're not firing them right now | |
if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { | |
return; | |
} | |
if ( type.indexOf( "!" ) >= 0 ) { | |
// Exclusive events trigger only for the exact event (no namespaces) | |
type = type.slice(0, -1); | |
exclusive = true; | |
} | |
if ( type.indexOf( "." ) >= 0 ) { | |
// Namespaced trigger; create a regexp to match event type in handle() | |
namespaces = type.split("."); | |
type = namespaces.shift(); | |
namespaces.sort(); | |
} | |
if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { | |
// No jQuery handlers for this event type, and it can't have inline handlers | |
return; | |
} | |
// Caller can pass in an Event, Object, or just an event type string | |
event = typeof event === "object" ? | |
// jQuery.Event object | |
event[ jQuery.expando ] ? event : | |
// Object literal | |
new jQuery.Event( type, event ) : | |
// Just the event type (string) | |
new jQuery.Event( type ); | |
event.type = type; | |
event.isTrigger = true; | |
event.exclusive = exclusive; | |
event.namespace = namespaces.join( "." ); | |
event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null; | |
ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; | |
// Handle a global trigger | |
if ( !elem ) { | |
// TODO: Stop taunting the data cache; remove global events and always attach to document | |
cache = jQuery.cache; | |
for ( i in cache ) { | |
if ( cache[ i ].events && cache[ i ].events[ type ] ) { | |
jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); | |
} | |
} | |
return; | |
} | |
// Clean up the event in case it is being reused | |
event.result = undefined; | |
if ( !event.target ) { | |
event.target = elem; | |
} | |
// Clone any incoming data and prepend the event, creating the handler arg list | |
data = data != null ? jQuery.makeArray( data ) : []; | |
data.unshift( event ); | |
// Allow special events to draw outside the lines | |
special = jQuery.event.special[ type ] || {}; | |
if ( special.trigger && special.trigger.apply( elem, data ) === false ) { | |
return; | |
} | |
// Determine event propagation path in advance, per W3C events spec (#9951) | |
// Bubble up to document, then to window; watch for a global ownerDocument var (#9724) | |
eventPath = [[ elem, special.bindType || type ]]; | |
if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { | |
bubbleType = special.delegateType || type; | |
cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; | |
for ( old = elem; cur; cur = cur.parentNode ) { | |
eventPath.push([ cur, bubbleType ]); | |
old = cur; | |
} | |
// Only add window if we got to document (e.g., not plain obj or detached DOM) | |
if ( old === (elem.ownerDocument || document) ) { | |
eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); | |
} | |
} | |
// Fire handlers on the event path | |
for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { | |
cur = eventPath[i][0]; | |
event.type = eventPath[i][1]; | |
handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); | |
if ( handle ) { | |
handle.apply( cur, data ); | |
} | |
// Note that this is a bare JS function and not a jQuery handler | |
handle = ontype && cur[ ontype ]; | |
if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { | |
event.preventDefault(); | |
} | |
} | |
event.type = type; | |
// If nobody prevented the default action, do it now | |
if ( !onlyHandlers && !event.isDefaultPrevented() ) { | |
if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && | |
!(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { | |
// Call a native DOM method on the target with the same name name as the event. | |
// Can't use an .isFunction() check here because IE6/7 fails that test. | |
// Don't do default actions on window, that's where global variables be (#6170) | |
// IE<9 dies on focus/blur to hidden element (#1486) | |
if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { | |
// Don't re-trigger an onFOO event when we call its FOO() method | |
old = elem[ ontype ]; | |
if ( old ) { | |
elem[ ontype ] = null; | |
} | |
// Prevent re-triggering of the same event, since we already bubbled it above | |
jQuery.event.triggered = type; | |
elem[ type ](); | |
jQuery.event.triggered = undefined; | |
if ( old ) { | |
elem[ ontype ] = old; | |
} | |
} | |
} | |
} | |
return event.result; | |
}, | |
dispatch: function( event ) { | |
// Make a writable jQuery.Event from the native event object | |
event = jQuery.event.fix( event || window.event ); | |
var i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related, | |
handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), | |
delegateCount = handlers.delegateCount, | |
args = [].slice.call( arguments ), | |
run_all = !event.exclusive && !event.namespace, | |
special = jQuery.event.special[ event.type ] || {}, | |
handlerQueue = []; | |
// Use the fix-ed jQuery.Event rather than the (read-only) native event | |
args[0] = event; | |
event.delegateTarget = this; | |
// Call the preDispatch hook for the mapped type, and let it bail if desired | |
if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { | |
return; | |
} | |
// Determine handlers that should run if there are delegated events | |
// Avoid non-left-click bubbling in Firefox (#3861) | |
if ( delegateCount && !(event.button && event.type === "click") ) { | |
// Pregenerate a single jQuery object for reuse with .is() | |
jqcur = jQuery(this); | |
jqcur.context = this; | |
for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { | |
// Don't process clicks (ONLY) on disabled elements (#6911, #8165, #xxxx) | |
if ( cur.disabled !== true || event.type !== "click" ) { | |
selMatch = {}; | |
matches = []; | |
jqcur[0] = cur; | |
for ( i = 0; i < delegateCount; i++ ) { | |
handleObj = handlers[ i ]; | |
sel = handleObj.selector; | |
if ( selMatch[ sel ] === undefined ) { | |
selMatch[ sel ] = jqcur.is( sel ); | |
} | |
if ( selMatch[ sel ] ) { | |
matches.push( handleObj ); | |
} | |
} | |
if ( matches.length ) { | |
handlerQueue.push({ elem: cur, matches: matches }); | |
} | |
} | |
} | |
} | |
// Add the remaining (directly-bound) handlers | |
if ( handlers.length > delegateCount ) { | |
handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); | |
} | |
// Run delegates first; they may want to stop propagation beneath us | |
for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { | |
matched = handlerQueue[ i ]; | |
event.currentTarget = matched.elem; | |
for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { | |
handleObj = matched.matches[ j ]; | |
// Triggered event must either 1) be non-exclusive and have no namespace, or | |
// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). | |
if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { | |
event.data = handleObj.data; | |
event.handleObj = handleObj; | |
ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) | |
.apply( matched.elem, args ); | |
if ( ret !== undefined ) { | |
event.result = ret; | |
if ( ret === false ) { | |
event.preventDefault(); | |
event.stopPropagation(); | |
} | |
} | |
} | |
} | |
} | |
// Call the postDispatch hook for the mapped type | |
if ( special.postDispatch ) { | |
special.postDispatch.call( this, event ); | |
} | |
return event.result; | |
}, | |
// Includes some event props shared by KeyEvent and MouseEvent | |
// *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** | |
props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), | |
fixHooks: {}, | |
keyHooks: { | |
props: "char charCode key keyCode".split(" "), | |
filter: function( event, original ) { | |
// Add which for key events | |
if ( event.which == null ) { | |
event.which = original.charCode != null ? original.charCode : original.keyCode; | |
} | |
return event; | |
} | |
}, | |
mouseHooks: { | |
props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), | |
filter: function( event, original ) { | |
var eventDoc, doc, body, | |
button = original.button, | |
fromElement = original.fromElement; | |
// Calculate pageX/Y if missing and clientX/Y available | |
if ( event.pageX == null && original.clientX != null ) { | |
eventDoc = event.target.ownerDocument || document; | |
doc = eventDoc.documentElement; | |
body = eventDoc.body; | |
event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); | |
event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); | |
} | |
// Add relatedTarget, if necessary | |
if ( !event.relatedTarget && fromElement ) { | |
event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; | |
} | |
// Add which for click: 1 === left; 2 === middle; 3 === right | |
// Note: button is not normalized, so don't use it | |
if ( !event.which && button !== undefined ) { | |
event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); | |
} | |
return event; | |
} | |
}, | |
fix: function( event ) { | |
if ( event[ jQuery.expando ] ) { | |
return event; | |
} | |
// Create a writable copy of the event object and normalize some properties | |
var i, prop, | |
originalEvent = event, | |
fixHook = jQuery.event.fixHooks[ event.type ] || {}, | |
copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; | |
event = jQuery.Event( originalEvent ); | |
for ( i = copy.length; i; ) { | |
prop = copy[ --i ]; | |
event[ prop ] = originalEvent[ prop ]; | |
} | |
// Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) | |
if ( !event.target ) { | |
event.target = originalEvent.srcElement || document; | |
} | |
// Target should not be a text node (#504, Safari) | |
if ( event.target.nodeType === 3 ) { | |
event.target = event.target.parentNode; | |
} | |
// For mouse/key events, metaKey==false if it's undefined (#3368, #11328; IE6/7/8) | |
event.metaKey = !!event.metaKey; | |
return fixHook.filter? fixHook.filter( event, originalEvent ) : event; | |
}, | |
special: { | |
ready: { | |
// Make sure the ready event is setup | |
setup: jQuery.bindReady | |
}, | |
load: { | |
// Prevent triggered image.load events from bubbling to window.load | |
noBubble: true | |
}, | |
focus: { | |
delegateType: "focusin" | |
}, | |
blur: { | |
delegateType: "focusout" | |
}, | |
beforeunload: { | |
setup: function( data, namespaces, eventHandle ) { | |
// We only want to do this special case on windows | |
if ( jQuery.isWindow( this ) ) { | |
this.onbeforeunload = eventHandle; | |
} | |
}, | |
teardown: function( namespaces, eventHandle ) { | |
if ( this.onbeforeunload === eventHandle ) { | |
this.onbeforeunload = null; | |
} | |
} | |
} | |
}, | |
simulate: function( type, elem, event, bubble ) { | |
// Piggyback on a donor event to simulate a different one. | |
// Fake originalEvent to avoid donor's stopPropagation, but if the | |
// simulated event prevents default then we do the same on the donor. | |
var e = jQuery.extend( | |
new jQuery.Event(), | |
event, | |
{ type: type, | |
isSimulated: true, | |
originalEvent: {} | |
} | |
); | |
if ( bubble ) { | |
jQuery.event.trigger( e, null, elem ); | |
} else { | |
jQuery.event.dispatch.call( elem, e ); | |
} | |
if ( e.isDefaultPrevented() ) { | |
event.preventDefault(); | |
} | |
} | |
}; | |
// Some plugins are using, but it's undocumented/deprecated and will be removed. | |
// The 1.7 special event interface should provide all the hooks needed now. | |
jQuery.event.handle = jQuery.event.dispatch; | |
jQuery.removeEvent = document.removeEventListener ? | |
function( elem, type, handle ) { | |
if ( elem.removeEventListener ) { | |
elem.removeEventListener( type, handle, false ); | |
} | |
} : | |
function( elem, type, handle ) { | |
var name = "on" + type; | |
if ( elem.detachEvent ) { | |
// #8545, #7054, preventing memory leaks for custom events in IE6-8 – | |
// detachEvent needed property on element, by name of that event, to properly expose it to GC | |
if ( typeof elem[ name ] === "undefined" ) { | |
elem[ name ] = null; | |
} | |
elem.detachEvent( name, handle ); | |
} | |
}; | |
jQuery.Event = function( src, props ) { | |
// Allow instantiation without the 'new' keyword | |
if ( !(this instanceof jQuery.Event) ) { | |
return new jQuery.Event( src, props ); | |
} | |
// Event object | |
if ( src && src.type ) { | |
this.originalEvent = src; | |
this.type = src.type; | |
// Events bubbling up the document may have been marked as prevented | |
// by a handler lower down the tree; reflect the correct value. | |
this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || | |
src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; | |
// Event type | |
} else { | |
this.type = src; | |
} | |
// Put explicitly provided properties onto the event object | |
if ( props ) { | |
jQuery.extend( this, props ); | |
} | |
// Create a timestamp if incoming event doesn't have one | |
this.timeStamp = src && src.timeStamp || jQuery.now(); | |
// Mark it as fixed | |
this[ jQuery.expando ] = true; | |
}; | |
function returnFalse() { | |
return false; | |
} | |
function returnTrue() { | |
return true; | |
} | |
// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding | |
// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html | |
jQuery.Event.prototype = { | |
preventDefault: function() { | |
this.isDefaultPrevented = returnTrue; | |
var e = this.originalEvent; | |
if ( !e ) { | |
return; | |
} | |
// if preventDefault exists run it on the original event | |
if ( e.preventDefault ) { | |
e.preventDefault(); | |
// otherwise set the returnValue property of the original event to false (IE) | |
} else { | |
e.returnValue = false; | |
} | |
}, | |
stopPropagation: function() { | |
this.isPropagationStopped = returnTrue; | |
var e = this.originalEvent; | |
if ( !e ) { | |
return; | |
} | |
// if stopPropagation exists run it on the original event | |
if ( e.stopPropagation ) { | |
e.stopPropagation(); | |
} | |
// otherwise set the cancelBubble property of the original event to true (IE) | |
e.cancelBubble = true; | |
}, | |
stopImmediatePropagation: function() { | |
this.isImmediatePropagationStopped = returnTrue; | |
this.stopPropagation(); | |
}, | |
isDefaultPrevented: returnFalse, | |
isPropagationStopped: returnFalse, | |
isImmediatePropagationStopped: returnFalse | |
}; | |
// Create mouseenter/leave events using mouseover/out and event-time checks | |
jQuery.each({ | |
mouseenter: "mouseover", | |
mouseleave: "mouseout" | |
}, function( orig, fix ) { | |
jQuery.event.special[ orig ] = { | |
delegateType: fix, | |
bindType: fix, | |
handle: function( event ) { | |
var ret, | |
target = this, | |
related = event.relatedTarget, | |
handleObj = event.handleObj, | |
selector = handleObj.selector; | |
// For mousenter/leave call the handler if related is outside the target. | |
// NB: No relatedTarget if the mouse left/entered the browser window | |
if ( !related || (related !== target && !jQuery.contains( target, related )) ) { | |
event.type = handleObj.origType; | |
ret = handleObj.handler.apply( this, arguments ); | |
event.type = fix; | |
} | |
return ret; | |
} | |
}; | |
}); | |
// IE submit delegation | |
if ( !jQuery.support.submitBubbles ) { | |
jQuery.event.special.submit = { | |
setup: function() { | |
// Only need this for delegated form submit events | |
if ( jQuery.nodeName( this, "form" ) ) { | |
return false; | |
} | |
// Lazy-add a submit handler when a descendant form may potentially be submitted | |
jQuery.event.add( this, "click._submit keypress._submit", function( e ) { | |
// Node name check avoids a VML-related crash in IE (#9807) | |
var elem = e.target, | |
form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; | |
if ( form && !jQuery._data( form, "_submit_attached" ) ) { | |
jQuery.event.add( form, "submit._submit", function( event ) { | |
event._submit_bubble = true; | |
}); | |
jQuery._data( form, "_submit_attached", true ); | |
} | |
}); | |
// return undefined since we don't need an event listener | |
}, | |
postDispatch: function( event ) { | |
// If form was submitted by the user, bubble the event up the tree | |
if ( event._submit_bubble ) { | |
delete event._submit_bubble; | |
if ( this.parentNode && !event.isTrigger ) { | |
jQuery.event.simulate( "submit", this.parentNode, event, true ); | |
} | |
} | |
}, | |
teardown: function() { | |
// Only need this for delegated form submit events | |
if ( jQuery.nodeName( this, "form" ) ) { | |
return false; | |
} | |
// Remove delegated handlers; cleanData eventually reaps submit handlers attached above | |
jQuery.event.remove( this, "._submit" ); | |
} | |
}; | |
} | |
// IE change delegation and checkbox/radio fix | |
if ( !jQuery.support.changeBubbles ) { | |
jQuery.event.special.change = { | |
setup: function() { | |
if ( rformElems.test( this.nodeName ) ) { | |
// IE doesn't fire change on a check/radio until blur; trigger it on click | |
// after a propertychange. Eat the blur-change in special.change.handle. | |
// This still fires onchange a second time for check/radio after blur. | |
if ( this.type === "checkbox" || this.type === "radio" ) { | |
jQuery.event.add( this, "propertychange._change", function( event ) { | |
if ( event.originalEvent.propertyName === "checked" ) { | |
this._just_changed = true; | |
} | |
}); | |
jQuery.event.add( this, "click._change", function( event ) { | |
if ( this._just_changed && !event.isTrigger ) { | |
this._just_changed = false; | |
} | |
// Allow triggered, simulated change events (#11500) | |
jQuery.event.simulate( "change", this, event, true ); | |
}); | |
} | |
return false; | |
} | |
// Delegated event; lazy-add a change handler on descendant inputs | |
jQuery.event.add( this, "beforeactivate._change", function( e ) { | |
var elem = e.target; | |
if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "_change_attached" ) ) { | |
jQuery.event.add( elem, "change._change", function( event ) { | |
if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { | |
jQuery.event.simulate( "change", this.parentNode, event, true ); | |
} | |
}); | |
jQuery._data( elem, "_change_attached", true ); | |
} | |
}); | |
}, | |
handle: function( event ) { | |
var elem = event.target; | |
// Swallow native change events from checkbox/radio, we already triggered them above | |
if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { | |
return event.handleObj.handler.apply( this, arguments ); | |
} | |
}, | |
teardown: function() { | |
jQuery.event.remove( this, "._change" ); | |
return rformElems.test( this.nodeName ); | |
} | |
}; | |
} | |
// Create "bubbling" focus and blur events | |
if ( !jQuery.support.focusinBubbles ) { | |
jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { | |
// Attach a single capturing handler while someone wants focusin/focusout | |
var attaches = 0, | |
handler = function( event ) { | |
jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); | |
}; | |
jQuery.event.special[ fix ] = { | |
setup: function() { | |
if ( attaches++ === 0 ) { | |
document.addEventListener( orig, handler, true ); | |
} | |
}, | |
teardown: function() { | |
if ( --attaches === 0 ) { | |
document.removeEventListener( orig, handler, true ); | |
} | |
} | |
}; | |
}); | |
} | |
jQuery.fn.extend({ | |
on: function( types, selector, data, fn, /*INTERNAL*/ one ) { | |
var origFn, type; | |
// Types can be a map of types/handlers | |
if ( typeof types === "object" ) { | |
// ( types-Object, selector, data ) | |
if ( typeof selector !== "string" ) { // && selector != null | |
// ( types-Object, data ) | |
data = data || selector; | |
selector = undefined; | |
} | |
for ( type in types ) { | |
this.on( type, selector, data, types[ type ], one ); | |
} | |
return this; | |
} | |
if ( data == null && fn == null ) { | |
// ( types, fn ) | |
fn = selector; | |
data = selector = undefined; | |
} else if ( fn == null ) { | |
if ( typeof selector === "string" ) { | |
// ( types, selector, fn ) | |
fn = data; | |
data = undefined; | |
} else { | |
// ( types, data, fn ) | |
fn = data; | |
data = selector; | |
selector = undefined; | |
} | |
} | |
if ( fn === false ) { | |
fn = returnFalse; | |
} else if ( !fn ) { | |
return this; | |
} | |
if ( one === 1 ) { | |
origFn = fn; | |
fn = function( event ) { | |
// Can use an empty set, since event contains the info | |
jQuery().off( event ); | |
return origFn.apply( this, arguments ); | |
}; | |
// Use same guid so caller can remove using origFn | |
fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); | |
} | |
return this.each( function() { | |
jQuery.event.add( this, types, fn, data, selector ); | |
}); | |
}, | |
one: function( types, selector, data, fn ) { | |
return this.on( types, selector, data, fn, 1 ); | |
}, | |
off: function( types, selector, fn ) { | |
var handleObj, type; | |
if ( types && types.preventDefault && types.handleObj ) { | |
// ( event ) dispatched jQuery.Event | |
handleObj = types.handleObj; | |
jQuery( types.delegateTarget ).off( | |
handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, | |
handleObj.selector, | |
handleObj.handler | |
); | |
return this; | |
} | |
if ( typeof types === "object" ) { | |
// ( types-object [, selector] ) | |
for ( type in types ) { | |
this.off( type, selector, types[ type ] ); | |
} | |
return this; | |
} | |
if ( selector === false || typeof selector === "function" ) { | |
// ( types [, fn] ) | |
fn = selector; | |
selector = undefined; | |
} | |
if ( fn === false ) { | |
fn = returnFalse; | |
} | |
return this.each(function() { | |
jQuery.event.remove( this, types, fn, selector ); | |
}); | |
}, | |
bind: function( types, data, fn ) { | |
return this.on( types, null, data, fn ); | |
}, | |
unbind: function( types, fn ) { | |
return this.off( types, null, fn ); | |
}, | |
live: function( types, data, fn ) { | |
jQuery( this.context ).on( types, this.selector, data, fn ); | |
return this; | |
}, | |
die: function( types, fn ) { | |
jQuery( this.context ).off( types, this.selector || "**", fn ); | |
return this; | |
}, | |
delegate: function( selector, types, data, fn ) { | |
return this.on( types, selector, data, fn ); | |
}, | |
undelegate: function( selector, types, fn ) { | |
// ( namespace ) or ( selector, types [, fn] ) | |
return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); | |
}, | |
trigger: function( type, data ) { | |
return this.each(function() { | |
jQuery.event.trigger( type, data, this ); | |
}); | |
}, | |
triggerHandler: function( type, data ) { | |
if ( this[0] ) { | |
return jQuery.event.trigger( type, data, this[0], true ); | |
} | |
}, | |
toggle: function( fn ) { | |
// Save reference to arguments for access in closure | |
var args = arguments, | |
guid = fn.guid || jQuery.guid++, | |
i = 0, | |
toggler = function( event ) { | |
// Figure out which function to execute | |
var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; | |
jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); | |
// Make sure that clicks stop | |
event.preventDefault(); | |
// and execute the function | |
return args[ lastToggle ].apply( this, arguments ) || false; | |
}; | |
// link all the functions, so any of them can unbind this click handler | |
toggler.guid = guid; | |
while ( i < args.length ) { | |
args[ i++ ].guid = guid; | |
} | |
return this.click( toggler ); | |
}, | |
hover: function( fnOver, fnOut ) { | |
return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); | |
} | |
}); | |
jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + | |
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + | |
"change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { | |
// Handle event binding | |
jQuery.fn[ name ] = function( data, fn ) { | |
if ( fn == null ) { | |
fn = data; | |
data = null; | |
} | |
return arguments.length > 0 ? | |
this.on( name, null, data, fn ) : | |
this.trigger( name ); | |
}; | |
if ( rkeyEvent.test( name ) ) { | |
jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; | |
} | |
if ( rmouseEvent.test( name ) ) { | |
jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; | |
} | |
}); | |
/*! | |
* Sizzle CSS Selector Engine | |
* Copyright 2012 jQuery Foundation and other contributors | |
* Released under the MIT license | |
* http://sizzlejs.com/ | |
*/ | |
(function( window, undefined ) { | |
var cachedruns, | |
dirruns, | |
sortOrder, | |
siblingCheck, | |
assertGetIdNotName, | |
document = window.document, | |
docElem = document.documentElement, | |
strundefined = "undefined", | |
hasDuplicate = false, | |
baseHasDuplicate = true, | |
done = 0, | |
slice = [].slice, | |
push = [].push, | |
expando = ( "sizcache" + Math.random() ).replace( ".", "" ), | |
// Regex | |
// Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace | |
whitespace = "[\\x20\\t\\r\\n\\f]", | |
// http://www.w3.org/TR/css3-syntax/#characters | |
characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+", | |
// Loosely modeled on CSS identifier characters | |
// An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors) | |
// Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier | |
identifier = characterEncoding.replace( "w", "w#" ), | |
// Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors | |
operators = "([*^$|!~]?=)", | |
attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + | |
"*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", | |
pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|((?:[^,]|\\\\,|(?:,(?=[^\\[]*\\]))|(?:,(?=[^\\(]*\\))))*))\\)|)", | |
pos = ":(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\)|)(?=[^-]|$)", | |
combinators = whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*", | |
groups = "(?=[^\\x20\\t\\r\\n\\f])(?:\\\\.|" + attributes + "|" + pseudos.replace( 2, 7 ) + "|[^\\\\(),])+", | |
// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter | |
rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), | |
rcombinators = new RegExp( "^" + combinators ), | |
// All simple (non-comma) selectors, excluding insignifant trailing whitespace | |
rgroups = new RegExp( groups + "?(?=" + whitespace + "*,|$)", "g" ), | |
// A selector, or everything after leading whitespace | |
// Optionally followed in either case by a ")" for terminating sub-selectors | |
rselector = new RegExp( "^(?:(?!,)(?:(?:^|,)" + whitespace + "*" + groups + ")*?|" + whitespace + "*(.*?))(\\)|$)" ), | |
// All combinators and selector components (attribute test, tag, pseudo, etc.), the latter appearing together when consecutive | |
rtokens = new RegExp( groups.slice( 19, -6 ) + "\\x20\\t\\r\\n\\f>+~])+|" + combinators, "g" ), | |
// Easily-parseable/retrievable ID or TAG or CLASS selectors | |
rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/, | |
rsibling = /[\x20\t\r\n\f]*[+~]/, | |
rendsWithNot = /:not\($/, | |
rheader = /h\d/i, | |
rinputs = /input|select|textarea|button/i, | |
rbackslash = /\\(?!\\)/g, | |
matchExpr = { | |
"ID": new RegExp( "^#(" + characterEncoding + ")" ), | |
"CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), | |
"NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), | |
"TAG": new RegExp( "^(" + characterEncoding.replace( "[-", "[-\\*" ) + ")" ), | |
"ATTR": new RegExp( "^" + attributes ), | |
"PSEUDO": new RegExp( "^" + pseudos ), | |
"CHILD": new RegExp( "^:(only|nth|last|first)-child(?:\\(" + whitespace + | |
"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + | |
"*(\\d+)|))" + whitespace + "*\\)|)", "i" ), | |
"POS": new RegExp( pos, "ig" ), | |
// For use in libraries implementing .is() | |
"needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" ) | |
}, | |
classCache = {}, | |
cachedClasses = [], | |
compilerCache = {}, | |
cachedSelectors = [], | |
// Mark a function for use in filtering | |
markFunction = function( fn ) { | |
fn.sizzleFilter = true; | |
return fn; | |
}, | |
// Returns a function to use in pseudos for input types | |
createInputFunction = function( type ) { | |
return function( elem ) { | |
// Check the input's nodeName and type | |
return elem.nodeName.toLowerCase() === "input" && elem.type === type; | |
}; | |
}, | |
// Returns a function to use in pseudos for buttons | |
createButtonFunction = function( type ) { | |
return function( elem ) { | |
var name = elem.nodeName.toLowerCase(); | |
return (name === "input" || name === "button") && elem.type === type; | |
}; | |
}, | |
// Used for testing something on an element | |
assert = function( fn ) { | |
var pass = false, | |
div = document.createElement("div"); | |
try { | |
pass = fn( div ); | |
} catch (e) {} | |
// release memory in IE | |
div = null; | |
return pass; | |
}, | |
// Check if attributes should be retrieved by attribute nodes | |
assertAttributes = assert(function( div ) { | |
div.innerHTML = "<select></select>"; | |
var type = typeof div.lastChild.getAttribute("multiple"); | |
// IE8 returns a string for some attributes even when not present | |
return type !== "boolean" && type !== "string"; | |
}), | |
// Check if getElementById returns elements by name | |
// Check if getElementsByName privileges form controls or returns elements by ID | |
assertUsableName = assert(function( div ) { | |
// Inject content | |
div.id = expando + 0; | |
div.innerHTML = "<a name='" + expando + "'></a><div name='" + expando + "'></div>"; | |
docElem.insertBefore( div, docElem.firstChild ); | |
// Test | |
var pass = document.getElementsByName && | |
// buggy browsers will return fewer than the correct 2 | |
document.getElementsByName( expando ).length === | |
// buggy browsers will return more than the correct 0 | |
2 + document.getElementsByName( expando + 0 ).length; | |
assertGetIdNotName = !document.getElementById( expando ); | |
// Cleanup | |
docElem.removeChild( div ); | |
return pass; | |
}), | |
// Check if the browser returns only elements | |
// when doing getElementsByTagName("*") | |
assertTagNameNoComments = assert(function( div ) { | |
div.appendChild( document.createComment("") ); | |
return div.getElementsByTagName("*").length === 0; | |
}), | |
// Check if getAttribute returns normalized href attributes | |
assertHrefNotNormalized = assert(function( div ) { | |
div.innerHTML = "<a href='#'></a>"; | |
return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && | |
div.firstChild.getAttribute("href") === "#"; | |
}), | |
// Check if getElementsByClassName can be trusted | |
assertUsableClassName = assert(function( div ) { | |
// Opera can't find a second classname (in 9.6) | |
div.innerHTML = "<div class='hidden e'></div><div class='hidden'></div>"; | |
if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { | |
return false; | |
} | |
// Safari caches class attributes, doesn't catch changes (in 3.2) | |
div.lastChild.className = "e"; | |
return div.getElementsByClassName("e").length !== 1; | |
}); | |
var Sizzle = function( selector, context, results, seed ) { | |
results = results || []; | |
context = context || document; | |
var match, elem, xml, m, | |
nodeType = context.nodeType; | |
if ( nodeType !== 1 && nodeType !== 9 ) { | |
return []; | |
} | |
if ( !selector || typeof selector !== "string" ) { | |
return results; | |
} | |
xml = isXML( context ); | |
if ( !xml && !seed ) { | |
if ( (match = rquickExpr.exec( selector )) ) { | |
// Speed-up: Sizzle("#ID") | |
if ( (m = match[1]) ) { | |
if ( nodeType === 9 ) { | |
elem = context.getElementById( m ); | |
// Check parentNode to catch when Blackberry 4.6 returns | |
// nodes that are no longer in the document #6963 | |
if ( elem && elem.parentNode ) { | |
// Handle the case where IE, Opera, and Webkit return items | |
// by name instead of ID | |
if ( elem.id === m ) { | |
results.push( elem ); | |
return results; | |
} | |
} else { | |
return results; | |
} | |
} else { | |
// Context is not a document | |
if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && | |
contains( context, elem ) && elem.id === m ) { | |
results.push( elem ); | |
return results; | |
} | |
} | |
// Speed-up: Sizzle("TAG") | |
} else if ( match[2] ) { | |
push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); | |
return results; | |
// Speed-up: Sizzle(".CLASS") | |
} else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) { | |
push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); | |
return results; | |
} | |
} | |
} | |
// All others | |
return select( selector, context, results, seed, xml ); | |
}; | |
var Expr = Sizzle.selectors = { | |
// Can be adjusted by the user | |
cacheLength: 50, | |
match: matchExpr, | |
order: [ "ID", "TAG" ], | |
attrHandle: {}, | |
createPseudo: markFunction, | |
find: { | |
"ID": assertGetIdNotName ? | |
function( id, context, xml ) { | |
if ( typeof context.getElementById !== strundefined && !xml ) { | |
var m = context.getElementById( id ); | |
// Check parentNode to catch when Blackberry 4.6 returns | |
// nodes that are no longer in the document #6963 | |
return m && m.parentNode ? [m] : []; | |
} | |
} : | |
function( id, context, xml ) { | |
if ( typeof context.getElementById !== strundefined && !xml ) { | |
var m = context.getElementById( id ); | |
return m ? | |
m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? | |
[m] : | |
undefined : | |
[]; | |
} | |
}, | |
"TAG": assertTagNameNoComments ? | |
function( tag, context ) { | |
if ( typeof context.getElementsByTagName !== strundefined ) { | |
return context.getElementsByTagName( tag ); | |
} | |
} : | |
function( tag, context ) { | |
var results = context.getElementsByTagName( tag ); | |
// Filter out possible comments | |
if ( tag === "*" ) { | |
var elem, | |
tmp = [], | |
i = 0; | |
for ( ; (elem = results[i]); i++ ) { | |
if ( elem.nodeType === 1 ) { | |
tmp.push( elem ); | |
} | |
} | |
return tmp; | |
} | |
return results; | |
} | |
}, | |
relative: { | |
">": { dir: "parentNode", first: true }, | |
" ": { dir: "parentNode" }, | |
"+": { dir: "previousSibling", first: true }, | |
"~": { dir: "previousSibling" } | |
}, | |
preFilter: { | |
"ATTR": function( match ) { | |
match[1] = match[1].replace( rbackslash, "" ); | |
// Move the given value to match[3] whether quoted or unquoted | |
match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" ); | |
if ( match[2] === "~=" ) { | |
match[3] = " " + match[3] + " "; | |
} | |
return match.slice( 0, 4 ); | |
}, | |
"CHILD": function( match ) { | |
/* matches from matchExpr.CHILD | |
1 type (only|nth|...) | |
2 argument (even|odd|\d*|\d*n([+-]\d+)?|...) | |
3 xn-component of xn+y argument ([+-]?\d*n|) | |
4 sign of xn-component | |
5 x of xn-component | |
6 sign of y-component | |
7 y of y-component | |
*/ | |
match[1] = match[1].toLowerCase(); | |
if ( match[1] === "nth" ) { | |
// nth-child requires argument | |
if ( !match[2] ) { | |
Sizzle.error( match[0] ); | |
} | |
// numeric x and y parameters for Expr.filter.CHILD | |
// remember that false/true cast respectively to 0/1 | |
match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) ); | |
match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" ); | |
// other types prohibit arguments | |
} else if ( match[2] ) { | |
Sizzle.error( match[0] ); | |
} | |
return match; | |
}, | |
"PSEUDO": function( match ) { | |
var argument, | |
unquoted = match[4]; | |
if ( matchExpr["CHILD"].test( match[0] ) ) { | |
return null; | |
} | |
// Relinquish our claim on characters in `unquoted` from a closing parenthesis on | |
if ( unquoted && (argument = rselector.exec( unquoted )) && argument.pop() ) { | |
match[0] = match[0].slice( 0, argument[0].length - unquoted.length - 1 ); | |
unquoted = argument[0].slice( 0, -1 ); | |
} | |
// Quoted or unquoted, we have the full argument | |
// Return only captures needed by the pseudo filter method (type and argument) | |
match.splice( 2, 3, unquoted || match[3] ); | |
return match; | |
} | |
}, | |
filter: { | |
"ID": assertGetIdNotName ? | |
function( id ) { | |
id = id.replace( rbackslash, "" ); | |
return function( elem ) { | |
return elem.getAttribute("id") === id; | |
}; | |
} : | |
function( id ) { | |
id = id.replace( rbackslash, "" ); | |
return function( elem ) { | |
var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); | |
return node && node.value === id; | |
}; | |
}, | |
"TAG": function( nodeName ) { | |
if ( nodeName === "*" ) { | |
return function() { return true; }; | |
} | |
nodeName = nodeName.replace( rbackslash, "" ).toLowerCase(); | |
return function( elem ) { | |
return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; | |
}; | |
}, | |
"CLASS": function( className ) { | |
var pattern = classCache[ className ]; | |
if ( !pattern ) { | |
pattern = classCache[ className ] = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" ); | |
cachedClasses.push( className ); | |
// Avoid too large of a cache | |
if ( cachedClasses.length > Expr.cacheLength ) { | |
delete classCache[ cachedClasses.shift() ]; | |
} | |
} | |
return function( elem ) { | |
return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); | |
}; | |
}, | |
"ATTR": function( name, operator, check ) { | |
if ( !operator ) { | |
return function( elem ) { | |
return Sizzle.attr( elem, name ) != null; | |
}; | |
} | |
return function( elem ) { | |
var result = Sizzle.attr( elem, name ), | |
value = result + ""; | |
if ( result == null ) { | |
return operator === "!="; | |
} | |
switch ( operator ) { | |
case "=": | |
return value === check; | |
case "!=": | |
return value !== check; | |
case "^=": | |
return check && value.indexOf( check ) === 0; | |
case "*=": | |
return check && value.indexOf( check ) > -1; | |
case "$=": | |
return check && value.substr( value.length - check.length ) === check; | |
case "~=": | |
return ( " " + value + " " ).indexOf( check ) > -1; | |
case "|=": | |
return value === check || value.substr( 0, check.length + 1 ) === check + "-"; | |
} | |
}; | |
}, | |
"CHILD": function( type, argument, first, last ) { | |
if ( type === "nth" ) { | |
var doneName = done++; | |
return function( elem ) { | |
var parent, diff, | |
count = 0, | |
node = elem; | |
if ( first === 1 && last === 0 ) { | |
return true; | |
} | |
parent = elem.parentNode; | |
if ( parent && (parent[ expando ] !== doneName || !elem.sizset) ) { | |
for ( node = parent.firstChild; node; node = node.nextSibling ) { | |
if ( node.nodeType === 1 ) { | |
node.sizset = ++count; | |
if ( node === elem ) { | |
break; | |
} | |
} | |
} | |
parent[ expando ] = doneName; | |
} | |
diff = elem.sizset - last; | |
if ( first === 0 ) { | |
return diff === 0; | |
} else { | |
return ( diff % first === 0 && diff / first >= 0 ); | |
} | |
}; | |
} | |
return function( elem ) { | |
var node = elem; | |
switch ( type ) { | |
case "only": | |
case "first": | |
while ( (node = node.previousSibling) ) { | |
if ( node.nodeType === 1 ) { | |
return false; | |
} | |
} | |
if ( type === "first" ) { | |
return true; | |
} | |
node = elem; | |
/* falls through */ | |
case "last": | |
while ( (node = node.nextSibling) ) { | |
if ( node.nodeType === 1 ) { | |
return false; | |
} | |
} | |
return true; | |
} | |
}; | |
}, | |
"PSEUDO": function( pseudo, argument, context, xml ) { | |
// pseudo-class names are case-insensitive | |
// http://www.w3.org/TR/selectors/#pseudo-classes | |
// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters | |
var fn = Expr.pseudos[ pseudo ] || Expr.pseudos[ pseudo.toLowerCase() ]; | |
if ( !fn ) { | |
Sizzle.error( "unsupported pseudo: " + pseudo ); | |
} | |
// The user may set fn.sizzleFilter to indicate | |
// that arguments are needed to create the filter function | |
// just as Sizzle does | |
if ( !fn.sizzleFilter ) { | |
return fn; | |
} | |
return fn( argument, context, xml ); | |
} | |
}, | |
pseudos: { | |
"not": markFunction(function( selector, context, xml ) { | |
// Trim the selector passed to compile | |
// to avoid treating leading and trailing | |
// spaces as combinators | |
var matcher = compile( selector.replace( rtrim, "$1" ), context, xml ); | |
return function( elem ) { | |
return !matcher( elem ); | |
}; | |
}), | |
"enabled": function( elem ) { | |
return elem.disabled === false; | |
}, | |
"disabled": function( elem ) { | |
return elem.disabled === true; | |
}, | |
"checked": function( elem ) { | |
// In CSS3, :checked should return both checked and selected elements | |
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked | |
var nodeName = elem.nodeName.toLowerCase(); | |
return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); | |
}, | |
"selected": function( elem ) { | |
// Accessing this property makes selected-by-default | |
// options in Safari work properly | |
if ( elem.parentNode ) { | |
elem.parentNode.selectedIndex; | |
} | |
return elem.selected === true; | |
}, | |
"parent": function( elem ) { | |
return !Expr.pseudos["empty"]( elem ); | |
}, | |
"empty": function( elem ) { | |
// http://www.w3.org/TR/selectors/#empty-pseudo | |
// :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), | |
// not comment, processing instructions, or others | |
// Thanks to Diego Perini for the nodeName shortcut | |
// Greater than "@" means alpha characters (specifically not starting with "#" or "?") | |
var nodeType; | |
elem = elem.firstChild; | |
while ( elem ) { | |
if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) { | |
return false; | |
} | |
elem = elem.nextSibling; | |
} | |
return true; | |
}, | |
"contains": markFunction(function( text ) { | |
return function( elem ) { | |
return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; | |
}; | |
}), | |
"has": markFunction(function( selector ) { | |
return function( elem ) { | |
return Sizzle( selector, elem ).length > 0; | |
}; | |
}), | |
"header": function( elem ) { | |
return rheader.test( elem.nodeName ); | |
}, | |
"text": function( elem ) { | |
var type, attr; | |
// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) | |
// use getAttribute instead to test this case | |
return elem.nodeName.toLowerCase() === "input" && | |
(type = elem.type) === "text" && | |
( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type ); | |
}, | |
// Input types | |
"radio": createInputFunction("radio"), | |
"checkbox": createInputFunction("checkbox"), | |
"file": createInputFunction("file"), | |
"password": createInputFunction("password"), | |
"image": createInputFunction("image"), | |
"submit": createButtonFunction("submit"), | |
"reset": createButtonFunction("reset"), | |
"button": function( elem ) { | |
var name = elem.nodeName.toLowerCase(); | |
return name === "input" && elem.type === "button" || name === "button"; | |
}, | |
"input": function( elem ) { | |
return rinputs.test( elem.nodeName ); | |
}, | |
"focus": function( elem ) { | |
var doc = elem.ownerDocument; | |
return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href); | |
}, | |
"active": function( elem ) { | |
return elem === elem.ownerDocument.activeElement; | |
} | |
}, | |
setFilters: { | |
"first": function( elements, argument, not ) { | |
return not ? elements.slice( 1 ) : [ elements[0] ]; | |
}, | |
"last": function( elements, argument, not ) { | |
var elem = elements.pop(); | |
return not ? elements : [ elem ]; | |
}, | |
"even": function( elements, argument, not ) { | |
var results = [], | |
i = not ? 1 : 0, | |
len = elements.length; | |
for ( ; i < len; i = i + 2 ) { | |
results.push( elements[i] ); | |
} | |
return results; | |
}, | |
"odd": function( elements, argument, not ) { | |
var results = [], | |
i = not ? 0 : 1, | |
len = elements.length; | |
for ( ; i < len; i = i + 2 ) { | |
results.push( elements[i] ); | |
} | |
return results; | |
}, | |
"lt": function( elements, argument, not ) { | |
return not ? elements.slice( +argument ) : elements.slice( 0, +argument ); | |
}, | |
"gt": function( elements, argument, not ) { | |
return not ? elements.slice( 0, +argument + 1 ) : elements.slice( +argument + 1 ); | |
}, | |
"eq": function( elements, argument, not ) { | |
var elem = elements.splice( +argument, 1 ); | |
return not ? elements : elem; | |
} | |
} | |
}; | |
// Deprecated | |
Expr.setFilters["nth"] = Expr.setFilters["eq"]; | |
// Back-compat | |
Expr.filters = Expr.pseudos; | |
// IE6/7 return a modified href | |
if ( !assertHrefNotNormalized ) { | |
Expr.attrHandle = { | |
"href": function( elem ) { | |
return elem.getAttribute( "href", 2 ); | |
}, | |
"type": function( elem ) { | |
return elem.getAttribute("type"); | |
} | |
}; | |
} | |
// Add getElementsByName if usable | |
if ( assertUsableName ) { | |
Expr.order.push("NAME"); | |
Expr.find["NAME"] = function( name, context ) { | |
if ( typeof context.getElementsByName !== strundefined ) { | |
return context.getElementsByName( name ); | |
} | |
}; | |
} | |
// Add getElementsByClassName if usable | |
if ( assertUsableClassName ) { | |
Expr.order.splice( 1, 0, "CLASS" ); | |
Expr.find["CLASS"] = function( className, context, xml ) { | |
if ( typeof context.getElementsByClassName !== strundefined && !xml ) { | |
return context.getElementsByClassName( className ); | |
} | |
}; | |
} | |
// If slice is not available, provide a backup | |
try { | |
slice.call( docElem.childNodes, 0 )[0].nodeType; | |
} catch ( e ) { | |
slice = function( i ) { | |
var elem, results = []; | |
for ( ; (elem = this[i]); i++ ) { | |
results.push( elem ); | |
} | |
return results; | |
}; | |
} | |
var isXML = Sizzle.isXML = function( elem ) { | |
// documentElement is verified for cases where it doesn't yet exist | |
// (such as loading iframes in IE - #4833) | |
var documentElement = elem && (elem.ownerDocument || elem).documentElement; | |
return documentElement ? documentElement.nodeName !== "HTML" : false; | |
}; | |
// Element contains another | |
var contains = Sizzle.contains = docElem.compareDocumentPosition ? | |
function( a, b ) { | |
return !!( a.compareDocumentPosition( b ) & 16 ); | |
} : | |
docElem.contains ? | |
function( a, b ) { | |
var adown = a.nodeType === 9 ? a.documentElement : a, | |
bup = b.parentNode; | |
return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) ); | |
} : | |
function( a, b ) { | |
while ( (b = b.parentNode) ) { | |
if ( b === a ) { | |
return true; | |
} | |
} | |
return false; | |
}; | |
/** | |
* Utility function for retrieving the text value of an array of DOM nodes | |
* @param {Array|Element} elem | |
*/ | |
var getText = Sizzle.getText = function( elem ) { | |
var node, | |
ret = "", | |
i = 0, | |
nodeType = elem.nodeType; | |
if ( nodeType ) { | |
if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { | |
// Use textContent for elements | |
// innerText usage removed for consistency of new lines (see #11153) | |
if ( typeof elem.textContent === "string" ) { | |
return elem.textContent; | |
} else { | |
// Traverse its children | |
for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { | |
ret += getText( elem ); | |
} | |
} | |
} else if ( nodeType === 3 || nodeType === 4 ) { | |
return elem.nodeValue; | |
} | |
// Do not include comment or processing instruction nodes | |
} else { | |
// If no nodeType, this is expected to be an array | |
for ( ; (node = elem[i]); i++ ) { | |
// Do not traverse comment nodes | |
ret += getText( node ); | |
} | |
} | |
return ret; | |
}; | |
Sizzle.attr = function( elem, name ) { | |
var attr, | |
xml = isXML( elem ); | |
if ( !xml ) { | |
name = name.toLowerCase(); | |
} | |
if ( Expr.attrHandle[ name ] ) { | |
return Expr.attrHandle[ name ]( elem ); | |
} | |
if ( assertAttributes || xml ) { | |
return elem.getAttribute( name ); | |
} | |
attr = elem.getAttributeNode( name ); | |
return attr ? | |
typeof elem[ name ] === "boolean" ? | |
elem[ name ] ? name : null : | |
attr.specified ? attr.value : null : | |
null; | |
}; | |
Sizzle.error = function( msg ) { | |
throw new Error( "Syntax error, unrecognized expression: " + msg ); | |
}; | |
// Check if the JavaScript engine is using some sort of | |
// optimization where it does not always call our comparision | |
// function. If that is the case, discard the hasDuplicate value. | |
// Thus far that includes Google Chrome. | |
[0, 0].sort(function() { | |
return (baseHasDuplicate = 0); | |
}); | |
if ( docElem.compareDocumentPosition ) { | |
sortOrder = function( a, b ) { | |
if ( a === b ) { | |
hasDuplicate = true; | |
return 0; | |
} | |
return ( !a.compareDocumentPosition || !b.compareDocumentPosition ? | |
a.compareDocumentPosition : | |
a.compareDocumentPosition(b) & 4 | |
) ? -1 : 1; | |
}; | |
} else { | |
sortOrder = function( a, b ) { | |
// The nodes are identical, we can exit early | |
if ( a === b ) { | |
hasDuplicate = true; | |
return 0; | |
// Fallback to using sourceIndex (in IE) if it's available on both nodes | |
} else if ( a.sourceIndex && b.sourceIndex ) { | |
return a.sourceIndex - b.sourceIndex; | |
} | |
var al, bl, | |
ap = [], | |
bp = [], | |
aup = a.parentNode, | |
bup = b.parentNode, | |
cur = aup; | |
// If the nodes are siblings (or identical) we can do a quick check | |
if ( aup === bup ) { | |
return siblingCheck( a, b ); | |
// If no parents were found then the nodes are disconnected | |
} else if ( !aup ) { | |
return -1; | |
} else if ( !bup ) { | |
return 1; | |
} | |
// Otherwise they're somewhere else in the tree so we need | |
// to build up a full list of the parentNodes for comparison | |
while ( cur ) { | |
ap.unshift( cur ); | |
cur = cur.parentNode; | |
} | |
cur = bup; | |
while ( cur ) { | |
bp.unshift( cur ); | |
cur = cur.parentNode; | |
} | |
al = ap.length; | |
bl = bp.length; | |
// Start walking down the tree looking for a discrepancy | |
for ( var i = 0; i < al && i < bl; i++ ) { | |
if ( ap[i] !== bp[i] ) { | |
return siblingCheck( ap[i], bp[i] ); | |
} | |
} | |
// We ended someplace up the tree so do a sibling check | |
return i === al ? | |
siblingCheck( a, bp[i], -1 ) : | |
siblingCheck( ap[i], b, 1 ); | |
}; | |
siblingCheck = function( a, b, ret ) { | |
if ( a === b ) { | |
return ret; | |
} | |
var cur = a.nextSibling; | |
while ( cur ) { | |
if ( cur === b ) { | |
return -1; | |
} | |
cur = cur.nextSibling; | |
} | |
return 1; | |
}; | |
} | |
// Document sorting and removing duplicates | |
Sizzle.uniqueSort = function( results ) { | |
var elem, | |
i = 1; | |
if ( sortOrder ) { | |
hasDuplicate = baseHasDuplicate; | |
results.sort( sortOrder ); | |
if ( hasDuplicate ) { | |
for ( ; (elem = results[i]); i++ ) { | |
if ( elem === results[ i - 1 ] ) { | |
results.splice( i--, 1 ); | |
} | |
} | |
} | |
} | |
return results; | |
}; | |
function multipleContexts( selector, contexts, results, seed ) { | |
var i = 0, | |
len = contexts.length; | |
for ( ; i < len; i++ ) { | |
Sizzle( selector, contexts[i], results, seed ); | |
} | |
} | |
function handlePOSGroup( selector, posfilter, argument, contexts, seed, not ) { | |
var results, | |
fn = Expr.setFilters[ posfilter.toLowerCase() ]; | |
if ( !fn ) { | |
Sizzle.error( posfilter ); | |
} | |
if ( selector || !(results = seed) ) { | |
multipleContexts( selector || "*", contexts, (results = []), seed ); | |
} | |
return results.length > 0 ? fn( results, argument, not ) : []; | |
} | |
function handlePOS( selector, context, results, seed, groups ) { | |
var match, not, anchor, ret, elements, currentContexts, part, lastIndex, | |
i = 0, | |
len = groups.length, | |
rpos = matchExpr["POS"], | |
// This is generated here in case matchExpr["POS"] is extended | |
rposgroups = new RegExp( "^" + rpos.source + "(?!" + whitespace + ")", "i" ), | |
// This is for making sure non-participating | |
// matching groups are represented cross-browser (IE6-8) | |
setUndefined = function() { | |
var i = 1, | |
len = arguments.length - 2; | |
for ( ; i < len; i++ ) { | |
if ( arguments[i] === undefined ) { | |
match[i] = undefined; | |
} | |
} | |
}; | |
for ( ; i < len; i++ ) { | |
// Reset regex index to 0 | |
rpos.exec(""); | |
selector = groups[i]; | |
ret = []; | |
anchor = 0; | |
elements = seed; | |
while ( (match = rpos.exec( selector )) ) { | |
lastIndex = rpos.lastIndex = match.index + match[0].length; | |
if ( lastIndex > anchor ) { | |
part = selector.slice( anchor, match.index ); | |
anchor = lastIndex; | |
currentContexts = [ context ]; | |
if ( rcombinators.test(part) ) { | |
if ( elements ) { | |
currentContexts = elements; | |
} | |
elements = seed; | |
} | |
if ( (not = rendsWithNot.test( part )) ) { | |
part = part.slice( 0, -5 ).replace( rcombinators, "$&*" ); | |
} | |
if ( match.length > 1 ) { | |
match[0].replace( rposgroups, setUndefined ); | |
} | |
elements = handlePOSGroup( part, match[1], match[2], currentContexts, elements, not ); | |
} | |
} | |
if ( elements ) { | |
ret = ret.concat( elements ); | |
if ( (part = selector.slice( anchor )) && part !== ")" ) { | |
if ( rcombinators.test(part) ) { | |
multipleContexts( part, ret, results, seed ); | |
} else { | |
Sizzle( part, context, results, seed ? seed.concat(elements) : elements ); | |
} | |
} else { | |
push.apply( results, ret ); | |
} | |
} else { | |
Sizzle( selector, context, results, seed ); | |
} | |
} | |
// Do not sort if this is a single filter | |
return len === 1 ? results : Sizzle.uniqueSort( results ); | |
} | |
function tokenize( selector, context, xml ) { | |
var tokens, soFar, type, | |
groups = [], | |
i = 0, | |
// Catch obvious selector issues: terminal ")"; nonempty fallback match | |
// rselector never fails to match *something* | |
match = rselector.exec( selector ), | |
matched = !match.pop() && !match.pop(), | |
selectorGroups = matched && selector.match( rgroups ) || [""], | |
preFilters = Expr.preFilter, | |
filters = Expr.filter, | |
checkContext = !xml && context !== document; | |
for ( ; (soFar = selectorGroups[i]) != null && matched; i++ ) { | |
groups.push( tokens = [] ); | |
// Need to make sure we're within a narrower context if necessary | |
// Adding a descendant combinator will generate what is needed | |
if ( checkContext ) { | |
soFar = " " + soFar; | |
} | |
while ( soFar ) { | |
matched = false; | |
// Combinators | |
if ( (match = rcombinators.exec( soFar )) ) { | |
soFar = soFar.slice( match[0].length ); | |
// Cast descendant combinators to space | |
matched = tokens.push({ part: match.pop().replace( rtrim, " " ), captures: match }); | |
} | |
// Filters | |
for ( type in filters ) { | |
if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || | |
(match = preFilters[ type ]( match, context, xml )) ) ) { | |
soFar = soFar.slice( match.shift().length ); | |
matched = tokens.push({ part: type, captures: match }); | |
} | |
} | |
if ( !matched ) { | |
break; | |
} | |
} | |
} | |
if ( !matched ) { | |
Sizzle.error( selector ); | |
} | |
return groups; | |
} | |
function addCombinator( matcher, combinator, context ) { | |
var dir = combinator.dir, | |
doneName = done++; | |
if ( !matcher ) { | |
// If there is no matcher to check, check against the context | |
matcher = function( elem ) { | |
return elem === context; | |
}; | |
} | |
return combinator.first ? | |
function( elem, context ) { | |
while ( (elem = elem[ dir ]) ) { | |
if ( elem.nodeType === 1 ) { | |
return matcher( elem, context ) && elem; | |
} | |
} | |
} : | |
function( elem, context ) { | |
var cache, | |
dirkey = doneName + "." + dirruns, | |
cachedkey = dirkey + "." + cachedruns; | |
while ( (elem = elem[ dir ]) ) { | |
if ( elem.nodeType === 1 ) { | |
if ( (cache = elem[ expando ]) === cachedkey ) { | |
return elem.sizset; | |
} else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) { | |
if ( elem.sizset ) { | |
return elem; | |
} | |
} else { | |
elem[ expando ] = cachedkey; | |
if ( matcher( elem, context ) ) { | |
elem.sizset = true; | |
return elem; | |
} | |
elem.sizset = false; | |
} | |
} | |
} | |
}; | |
} | |
function addMatcher( higher, deeper ) { | |
return higher ? | |
function( elem, context ) { | |
var result = deeper( elem, context ); | |
return result && higher( result === true ? elem : result, context ); | |
} : | |
deeper; | |
} | |
// ["TAG", ">", "ID", " ", "CLASS"] | |
function matcherFromTokens( tokens, context, xml ) { | |
var token, matcher, | |
i = 0; | |
for ( ; (token = tokens[i]); i++ ) { | |
if ( Expr.relative[ token.part ] ) { | |
matcher = addCombinator( matcher, Expr.relative[ token.part ], context ); | |
} else { | |
token.captures.push( context, xml ); | |
matcher = addMatcher( matcher, Expr.filter[ token.part ].apply( null, token.captures ) ); | |
} | |
} | |
return matcher; | |
} | |
function matcherFromGroupMatchers( matchers ) { | |
return function( elem, context ) { | |
var matcher, | |
j = 0; | |
for ( ; (matcher = matchers[j]); j++ ) { | |
if ( matcher(elem, context) ) { | |
return true; | |
} | |
} | |
return false; | |
}; | |
} | |
var compile = Sizzle.compile = function( selector, context, xml ) { | |
var tokens, group, i, | |
cached = compilerCache[ selector ]; | |
// Return a cached group function if already generated (context dependent) | |
if ( cached && cached.context === context ) { | |
return cached; | |
} | |
// Generate a function of recursive functions that can be used to check each element | |
group = tokenize( selector, context, xml ); | |
for ( i = 0; (tokens = group[i]); i++ ) { | |
group[i] = matcherFromTokens( tokens, context, xml ); | |
} | |
// Cache the compiled function | |
cached = compilerCache[ selector ] = matcherFromGroupMatchers( group ); | |
cached.context = context; | |
cached.runs = cached.dirruns = 0; | |
cachedSelectors.push( selector ); | |
// Ensure only the most recent are cached | |
if ( cachedSelectors.length > Expr.cacheLength ) { | |
delete compilerCache[ cachedSelectors.shift() ]; | |
} | |
return cached; | |
}; | |
Sizzle.matches = function( expr, elements ) { | |
return Sizzle( expr, null, null, elements ); | |
}; | |
Sizzle.matchesSelector = function( elem, expr ) { | |
return Sizzle( expr, null, null, [ elem ] ).length > 0; | |
}; | |
var select = function( selector, context, results, seed, xml ) { | |
// Remove excessive whitespace | |
selector = selector.replace( rtrim, "$1" ); | |
var elements, matcher, i, len, elem, token, | |
type, findContext, notTokens, | |
match = selector.match( rgroups ), | |
tokens = selector.match( rtokens ), | |
contextNodeType = context.nodeType; | |
// POS handling | |
if ( matchExpr["POS"].test(selector) ) { | |
return handlePOS( selector, context, results, seed, match ); | |
} | |
if ( seed ) { | |
elements = slice.call( seed, 0 ); | |
// To maintain document order, only narrow the | |
// set if there is one group | |
} else if ( match && match.length === 1 ) { | |
// Take a shortcut and set the context if the root selector is an ID | |
if ( tokens.length > 1 && contextNodeType === 9 && !xml && | |
(match = matchExpr["ID"].exec( tokens[0] )) ) { | |
context = Expr.find["ID"]( match[1], context, xml )[0]; | |
if ( !context ) { | |
return results; | |
} | |
selector = selector.slice( tokens.shift().length ); | |
} | |
findContext = ( (match = rsibling.exec( tokens[0] )) && !match.index && context.parentNode ) || context; | |
// Get the last token, excluding :not | |
notTokens = tokens.pop(); | |
token = notTokens.split(":not")[0]; | |
for ( i = 0, len = Expr.order.length; i < len; i++ ) { | |
type = Expr.order[i]; | |
if ( (match = matchExpr[ type ].exec( token )) ) { | |
elements = Expr.find[ type ]( (match[1] || "").replace( rbackslash, "" ), findContext, xml ); | |
if ( elements == null ) { | |
continue; | |
} | |
if ( token === notTokens ) { | |
selector = selector.slice( 0, selector.length - notTokens.length ) + | |
token.replace( matchExpr[ type ], "" ); | |
if ( !selector ) { | |
push.apply( results, slice.call(elements, 0) ); | |
} | |
} | |
break; | |
} | |
} | |
} | |
// Only loop over the given elements once | |
// If selector is empty, we're already done | |
if ( selector ) { | |
matcher = compile( selector, context, xml ); | |
dirruns = matcher.dirruns++; | |
if ( elements == null ) { | |
elements = Expr.find["TAG"]( "*", (rsibling.test( selector ) && context.parentNode) || context ); | |
} | |
for ( i = 0; (elem = elements[i]); i++ ) { | |
cachedruns = matcher.runs++; | |
if ( matcher(elem, context) ) { | |
results.push( elem ); | |
} | |
} | |
} | |
return results; | |
}; | |
if ( document.querySelectorAll ) { | |
(function() { | |
var disconnectedMatch, | |
oldSelect = select, | |
rescape = /'|\\/g, | |
rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, | |
rbuggyQSA = [], | |
// matchesSelector(:active) reports false when true (IE9/Opera 11.5) | |
// A support test would require too much code (would include document ready) | |
// just skip matchesSelector for :active | |
rbuggyMatches = [":active"], | |
matches = docElem.matchesSelector || | |
docElem.mozMatchesSelector || | |
docElem.webkitMatchesSelector || | |
docElem.oMatchesSelector || | |
docElem.msMatchesSelector; | |
// Build QSA regex | |
// Regex strategy adopted from Diego Perini | |
assert(function( div ) { | |
div.innerHTML = "<select><option selected></option></select>"; | |
// IE8 - Some boolean attributes are not treated correctly | |
if ( !div.querySelectorAll("[selected]").length ) { | |
rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); | |
} | |
// Webkit/Opera - :checked should return selected option elements | |
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked | |
// IE8 throws error here (do not put tests after this one) | |
if ( !div.querySelectorAll(":checked").length ) { | |
rbuggyQSA.push(":checked"); | |
} | |
}); | |
assert(function( div ) { | |
// Opera 10-12/IE9 - ^= $= *= and empty values | |
// Should not select anything | |
div.innerHTML = "<p test=''></p>"; | |
if ( div.querySelectorAll("[test^='']").length ) { | |
rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); | |
} | |
// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) | |
// IE8 throws error here (do not put tests after this one) | |
div.innerHTML = "<input type='hidden'>"; | |
if ( !div.querySelectorAll(":enabled").length ) { | |
rbuggyQSA.push(":enabled", ":disabled"); | |
} | |
}); | |
rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); | |
select = function( selector, context, results, seed, xml ) { | |
// Only use querySelectorAll when not filtering, | |
// when this is not xml, | |
// and when no QSA bugs apply | |
if ( !seed && !xml && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { | |
if ( context.nodeType === 9 ) { | |
try { | |
push.apply( results, slice.call(context.querySelectorAll( selector ), 0) ); | |
return results; | |
} catch(qsaError) {} | |
// qSA works strangely on Element-rooted queries | |
// We can work around this by specifying an extra ID on the root | |
// and working up from there (Thanks to Andrew Dupont for the technique) | |
// IE 8 doesn't work on object elements | |
} else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { | |
var old = context.getAttribute("id"), | |
nid = old || expando, | |
newContext = rsibling.test( selector ) && context.parentNode || context; | |
if ( old ) { | |
nid = nid.replace( rescape, "\\$&" ); | |
} else { | |
context.setAttribute( "id", nid ); | |
} | |
try { | |
push.apply( results, slice.call( newContext.querySelectorAll( | |
selector.replace( rgroups, "[id='" + nid + "'] $&" ) | |
), 0 ) ); | |
return results; | |
} catch(qsaError) { | |
} finally { | |
if ( !old ) { | |
context.removeAttribute("id"); | |
} | |
} | |
} | |
} | |
return oldSelect( selector, context, results, seed, xml ); | |
}; | |
if ( matches ) { | |
assert(function( div ) { | |
// Check to see if it's possible to do matchesSelector | |
// on a disconnected node (IE 9) | |
disconnectedMatch = matches.call( div, "div" ); | |
// This should fail with an exception | |
// Gecko does not error, returns false instead | |
try { | |
matches.call( div, "[test!='']:sizzle" ); | |
rbuggyMatches.push( Expr.match.PSEUDO ); | |
} catch ( e ) {} | |
}); | |
// rbuggyMatches always contains :active, so no need for a length check | |
rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") ); | |
Sizzle.matchesSelector = function( elem, expr ) { | |
// Make sure that attribute selectors are quoted | |
expr = expr.replace( rattributeQuotes, "='$1']" ); | |
// rbuggyMatches always contains :active, so no need for an existence check | |
if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && (!rbuggyQSA || !rbuggyQSA.test( expr )) ) { | |
try { | |
var ret = matches.call( elem, expr ); | |
// IE 9's matchesSelector returns false on disconnected nodes | |
if ( ret || disconnectedMatch || | |
// As well, disconnected nodes are said to be in a document | |
// fragment in IE 9 | |
elem.document && elem.document.nodeType !== 11 ) { | |
return ret; | |
} | |
} catch(e) {} | |
} | |
return Sizzle( expr, null, null, [ elem ] ).length > 0; | |
}; | |
} | |
})(); | |
} | |
// Override sizzle attribute retrieval | |
Sizzle.attr = jQuery.attr; | |
jQuery.find = Sizzle; | |
jQuery.expr = Sizzle.selectors; | |
jQuery.expr[":"] = jQuery.expr.pseudos; | |
jQuery.unique = Sizzle.uniqueSort; | |
jQuery.text = Sizzle.getText; | |
jQuery.isXMLDoc = Sizzle.isXML; | |
jQuery.contains = Sizzle.contains; | |
})( window ); | |
var runtil = /Until$/, | |
rparentsprev = /^(?:parents|prev(?:Until|All))/, | |
isSimple = /^.[^:#\[\.,]*$/, | |
rneedsContext = jQuery.expr.match.needsContext, | |
// methods guaranteed to produce a unique set when starting from a unique set | |
guaranteedUnique = { | |
children: true, | |
contents: true, | |
next: true, | |
prev: true | |
}; | |
jQuery.fn.extend({ | |
find: function( selector ) { | |
var i, l, length, n, r, ret, | |
self = this; | |
if ( typeof selector !== "string" ) { | |
return jQuery( selector ).filter(function() { | |
for ( i = 0, l = self.length; i < l; i++ ) { | |
if ( jQuery.contains( self[ i ], this ) ) { | |
return true; | |
} | |
} | |
}); | |
} | |
ret = this.pushStack( "", "find", selector ); | |
for ( i = 0, l = this.length; i < l; i++ ) { | |
length = ret.length; | |
jQuery.find( selector, this[i], ret ); | |
if ( i > 0 ) { | |
// Make sure that the results are unique | |
for ( n = length; n < ret.length; n++ ) { | |
for ( r = 0; r < length; r++ ) { | |
if ( ret[r] === ret[n] ) { | |
ret.splice(n--, 1); | |
break; | |
} | |
} | |
} | |
} | |
} | |
return ret; | |
}, | |
has: function( target ) { | |
var i, | |
targets = jQuery( target, this ), | |
len = targets.length; | |
return this.filter(function() { | |
for ( i = 0; i < len; i++ ) { | |
if ( jQuery.contains( this, targets[i] ) ) { | |
return true; | |
} | |
} | |
}); | |
}, | |
not: function( selector ) { | |
return this.pushStack( winnow(this, selector, false), "not", selector); | |
}, | |
filter: function( selector ) { | |
return this.pushStack( winnow(this, selector, true), "filter", selector ); | |
}, | |
is: function( selector ) { | |
return !!selector && ( | |
typeof selector === "string" ? | |
// If this is a positional/relative selector, check membership in the returned set | |
// so $("p:first").is("p:last") won't return true for a doc with two "p". | |
rneedsContext.test( selector ) ? | |
jQuery( selector, this.context ).index( this[0] ) >= 0 : | |
jQuery.filter( selector, this ).length > 0 : | |
this.filter( selector ).length > 0 ); | |
}, | |
closest: function( selectors, context ) { | |
var cur, | |
i = 0, | |
l = this.length, | |
ret = [], | |
pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? | |
jQuery( selectors, context || this.context ) : | |
0; | |
for ( ; i < l; i++ ) { | |
cur = this[i]; | |
while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) { | |
if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { | |
ret.push( cur ); | |
break; | |
} | |
cur = cur.parentNode; | |
} | |
} | |
ret = ret.length > 1 ? jQuery.unique( ret ) : ret; | |
return this.pushStack( ret, "closest", selectors ); | |
}, | |
// Determine the position of an element within | |
// the matched set of elements | |
index: function( elem ) { | |
// No argument, return index in parent | |
if ( !elem ) { | |
return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; | |
} | |
// index in selector | |
if ( typeof elem === "string" ) { | |
return jQuery.inArray( this[0], jQuery( elem ) ); | |
} | |
// Locate the position of the desired element | |
return jQuery.inArray( | |
// If it receives a jQuery object, the first element is used | |
elem.jquery ? elem[0] : elem, this ); | |
}, | |
add: function( selector, context ) { | |
var set = typeof selector === "string" ? | |
jQuery( selector, context ) : | |
jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), | |
all = jQuery.merge( this.get(), set ); | |
return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? | |
all : | |
jQuery.unique( all ) ); | |
}, | |
addBack: function( selector ) { | |
return this.add( selector == null ? | |
this.prevObject : this.prevObject.filter(selector) | |
); | |
} | |
}); | |
jQuery.fn.andSelf = jQuery.fn.addBack; | |
// A painfully simple check to see if an element is disconnected | |
// from a document (should be improved, where feasible). | |
function isDisconnected( node ) { | |
return !node || !node.parentNode || node.parentNode.nodeType === 11; | |
} | |
function sibling( cur, dir ) { | |
do { | |
cur = cur[ dir ]; | |
} while ( cur && cur.nodeType !== 1 ); | |
return cur; | |
} | |
jQuery.each({ | |
parent: function( elem ) { | |
var parent = elem.parentNode; | |
return parent && parent.nodeType !== 11 ? parent : null; | |
}, | |
parents: function( elem ) { | |
return jQuery.dir( elem, "parentNode" ); | |
}, | |
parentsUntil: function( elem, i, until ) { | |
return jQuery.dir( elem, "parentNode", until ); | |
}, | |
next: function( elem ) { | |
return sibling( elem, "nextSibling" ); | |
}, | |
prev: function( elem ) { | |
return sibling( elem, "previousSibling" ); | |
}, | |
nextAll: function( elem ) { | |
return jQuery.dir( elem, "nextSibling" ); | |
}, | |
prevAll: function( elem ) { | |
return jQuery.dir( elem, "previousSibling" ); | |
}, | |
nextUntil: function( elem, i, until ) { | |
return jQuery.dir( elem, "nextSibling", until ); | |
}, | |
prevUntil: function( elem, i, until ) { | |
return jQuery.dir( elem, "previousSibling", until ); | |
}, | |
siblings: function( elem ) { | |
return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); | |
}, | |
children: function( elem ) { | |
return jQuery.sibling( elem.firstChild ); | |
}, | |
contents: function( elem ) { | |
return jQuery.nodeName( elem, "iframe" ) ? | |
elem.contentDocument || elem.contentWindow.document : | |
jQuery.merge( [], elem.childNodes ); | |
} | |
}, function( name, fn ) { | |
jQuery.fn[ name ] = function( until, selector ) { | |
var ret = jQuery.map( this, fn, until ); | |
if ( !runtil.test( name ) ) { | |
selector = until; | |
} | |
if ( selector && typeof selector === "string" ) { | |
ret = jQuery.filter( selector, ret ); | |
} | |
ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; | |
if ( this.length > 1 && rparentsprev.test( name ) ) { | |
ret = ret.reverse(); | |
} | |
return this.pushStack( ret, name, core_slice.call( arguments ).join(",") ); | |
}; | |
}); | |
jQuery.extend({ | |
filter: function( expr, elems, not ) { | |
if ( not ) { | |
expr = ":not(" + expr + ")"; | |
} | |
return elems.length === 1 ? | |
jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : | |
jQuery.find.matches(expr, elems); | |
}, | |
dir: function( elem, dir, until ) { | |
var matched = [], | |
cur = elem[ dir ]; | |
while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { | |
if ( cur.nodeType === 1 ) { | |
matched.push( cur ); | |
} | |
cur = cur[dir]; | |
} | |
return matched; | |
}, | |
sibling: function( n, elem ) { | |
var r = []; | |
for ( ; n; n = n.nextSibling ) { | |
if ( n.nodeType === 1 && n !== elem ) { | |
r.push( n ); | |
} | |
} | |
return r; | |
} | |
}); | |
// Implement the identical functionality for filter and not | |
function winnow( elements, qualifier, keep ) { | |
// Can't pass null or undefined to indexOf in Firefox 4 | |
// Set to 0 to skip string check | |
qualifier = qualifier || 0; | |
if ( jQuery.isFunction( qualifier ) ) { | |
return jQuery.grep(elements, function( elem, i ) { | |
var retVal = !!qualifier.call( elem, i, elem ); | |
return retVal === keep; | |
}); | |
} else if ( qualifier.nodeType ) { | |
return jQuery.grep(elements, function( elem, i ) { | |
return ( elem === qualifier ) === keep; | |
}); | |
} else if ( typeof qualifier === "string" ) { | |
var filtered = jQuery.grep(elements, function( elem ) { | |
return elem.nodeType === 1; | |
}); | |
if ( isSimple.test( qualifier ) ) { | |
return jQuery.filter(qualifier, filtered, !keep); | |
} else { | |
qualifier = jQuery.filter( qualifier, filtered ); | |
} | |
} | |
return jQuery.grep(elements, function( elem, i ) { | |
return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; | |
}); | |
} | |
function createSafeFragment( document ) { | |
var list = nodeNames.split( "|" ), | |
safeFrag = document.createDocumentFragment(); | |
if ( safeFrag.createElement ) { | |
while ( list.length ) { | |
safeFrag.createElement( | |
list.pop() | |
); | |
} | |
} | |
return safeFrag; | |
} | |
var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + | |
"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", | |
rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, | |
rleadingWhitespace = /^\s+/, | |
rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, | |
rtagName = /<([\w:]+)/, | |
rtbody = /<tbody/i, | |
rhtml = /<|&#?\w+;/, | |
rnoInnerhtml = /<(?:script|style|link)/i, | |
rnocache = /<(?:script|object|embed|option|style)/i, | |
rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), | |
rcheckableType = /^(?:checkbox|radio)$/, | |
// checked="checked" or checked | |
rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, | |
rscriptType = /\/(java|ecma)script/i, | |
rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g, | |
wrapMap = { | |
option: [ 1, "<select multiple='multiple'>", "</select>" ], | |
legend: [ 1, "<fieldset>", "</fieldset>" ], | |
thead: [ 1, "<table>", "</table>" ], | |
tr: [ 2, "<table><tbody>", "</tbody></table>" ], | |
td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ], | |
col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ], | |
area: [ 1, "<map>", "</map>" ], | |
_default: [ 0, "", "" ] | |
}, | |
safeFragment = createSafeFragment( document ), | |
fragmentDiv = safeFragment.appendChild( document.createElement("div") ); | |
wrapMap.optgroup = wrapMap.option; | |
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; | |
wrapMap.th = wrapMap.td; | |
// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, | |
// unless wrapped in a div with non-breaking characters in front of it. | |
if ( !jQuery.support.htmlSerialize ) { | |
wrapMap._default = [ 1, "X<div>", "</div>" ]; | |
} | |
jQuery.fn.extend({ | |
text: function( value ) { | |
return jQuery.access( this, function( value ) { | |
return value === undefined ? | |
jQuery.text( this ) : | |
this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); | |
}, null, value, arguments.length ); | |
}, | |
wrapAll: function( html ) { | |
if ( jQuery.isFunction( html ) ) { | |
return this.each(function(i) { | |
jQuery(this).wrapAll( html.call(this, i) ); | |
}); | |
} | |
if ( this[0] ) { | |
// The elements to wrap the target around | |
var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); | |
if ( this[0].parentNode ) { | |
wrap.insertBefore( this[0] ); | |
} | |
wrap.map(function() { | |
var elem = this; | |
while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { | |
elem = elem.firstChild; | |
} | |
return elem; | |
}).append( this ); | |
} | |
return this; | |
}, | |
wrapInner: function( html ) { | |
if ( jQuery.isFunction( html ) ) { | |
return this.each(function(i) { | |
jQuery(this).wrapInner( html.call(this, i) ); | |
}); | |
} | |
return this.each(function() { | |
var self = jQuery( this ), | |
contents = self.contents(); | |
if ( contents.length ) { | |
contents.wrapAll( html ); | |
} else { | |
self.append( html ); | |
} | |
}); | |
}, | |
wrap: function( html ) { | |
var isFunction = jQuery.isFunction( html ); | |
return this.each(function(i) { | |
jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); | |
}); | |
}, | |
unwrap: function() { | |
return this.parent().each(function() { | |
if ( !jQuery.nodeName( this, "body" ) ) { | |
jQuery( this ).replaceWith( this.childNodes ); | |
} | |
}).end(); | |
}, | |
append: function() { | |
return this.domManip(arguments, true, function( elem ) { | |
if ( this.nodeType === 1 || this.nodeType === 11 ) { | |
this.appendChild( elem ); | |
} | |
}); | |
}, | |
prepend: function() { | |
return this.domManip(arguments, true, function( elem ) { | |
if ( this.nodeType === 1 || this.nodeType === 11 ) { | |
this.insertBefore( elem, this.firstChild ); | |
} | |
}); | |
}, | |
before: function() { | |
if ( !isDisconnected( this[0] ) ) { | |
return this.domManip(arguments, false, function( elem ) { | |
this.parentNode.insertBefore( elem, this ); | |
}); | |
} | |
if ( arguments.length ) { | |
var set = jQuery.clean( arguments ); | |
return this.pushStack( jQuery.merge( set, this ), "before", this.selector ); | |
} | |
}, | |
after: function() { | |
if ( !isDisconnected( this[0] ) ) { | |
return this.domManip(arguments, false, function( elem ) { | |
this.parentNode.insertBefore( elem, this.nextSibling ); | |
}); | |
} | |
if ( arguments.length ) { | |
var set = jQuery.clean( arguments ); | |
return this.pushStack( jQuery.merge( this, set ), "after", this.selector ); | |
} | |
}, | |
// keepData is for internal use only--do not document | |
remove: function( selector, keepData ) { | |
var elem, | |
i = 0; | |
for ( ; (elem = this[i]) != null; i++ ) { | |
if ( !selector || jQuery.filter( selector, [ elem ] ).length ) { | |
if ( !keepData && elem.nodeType === 1 ) { | |
jQuery.cleanData( elem.getElementsByTagName("*") ); | |
jQuery.cleanData( [ elem ] ); | |
} | |
if ( elem.parentNode ) { | |
elem.parentNode.removeChild( elem ); | |
} | |
} | |
} | |
return this; | |
}, | |
empty: function() { | |
var elem, | |
i = 0; | |
for ( ; (elem = this[i]) != null; i++ ) { | |
// Remove element nodes and prevent memory leaks | |
if ( elem.nodeType === 1 ) { | |
jQuery.cleanData( elem.getElementsByTagName("*") ); | |
} | |
// Remove any remaining nodes | |
while ( elem.firstChild ) { | |
elem.removeChild( elem.firstChild ); | |
} | |
} | |
return this; | |
}, | |
clone: function( dataAndEvents, deepDataAndEvents ) { | |
dataAndEvents = dataAndEvents == null ? false : dataAndEvents; | |
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; | |
return this.map( function () { | |
return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); | |
}); | |
}, | |
html: function( value ) { | |
return jQuery.access( this, function( value ) { | |
var elem = this[0] || {}, | |
i = 0, | |
l = this.length; | |
if ( value === undefined ) { | |
return elem.nodeType === 1 ? | |
elem.innerHTML.replace( rinlinejQuery, "" ) : | |
undefined; | |
} | |
// See if we can take a shortcut and just use innerHTML | |
if ( typeof value === "string" && !rnoInnerhtml.test( value ) && | |
( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && | |
( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && | |
!wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { | |
value = value.replace( rxhtmlTag, "<$1></$2>" ); | |
try { | |
for (; i < l; i++ ) { | |
// Remove element nodes and prevent memory leaks | |
elem = this[i] || {}; | |
if ( elem.nodeType === 1 ) { | |
jQuery.cleanData( elem.getElementsByTagName( "*" ) ); | |
elem.innerHTML = value; | |
} | |
} | |
elem = 0; | |
// If using innerHTML throws an exception, use the fallback method | |
} catch(e) {} | |
} | |
if ( elem ) { | |
this.empty().append( value ); | |
} | |
}, null, value, arguments.length ); | |
}, | |
replaceWith: function( value ) { | |
if ( !isDisconnected( this[0] ) ) { | |
// Make sure that the elements are removed from the DOM before they are inserted | |
// this can help fix replacing a parent with child elements | |
if ( jQuery.isFunction( value ) ) { | |
return this.each(function(i) { | |
var self = jQuery(this), old = self.html(); | |
self.replaceWith( value.call( this, i, old ) ); | |
}); | |
} | |
if ( typeof value !== "string" ) { | |
value = jQuery( value ).detach(); | |
} | |
return this.each(function() { | |
var next = this.nextSibling, | |
parent = this.parentNode; | |
jQuery( this ).remove(); | |
if ( next ) { | |
jQuery(next).before( value ); | |
} else { | |
jQuery(parent).append( value ); | |
} | |
}); | |
} | |
return this.length ? | |
this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) : | |
this; | |
}, | |
detach: function( selector ) { | |
return this.remove( selector, true ); | |
}, | |
domManip: function( args, table, callback ) { | |
// Flatten any nested arrays | |
args = [].concat.apply( [], args ); | |
var results, first, fragment, iNoClone, | |
i = 0, | |
value = args[0], | |
scripts = [], | |
l = this.length; | |
// We can't cloneNode fragments that contain checked, in WebKit | |
if ( !jQuery.support.checkClone && l > 1 && typeof value === "string" && rchecked.test( value ) ) { | |
return this.each(function() { | |
jQuery(this).domManip( args, table, callback ); | |
}); | |
} | |
if ( jQuery.isFunction(value) ) { | |
return this.each(function(i) { | |
var self = jQuery(this); | |
args[0] = value.call( this, i, table ? self.html() : undefined ); | |
self.domManip( args, table, callback ); | |
}); | |
} | |
if ( this[0] ) { | |
results = jQuery.buildFragment( args, this, scripts ); | |
fragment = results.fragment; | |
first = fragment.firstChild; | |
if ( fragment.childNodes.length === 1 ) { | |
fragment = first; | |
} | |
if ( first ) { | |
table = table && jQuery.nodeName( first, "tr" ); | |
// Use the original fragment for the last item instead of the first because it can end up | |
// being emptied incorrectly in certain situations (#8070). | |
// Fragments from the fragment cache must always be cloned and never used in place. | |
for ( iNoClone = results.cacheable || l - 1; i < l; i++ ) { | |
callback.call( | |
table && jQuery.nodeName( this[i], "table" ) ? | |
findOrAppend( this[i], "tbody" ) : | |
this[i], | |
i === iNoClone ? | |
fragment : | |
jQuery.clone( fragment, true, true ) | |
); | |
} | |
} | |
// Fix #11809: Avoid leaking memory | |
fragment = first = null; | |
if ( scripts.length ) { | |
jQuery.each( scripts, function( i, elem ) { | |
if ( elem.src ) { | |
if ( jQuery.ajax ) { | |
jQuery.ajax({ | |
url: elem.src, | |
type: "GET", | |
dataType: "script", | |
async: false, | |
global: false, | |
"throws": true | |
}); | |
} else { | |
jQuery.error("no ajax"); | |
} | |
} else { | |
jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "" ) ); | |
} | |
if ( elem.parentNode ) { | |
elem.parentNode.removeChild( elem ); | |
} | |
}); | |
} | |
} | |
return this; | |
} | |
}); | |
function findOrAppend( elem, tag ) { | |
return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) ); | |
} | |
function cloneCopyEvent( src, dest ) { | |
if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { | |
return; | |
} | |
var type, i, l, | |
oldData = jQuery._data( src ), | |
curData = jQuery._data( dest, oldData ), | |
events = oldData.events; | |
if ( events ) { | |
delete curData.handle; | |
curData.events = {}; | |
for ( type in events ) { | |
for ( i = 0, l = events[ type ].length; i < l; i++ ) { | |
jQuery.event.add( dest, type, events[ type ][ i ] ); | |
} | |
} | |
} | |
// make the cloned public data object a copy from the original | |
if ( curData.data ) { | |
curData.data = jQuery.extend( {}, curData.data ); | |
} | |
} | |
function cloneFixAttributes( src, dest ) { | |
var nodeName; | |
// We do not need to do anything for non-Elements | |
if ( dest.nodeType !== 1 ) { | |
return; | |
} | |
// clearAttributes removes the attributes, which we don't want, | |
// but also removes the attachEvent events, which we *do* want | |
if ( dest.clearAttributes ) { | |
dest.clearAttributes(); | |
} | |
// mergeAttributes, in contrast, only merges back on the | |
// original attributes, not the events | |
if ( dest.mergeAttributes ) { | |
dest.mergeAttributes( src ); | |
} | |
nodeName = dest.nodeName.toLowerCase(); | |
if ( nodeName === "object" ) { | |
// IE6-10 improperly clones children of object elements using classid. | |
// IE10 throws NoModificationAllowedError if parent is null, #12132. | |
if ( dest.parentNode ) { | |
dest.outerHTML = src.outerHTML; | |
} | |
// This path appears unavoidable for IE9. When cloning an object | |
// element in IE9, the outerHTML strategy above is not sufficient. | |
// If the src has innerHTML and the destination does not, | |
// copy the src.innerHTML into the dest.innerHTML. #10324 | |
if ( jQuery.support.html5Clone && (src.innerHTML && !jQuery.trim(dest.innerHTML)) ) { | |
dest.innerHTML = src.innerHTML; | |
} | |
} else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { | |
// IE6-8 fails to persist the checked state of a cloned checkbox | |
// or radio button. Worse, IE6-7 fail to give the cloned element | |
// a checked appearance if the defaultChecked value isn't also set | |
dest.defaultChecked = dest.checked = src.checked; | |
// IE6-7 get confused and end up setting the value of a cloned | |
// checkbox/radio button to an empty string instead of "on" | |
if ( dest.value !== src.value ) { | |
dest.value = src.value; | |
} | |
// IE6-8 fails to return the selected option to the default selected | |
// state when cloning options | |
} else if ( nodeName === "option" ) { | |
dest.selected = src.defaultSelected; | |
// IE6-8 fails to set the defaultValue to the correct value when | |
// cloning other types of input fields | |
} else if ( nodeName === "input" || nodeName === "textarea" ) { | |
dest.defaultValue = src.defaultValue; | |
// IE blanks contents when cloning scripts | |
} else if ( nodeName === "script" && dest.text !== src.text ) { | |
dest.text = src.text; | |
} | |
// Event data gets referenced instead of copied if the expando | |
// gets copied too | |
dest.removeAttribute( jQuery.expando ); | |
} | |
jQuery.buildFragment = function( args, context, scripts ) { | |
var fragment, cacheable, cachehit, | |
first = args[ 0 ]; | |
// Set context from what may come in as undefined or a jQuery collection or a node | |
context = context || document; | |
context = (context[0] || context).ownerDocument || context[0] || context; | |
// Ensure that an attr object doesn't incorrectly stand in as a document object | |
// Chrome and Firefox seem to allow this to occur and will throw exception | |
// Fixes #8950 | |
if ( typeof context.createDocumentFragment === "undefined" ) { | |
context = document; | |
} | |
// Only cache "small" (1/2 KB) HTML strings that are associated with the main document | |
// Cloning options loses the selected state, so don't cache them | |
// IE 6 doesn't like it when you put <object> or <embed> elements in a fragment | |
// Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache | |
// Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501 | |
if ( args.length === 1 && typeof first === "string" && first.length < 512 && context === document && | |
first.charAt(0) === "<" && !rnocache.test( first ) && | |
(jQuery.support.checkClone || !rchecked.test( first )) && | |
(jQuery.support.html5Clone || !rnoshimcache.test( first )) ) { | |
// Mark cacheable and look for a hit | |
cacheable = true; | |
fragment = jQuery.fragments[ first ]; | |
cachehit = fragment !== undefined; | |
} | |
if ( !fragment ) { | |
fragment = context.createDocumentFragment(); | |
jQuery.clean( args, context, fragment, scripts ); | |
// Update the cache, but only store false | |
// unless this is a second parsing of the same content | |
if ( cacheable ) { | |
jQuery.fragments[ first ] = cachehit && fragment; | |
} | |
} | |
return { fragment: fragment, cacheable: cacheable }; | |
}; | |
jQuery.fragments = {}; | |
jQuery.each({ | |
appendTo: "append", | |
prependTo: "prepend", | |
insertBefore: "before", | |
insertAfter: "after", | |
replaceAll: "replaceWith" | |
}, function( name, original ) { | |
jQuery.fn[ name ] = function( selector ) { | |
var elems, | |
i = 0, | |
ret = [], | |
insert = jQuery( selector ), | |
l = insert.length, | |
parent = this.length === 1 && this[0].parentNode; | |
if ( (parent == null || parent && parent.nodeType === 11 && parent.childNodes.length === 1) && l === 1 ) { | |
insert[ original ]( this[0] ); | |
return this; | |
} else { | |
for ( ; i < l; i++ ) { | |
elems = ( i > 0 ? this.clone(true) : this ).get(); | |
jQuery( insert[i] )[ original ]( elems ); | |
ret = ret.concat( elems ); | |
} | |
return this.pushStack( ret, name, insert.selector ); | |
} | |
}; | |
}); | |
function getAll( elem ) { | |
if ( typeof elem.getElementsByTagName !== "undefined" ) { | |
return elem.getElementsByTagName( "*" ); | |
} else if ( typeof elem.querySelectorAll !== "undefined" ) { | |
return elem.querySelectorAll( "*" ); | |
} else { | |
return []; | |
} | |
} | |
// Used in clean, fixes the defaultChecked property | |
function fixDefaultChecked( elem ) { | |
if ( rcheckableType.test( elem.type ) ) { | |
elem.defaultChecked = elem.checked; | |
} | |
} | |
jQuery.extend({ | |
clone: function( elem, dataAndEvents, deepDataAndEvents ) { | |
var srcElements, | |
destElements, | |
i, | |
clone; | |
if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { | |
clone = elem.cloneNode( true ); | |
// IE<=8 does not properly clone detached, unknown element nodes | |
} else { | |
fragmentDiv.innerHTML = elem.outerHTML; | |
fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); | |
} | |
if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && | |
(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { | |
// IE copies events bound via attachEvent when using cloneNode. | |
// Calling detachEvent on the clone will also remove the events | |
// from the original. In order to get around this, we use some | |
// proprietary methods to clear the events. Thanks to MooTools | |
// guys for this hotness. | |
cloneFixAttributes( elem, clone ); | |
// Using Sizzle here is crazy slow, so we use getElementsByTagName instead | |
srcElements = getAll( elem ); | |
destElements = getAll( clone ); | |
// Weird iteration because IE will replace the length property | |
// with an element if you are cloning the body and one of the | |
// elements on the page has a name or id of "length" | |
for ( i = 0; srcElements[i]; ++i ) { | |
// Ensure that the destination node is not null; Fixes #9587 | |
if ( destElements[i] ) { | |
cloneFixAttributes( srcElements[i], destElements[i] ); | |
} | |
} | |
} | |
// Copy the events from the original to the clone | |
if ( dataAndEvents ) { | |
cloneCopyEvent( elem, clone ); | |
if ( deepDataAndEvents ) { | |
srcElements = getAll( elem ); | |
destElements = getAll( clone ); | |
for ( i = 0; srcElements[i]; ++i ) { | |
cloneCopyEvent( srcElements[i], destElements[i] ); | |
} | |
} | |
} | |
srcElements = destElements = null; | |
// Return the cloned set | |
return clone; | |
}, | |
clean: function( elems, context, fragment, scripts ) { | |
var j, safe, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags, | |
i = 0, | |
ret = []; | |
// Ensure that context is a document | |
if ( !context || typeof context.createDocumentFragment === "undefined" ) { | |
context = document; | |
} | |
// Use the already-created safe fragment if context permits | |
for ( safe = context === document && safeFragment; (elem = elems[i]) != null; i++ ) { | |
if ( typeof elem === "number" ) { | |
elem += ""; | |
} | |
if ( !elem ) { | |
continue; | |
} | |
// Convert html string into DOM nodes | |
if ( typeof elem === "string" ) { | |
if ( !rhtml.test( elem ) ) { | |
elem = context.createTextNode( elem ); | |
} else { | |
// Ensure a safe container in which to render the html | |
safe = safe || createSafeFragment( context ); | |
div = div || safe.appendChild( context.createElement("div") ); | |
// Fix "XHTML"-style tags in all browsers | |
elem = elem.replace(rxhtmlTag, "<$1></$2>"); | |
// Go to html and back, then peel off extra wrappers | |
tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); | |
wrap = wrapMap[ tag ] || wrapMap._default; | |
depth = wrap[0]; | |
div.innerHTML = wrap[1] + elem + wrap[2]; | |
// Move to the right depth | |
while ( depth-- ) { | |
div = div.lastChild; | |
} | |
// Remove IE's autoinserted <tbody> from table fragments | |
if ( !jQuery.support.tbody ) { | |
// String was a <table>, *may* have spurious <tbody> | |
hasBody = rtbody.test(elem); | |
tbody = tag === "table" && !hasBody ? | |
div.firstChild && div.firstChild.childNodes : | |
// String was a bare <thead> or <tfoot> | |
wrap[1] === "<table>" && !hasBody ? | |
div.childNodes : | |
[]; | |
for ( j = tbody.length - 1; j >= 0 ; --j ) { | |
if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { | |
tbody[ j ].parentNode.removeChild( tbody[ j ] ); | |
} | |
} | |
} | |
// IE completely kills leading whitespace when innerHTML is used | |
if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { | |
div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); | |
} | |
elem = div.childNodes; | |
// Remember the top-level container for proper cleanup | |
div = safe.lastChild; | |
} | |
} | |
if ( elem.nodeType ) { | |
ret.push( elem ); | |
} else { | |
ret = jQuery.merge( ret, elem ); | |
} | |
} | |
// Fix #11356: Clear elements from safeFragment | |
if ( div ) { | |
safe.removeChild( div ); | |
elem = div = safe = null; | |
} | |
// Reset defaultChecked for any radios and checkboxes | |
// about to be appended to the DOM in IE 6/7 (#8060) | |
if ( !jQuery.support.appendChecked ) { | |
for ( i = 0; (elem = ret[i]) != null; i++ ) { | |
if ( jQuery.nodeName( elem, "input" ) ) { | |
fixDefaultChecked( elem ); | |
} else if ( typeof elem.getElementsByTagName !== "undefined" ) { | |
jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked ); | |
} | |
} | |
} | |
// Append elements to a provided document fragment | |
if ( fragment ) { | |
// Special handling of each script element | |
handleScript = function( elem ) { | |
// Check if we consider it executable | |
if ( !elem.type || rscriptType.test( elem.type ) ) { | |
// Detach the script and store it in the scripts array (if provided) or the fragment | |
// Return truthy to indicate that it has been handled | |
return scripts ? | |
scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) : | |
fragment.appendChild( elem ); | |
} | |
}; | |
for ( i = 0; (elem = ret[i]) != null; i++ ) { | |
// Check if we're done after handling an executable script | |
if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) { | |
// Append to fragment and handle embedded scripts | |
fragment.appendChild( elem ); | |
if ( typeof elem.getElementsByTagName !== "undefined" ) { | |
// handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration | |
jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript ); | |
// Splice the scripts into ret after their former ancestor and advance our index beyond them | |
ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); | |
i += jsTags.length; | |
} | |
} | |
} | |
} | |
return ret; | |
}, | |
cleanData: function( elems, /* internal */ acceptData ) { | |
var data, id, elem, type, | |
i = 0, | |
internalKey = jQuery.expando, | |
cache = jQuery.cache, | |
deleteExpando = jQuery.support.deleteExpando, | |
special = jQuery.event.special; | |
for ( ; (elem = elems[i]) != null; i++ ) { | |
if ( acceptData || jQuery.acceptData( elem ) ) { | |
id = elem[ internalKey ]; | |
data = id && cache[ id ]; | |
if ( data ) { | |
if ( data.events ) { | |
for ( type in data.events ) { | |
if ( special[ type ] ) { | |
jQuery.event.remove( elem, type ); | |
// This is a shortcut to avoid jQuery.event.remove's overhead | |
} else { | |
jQuery.removeEvent( elem, type, data.handle ); | |
} | |
} | |
} | |
// Remove cache only if it was not already removed by jQuery.event.remove | |
if ( cache[ id ] ) { | |
delete cache[ id ]; | |
// IE does not allow us to delete expando properties from nodes, | |
// nor does it have a removeAttribute function on Document nodes; | |
// we must handle all of these cases | |
if ( deleteExpando ) { | |
delete elem[ internalKey ]; | |
} else if ( elem.removeAttribute ) { | |
elem.removeAttribute( internalKey ); | |
} else { | |
elem[ internalKey ] = null; | |
} | |
jQuery.deletedIds.push( id ); | |
} | |
} | |
} | |
} | |
} | |
}); | |
// Limit scope pollution from any deprecated API | |
(function() { | |
var matched, browser; | |
// Use of jQuery.browser is frowned upon. | |
// More details: http://api.jquery.com/jQuery.browser | |
// jQuery.uaMatch maintained for back-compat | |
jQuery.uaMatch = function( ua ) { | |
ua = ua.toLowerCase(); | |
var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) || | |
/(webkit)[ \/]([\w.]+)/.exec( ua ) || | |
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) || | |
/(msie) ([\w.]+)/.exec( ua ) || | |
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || | |
[]; | |
return { | |
browser: match[ 1 ] || "", | |
version: match[ 2 ] || "0" | |
}; | |
}; | |
matched = jQuery.uaMatch( navigator.userAgent ); | |
browser = {}; | |
if ( matched.browser ) { | |
browser[ matched.browser ] = true; | |
browser.version = matched.version; | |
} | |
// Deprecated, use jQuery.browser.webkit instead | |
// Maintained for back-compat only | |
if ( browser.webkit ) { | |
browser.safari = true; | |
} | |
jQuery.browser = browser; | |
jQuery.sub = function() { | |
function jQuerySub( selector, context ) { | |
return new jQuerySub.fn.init( selector, context ); | |
} | |
jQuery.extend( true, jQuerySub, this ); | |
jQuerySub.superclass = this; | |
jQuerySub.fn = jQuerySub.prototype = this(); | |
jQuerySub.fn.constructor = jQuerySub; | |
jQuerySub.sub = this.sub; | |
jQuerySub.fn.init = function init( selector, context ) { | |
if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { | |
context = jQuerySub( context ); | |
} | |
return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); | |
}; | |
jQuerySub.fn.init.prototype = jQuerySub.fn; | |
var rootjQuerySub = jQuerySub(document); | |
return jQuerySub; | |
}; | |
})(); | |
var curCSS, iframe, iframeDoc, | |
ralpha = /alpha\([^)]*\)/i, | |
ropacity = /opacity=([^)]*)/, | |
rposition = /^(top|right|bottom|left)$/, | |
rmargin = /^margin/, | |
rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), | |
rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), | |
rrelNum = new RegExp( "^([-+])=(" + core_pnum + ")", "i" ), | |
elemdisplay = {}, | |
cssShow = { position: "absolute", visibility: "hidden", display: "block" }, | |
cssNormalTransform = { | |
letterSpacing: 0, | |
fontWeight: 400, | |
lineHeight: 1 | |
}, | |
cssExpand = [ "Top", "Right", "Bottom", "Left" ], | |
cssPrefixes = [ "Webkit", "O", "Moz", "ms" ], | |
eventsToggle = jQuery.fn.toggle; | |
// return a css property mapped to a potentially vendor prefixed property | |
function vendorPropName( style, name ) { | |
// shortcut for names that are not vendor prefixed | |
if ( name in style ) { | |
return name; | |
} | |
// check for vendor prefixed names | |
var capName = name.charAt(0).toUpperCase() + name.slice(1), | |
origName = name, | |
i = cssPrefixes.length; | |
while ( i-- ) { | |
name = cssPrefixes[ i ] + capName; | |
if ( name in style ) { | |
return name; | |
} | |
} | |
return origName; | |
} | |
function isHidden( elem, el ) { | |
elem = el || elem; | |
return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); | |
} | |
function showHide( elements, show ) { | |
var elem, display, | |
values = [], | |
index = 0, | |
length = elements.length; | |
for ( ; index < length; index++ ) { | |
elem = elements[ index ]; | |
if ( !elem.style ) { | |
continue; | |
} | |
values[ index ] = jQuery._data( elem, "olddisplay" ); | |
if ( show ) { | |
// Reset the inline display of this element to learn if it is | |
// being hidden by cascaded rules or not | |
if ( !values[ index ] && elem.style.display === "none" ) { | |
elem.style.display = ""; | |
} | |
// Set elements which have been overridden with display: none | |
// in a stylesheet to whatever the default browser style is | |
// for such an element | |
if ( elem.style.display === "" && isHidden( elem ) ) { | |
values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); | |
} | |
} else { | |
display = curCSS( elem, "display" ); | |
if ( !values[ index ] && display !== "none" ) { | |
jQuery._data( elem, "olddisplay", display ); | |
} | |
} | |
} | |
// Set the display of most of the elements in a second loop | |
// to avoid the constant reflow | |
for ( index = 0; index < length; index++ ) { | |
elem = elements[ index ]; | |
if ( !elem.style ) { | |
continue; | |
} | |
if ( !show || elem.style.display === "none" || elem.style.display === "" ) { | |
elem.style.display = show ? values[ index ] || "" : "none"; | |
} | |
} | |
return elements; | |
} | |
jQuery.fn.extend({ | |
css: function( name, value ) { | |
return jQuery.access( this, function( elem, name, value ) { | |
return value !== undefined ? | |
jQuery.style( elem, name, value ) : | |
jQuery.css( elem, name ); | |
}, name, value, arguments.length > 1 ); | |
}, | |
show: function() { | |
return showHide( this, true ); | |
}, | |
hide: function() { | |
return showHide( this ); | |
}, | |
toggle: function( state, fn2 ) { | |
var bool = typeof state === "boolean"; | |
if ( jQuery.isFunction( state ) && jQuery.isFunction( fn2 ) ) { | |
return eventsToggle.apply( this, arguments ); | |
} | |
return this.each(function() { | |
if ( bool ? state : isHidden( this ) ) { | |
jQuery( this ).show(); | |
} else { | |
jQuery( this ).hide(); | |
} | |
}); | |
} | |
}); | |
jQuery.extend({ | |
// Add in style property hooks for overriding the default | |
// behavior of getting and setting a style property | |
cssHooks: { | |
opacity: { | |
get: function( elem, computed ) { | |
if ( computed ) { | |
// We should always get a number back from opacity | |
var ret = curCSS( elem, "opacity" ); | |
return ret === "" ? "1" : ret; | |
} | |
} | |
} | |
}, | |
// Exclude the following css properties to add px | |
cssNumber: { | |
"fillOpacity": true, | |
"fontWeight": true, | |
"lineHeight": true, | |
"opacity": true, | |
"orphans": true, | |
"widows": true, | |
"zIndex": true, | |
"zoom": true | |
}, | |
// Add in properties whose names you wish to fix before | |
// setting or getting the value | |
cssProps: { | |
// normalize float css property | |
"float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" | |
}, | |
// Get and set the style property on a DOM Node | |
style: function( elem, name, value, extra ) { | |
// Don't set styles on text and comment nodes | |
if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { | |
return; | |
} | |
// Make sure that we're working with the right name | |
var ret, type, hooks, | |
origName = jQuery.camelCase( name ), | |
style = elem.style; | |
name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); | |
// gets hook for the prefixed version | |
// followed by the unprefixed version | |
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; | |
// Check if we're setting a value | |
if ( value !== undefined ) { | |
type = typeof value; | |
// convert relative number strings (+= or -=) to relative numbers. #7345 | |
if ( type === "string" && (ret = rrelNum.exec( value )) ) { | |
value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); | |
// Fixes bug #9237 | |
type = "number"; | |
} | |
// Make sure that NaN and null values aren't set. See: #7116 | |
if ( value == null || type === "number" && isNaN( value ) ) { | |
return; | |
} | |
// If a number was passed in, add 'px' to the (except for certain CSS properties) | |
if ( type === "number" && !jQuery.cssNumber[ origName ] ) { | |
value += "px"; | |
} | |
// If a hook was provided, use that value, otherwise just set the specified value | |
if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { | |
// Wrapped to prevent IE from throwing errors when 'invalid' values are provided | |
// Fixes bug #5509 | |
try { | |
style[ name ] = value; | |
} catch(e) {} | |
} | |
} else { | |
// If a hook was provided get the non-computed value from there | |
if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { | |
return ret; | |
} | |
// Otherwise just get the value from the style object | |
return style[ name ]; | |
} | |
}, | |
css: function( elem, name, numeric, extra ) { | |
var val, num, hooks, | |
origName = jQuery.camelCase( name ); | |
// Make sure that we're working with the right name | |
name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); | |
// gets hook for the prefixed version | |
// followed by the unprefixed version | |
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; | |
// If a hook was provided get the computed value from there | |
if ( hooks && "get" in hooks ) { | |
val = hooks.get( elem, true, extra ); | |
} | |
// Otherwise, if a way to get the computed value exists, use that | |
if ( val === undefined ) { | |
val = curCSS( elem, name ); | |
} | |
//convert "normal" to computed value | |
if ( val === "normal" && name in cssNormalTransform ) { | |
val = cssNormalTransform[ name ]; | |
} | |
// Return, converting to number if forced or a qualifier was provided and val looks numeric | |
if ( numeric || extra !== undefined ) { | |
num = parseFloat( val ); | |
return numeric || jQuery.isNumeric( num ) ? num || 0 : val; | |
} | |
return val; | |
}, | |
// A method for quickly swapping in/out CSS properties to get correct calculations | |
swap: function( elem, options, callback ) { | |
var ret, name, | |
old = {}; | |
// Remember the old values, and insert the new ones | |
for ( name in options ) { | |
old[ name ] = elem.style[ name ]; | |
elem.style[ name ] = options[ name ]; | |
} | |
ret = callback.call( elem ); | |
// Revert the old values | |
for ( name in options ) { | |
elem.style[ name ] = old[ name ]; | |
} | |
return ret; | |
} | |
}); | |
// NOTE: To any future maintainer, we've used both window.getComputedStyle | |
// and getComputedStyle here to produce a better gzip size | |
if ( window.getComputedStyle ) { | |
curCSS = function( elem, name ) { | |
var ret, width, minWidth, maxWidth, | |
computed = getComputedStyle( elem, null ), | |
style = elem.style; | |
if ( computed ) { | |
ret = computed[ name ]; | |
if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) { | |
ret = jQuery.style( elem, name ); | |
} | |
// A tribute to the "awesome hack by Dean Edwards" | |
// Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right | |
// Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels | |
// this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values | |
if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { | |
width = style.width; | |
minWidth = style.minWidth; | |
maxWidth = style.maxWidth; | |
style.minWidth = style.maxWidth = style.width = ret; | |
ret = computed.width; | |
style.width = width; | |
style.minWidth = minWidth; | |
style.maxWidth = maxWidth; | |
} | |
} | |
return ret; | |
}; | |
} else if ( document.documentElement.currentStyle ) { | |
curCSS = function( elem, name ) { | |
var left, rsLeft, | |
ret = elem.currentStyle && elem.currentStyle[ name ], | |
style = elem.style; | |
// Avoid setting ret to empty string here | |
// so we don't default to auto | |
if ( ret == null && style && style[ name ] ) { | |
ret = style[ name ]; | |
} | |
// From the awesome hack by Dean Edwards | |
// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 | |
// If we're not dealing with a regular pixel number | |
// but a number that has a weird ending, we need to convert it to pixels | |
// but not position css attributes, as those are proportional to the parent element instead | |
// and we can't measure the parent instead because it might trigger a "stacking dolls" problem | |
if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { | |
// Remember the original values | |
left = style.left; | |
rsLeft = elem.runtimeStyle && elem.runtimeStyle.left; | |
// Put in the new values to get a computed value out | |
if ( rsLeft ) { | |
elem.runtimeStyle.left = elem.currentStyle.left; | |
} | |
style.left = name === "fontSize" ? "1em" : ret; | |
ret = style.pixelLeft + "px"; | |
// Revert the changed values | |
style.left = left; | |
if ( rsLeft ) { | |
elem.runtimeStyle.left = rsLeft; | |
} | |
} | |
return ret === "" ? "auto" : ret; | |
}; | |
} | |
function setPositiveNumber( elem, value, subtract ) { | |
var matches = rnumsplit.exec( value ); | |
return matches ? | |
Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : | |
value; | |
} | |
function augmentWidthOrHeight( elem, name, extra, isBorderBox ) { | |
var i = extra === ( isBorderBox ? "border" : "content" ) ? | |
// If we already have the right measurement, avoid augmentation | |
4 : | |
// Otherwise initialize for horizontal or vertical properties | |
name === "width" ? 1 : 0, | |
val = 0; | |
for ( ; i < 4; i += 2 ) { | |
// both box models exclude margin, so add it if we want it | |
if ( extra === "margin" ) { | |
// we use jQuery.css instead of curCSS here | |
// because of the reliableMarginRight CSS hook! | |
val += jQuery.css( elem, extra + cssExpand[ i ], true ); | |
} | |
// From this point on we use curCSS for maximum performance (relevant in animations) | |
if ( isBorderBox ) { | |
// border-box includes padding, so remove it if we want content | |
if ( extra === "content" ) { | |
val -= parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; | |
} | |
// at this point, extra isn't border nor margin, so remove border | |
if ( extra !== "margin" ) { | |
val -= parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; | |
} | |
} else { | |
// at this point, extra isn't content, so add padding | |
val += parseFloat( curCSS( elem, "padding" + cssExpand[ i ] ) ) || 0; | |
// at this point, extra isn't content nor padding, so add border | |
if ( extra !== "padding" ) { | |
val += parseFloat( curCSS( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; | |
} | |
} | |
} | |
return val; | |
} | |
function getWidthOrHeight( elem, name, extra ) { | |
// Start with offset property, which is equivalent to the border-box value | |
var val = name === "width" ? elem.offsetWidth : elem.offsetHeight, | |
valueIsBorderBox = true, | |
isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box"; | |
if ( val <= 0 ) { | |
// Fall back to computed then uncomputed css if necessary | |
val = curCSS( elem, name ); | |
if ( val < 0 || val == null ) { | |
val = elem.style[ name ]; | |
} | |
// Computed unit is not pixels. Stop here and return. | |
if ( rnumnonpx.test(val) ) { | |
return val; | |
} | |
// we need the check for style in case a browser which returns unreliable values | |
// for getComputedStyle silently falls back to the reliable elem.style | |
valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); | |
// Normalize "", auto, and prepare for extra | |
val = parseFloat( val ) || 0; | |
} | |
// use the active box-sizing model to add/subtract irrelevant styles | |
return ( val + | |
augmentWidthOrHeight( | |
elem, | |
name, | |
extra || ( isBorderBox ? "border" : "content" ), | |
valueIsBorderBox | |
) | |
) + "px"; | |
} | |
// Try to determine the default display value of an element | |
function css_defaultDisplay( nodeName ) { | |
if ( elemdisplay[ nodeName ] ) { | |
return elemdisplay[ nodeName ]; | |
} | |
var elem = jQuery( "<" + nodeName + ">" ).appendTo( document.body ), | |
display = elem.css("display"); | |
elem.remove(); | |
// If the simple way fails, | |
// get element's real default display by attaching it to a temp iframe | |
if ( display === "none" || display === "" ) { | |
// Use the already-created iframe if possible | |
iframe = document.body.appendChild( | |
iframe || jQuery.extend( document.createElement("iframe"), { | |
frameBorder: 0, | |
width: 0, | |
height: 0 | |
}) | |
); | |
// Create a cacheable copy of the iframe document on first call. | |
// IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML | |
// document to it; WebKit & Firefox won't allow reusing the iframe document. | |
if ( !iframeDoc || !iframe.createElement ) { | |
iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; | |
iframeDoc.write("<!doctype html><html><body>"); | |
iframeDoc.close(); | |
} | |
elem = iframeDoc.body.appendChild( iframeDoc.createElement(nodeName) ); | |
display = curCSS( elem, "display" ); | |
document.body.removeChild( iframe ); | |
} | |
// Store the correct default display | |
elemdisplay[ nodeName ] = display; | |
return display; | |
} | |
jQuery.each([ "height", "width" ], function( i, name ) { | |
jQuery.cssHooks[ name ] = { | |
get: function( elem, computed, extra ) { | |
if ( computed ) { | |
if ( elem.offsetWidth !== 0 || curCSS( elem, "display" ) !== "none" ) { | |
return getWidthOrHeight( elem, name, extra ); | |
} else { | |
return jQuery.swap( elem, cssShow, function() { | |
return getWidthOrHeight( elem, name, extra ); | |
}); | |
} | |
} | |
}, | |
set: function( elem, value, extra ) { | |
return setPositiveNumber( elem, value, extra ? | |
augmentWidthOrHeight( | |
elem, | |
name, | |
extra, | |
jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box" | |
) : 0 | |
); | |
} | |
}; | |
}); | |
if ( !jQuery.support.opacity ) { | |
jQuery.cssHooks.opacity = { | |
get: function( elem, computed ) { | |
// IE uses filters for opacity | |
return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? | |
( 0.01 * parseFloat( RegExp.$1 ) ) + "" : | |
computed ? "1" : ""; | |
}, | |
set: function( elem, value ) { | |
var style = elem.style, | |
currentStyle = elem.currentStyle, | |
opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "", | |
filter = currentStyle && currentStyle.filter || style.filter || ""; | |
// IE has trouble with opacity if it does not have layout | |
// Force it by setting the zoom level | |
style.zoom = 1; | |
// if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652 | |
if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" && | |
style.removeAttribute ) { | |
// Setting style.filter to null, "" & " " still leave "filter:" in the cssText | |
// if "filter:" is present at all, clearType is disabled, we want to avoid this | |
// style.removeAttribute is IE Only, but so apparently is this code path... | |
style.removeAttribute( "filter" ); | |
// if there there is no filter style applied in a css rule, we are done | |
if ( currentStyle && !currentStyle.filter ) { | |
return; | |
} | |
} | |
// otherwise, set new filter values | |
style.filter = ralpha.test( filter ) ? | |
filter.replace( ralpha, opacity ) : | |
filter + " " + opacity; | |
} | |
}; | |
} | |
// These hooks cannot be added until DOM ready because the support test | |
// for it is not run until after DOM ready | |
jQuery(function() { | |
if ( !jQuery.support.reliableMarginRight ) { | |
jQuery.cssHooks.marginRight = { | |
get: function( elem, computed ) { | |
// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right | |
// Work around by temporarily setting element display to inline-block | |
return jQuery.swap( elem, { "display": "inline-block" }, function() { | |
if ( computed ) { | |
return curCSS( elem, "marginRight" ); | |
} | |
}); | |
} | |
}; | |
} | |
// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 | |
// getComputedStyle returns percent when specified for top/left/bottom/right | |
// rather than make the css module depend on the offset module, we just check for it here | |
if ( !jQuery.support.pixelPosition && jQuery.fn.position ) { | |
jQuery.each( [ "top", "left" ], function( i, prop ) { | |
jQuery.cssHooks[ prop ] = { | |
get: function( elem, computed ) { | |
if ( computed ) { | |
var ret = curCSS( elem, prop ); | |
// if curCSS returns percentage, fallback to offset | |
return rnumnonpx.test( ret ) ? jQuery( elem ).position()[ prop ] + "px" : ret; | |
} | |
} | |
}; | |
}); | |
} | |
}); | |
if ( jQuery.expr && jQuery.expr.filters ) { | |
jQuery.expr.filters.hidden = function( elem ) { | |
return ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || curCSS( elem, "display" )) === "none"); | |
}; | |
jQuery.expr.filters.visible = function( elem ) { | |
return !jQuery.expr.filters.hidden( elem ); | |
}; | |
} | |
// These hooks are used by animate to expand properties | |
jQuery.each({ | |
margin: "", | |
padding: "", | |
border: "Width" | |
}, function( prefix, suffix ) { | |
jQuery.cssHooks[ prefix + suffix ] = { | |
expand: function( value ) { | |
var i, | |
// assumes a single number if not a string | |
parts = typeof value === "string" ? value.split(" ") : [ value ], | |
expanded = {}; | |
for ( i = 0; i < 4; i++ ) { | |
expanded[ prefix + cssExpand[ i ] + suffix ] = | |
parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; | |
} | |
return expanded; | |
} | |
}; | |
if ( !rmargin.test( prefix ) ) { | |
jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; | |
} | |
}); | |
var r20 = /%20/g, | |
rbracket = /\[\]$/, | |
rCRLF = /\r?\n/g, | |
rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, | |
rselectTextarea = /^(?:select|textarea)/i; | |
jQuery.fn.extend({ | |
serialize: function() { | |
return jQuery.param( this.serializeArray() ); | |
}, | |
serializeArray: function() { | |
return this.map(function(){ | |
return this.elements ? jQuery.makeArray( this.elements ) : this; | |
}) | |
.filter(function(){ | |
return this.name && !this.disabled && | |
( this.checked || rselectTextarea.test( this.nodeName ) || | |
rinput.test( this.type ) ); | |
}) | |
.map(function( i, elem ){ | |
var val = jQuery( this ).val(); | |
return val == null ? | |
null : | |
jQuery.isArray( val ) ? | |
jQuery.map( val, function( val, i ){ | |
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; | |
}) : | |
{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; | |
}).get(); | |
} | |
}); | |
//Serialize an array of form elements or a set of | |
//key/values into a query string | |
jQuery.param = function( a, traditional ) { | |
var prefix, | |
s = [], | |
add = function( key, value ) { | |
// If value is a function, invoke it and return its value | |
value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); | |
s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); | |
}; | |
// Set traditional to true for jQuery <= 1.3.2 behavior. | |
if ( traditional === undefined ) { | |
traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; | |
} | |
// If an array was passed in, assume that it is an array of form elements. | |
if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { | |
// Serialize the form elements | |
jQuery.each( a, function() { | |
add( this.name, this.value ); | |
}); | |
} else { | |
// If traditional, encode the "old" way (the way 1.3.2 or older | |
// did it), otherwise encode params recursively. | |
for ( prefix in a ) { | |
buildParams( prefix, a[ prefix ], traditional, add ); | |
} | |
} | |
// Return the resulting serialization | |
return s.join( "&" ).replace( r20, "+" ); | |
}; | |
function buildParams( prefix, obj, traditional, add ) { | |
var name; | |
if ( jQuery.isArray( obj ) ) { | |
// Serialize array item. | |
jQuery.each( obj, function( i, v ) { | |
if ( traditional || rbracket.test( prefix ) ) { | |
// Treat each array item as a scalar. | |
add( prefix, v ); | |
} else { | |
// If array item is non-scalar (array or object), encode its | |
// numeric index to resolve deserialization ambiguity issues. | |
// Note that rack (as of 1.0.0) can't currently deserialize | |
// nested arrays properly, and attempting to do so may cause | |
// a server error. Possible fixes are to modify rack's | |
// deserialization algorithm or to provide an option or flag | |
// to force array serialization to be shallow. | |
buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); | |
} | |
}); | |
} else if ( !traditional && jQuery.type( obj ) === "object" ) { | |
// Serialize object item. | |
for ( name in obj ) { | |
buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); | |
} | |
} else { | |
// Serialize scalar item. | |
add( prefix, obj ); | |
} | |
} | |
var // Document location | |
ajaxLocation, | |
// Document location segments | |
ajaxLocParts, | |
rhash = /#.*$/, | |
rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL | |
// #7653, #8125, #8152: local protocol detection | |
rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/, | |
rnoContent = /^(?:GET|HEAD)$/, | |
rprotocol = /^\/\//, | |
rquery = /\?/, | |
rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, | |
rts = /([?&])_=[^&]*/, | |
rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/, | |
// Keep a copy of the old load method | |
_load = jQuery.fn.load, | |
/* Prefilters | |
* 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) | |
* 2) These are called: | |
* - BEFORE asking for a transport | |
* - AFTER param serialization (s.data is a string if s.processData is true) | |
* 3) key is the dataType | |
* 4) the catchall symbol "*" can be used | |
* 5) execution will start with transport dataType and THEN continue down to "*" if needed | |
*/ | |
prefilters = {}, | |
/* Transports bindings | |
* 1) key is the dataType | |
* 2) the catchall symbol "*" can be used | |
* 3) selection will start with transport dataType and THEN go to "*" if needed | |
*/ | |
transports = {}, | |
// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression | |
allTypes = ["*/"] + ["*"]; | |
// #8138, IE may throw an exception when accessing | |
// a field from window.location if document.domain has been set | |
try { | |
ajaxLocation = location.href; | |
} catch( e ) { | |
// Use the href attribute of an A element | |
// since IE will modify it given document.location | |
ajaxLocation = document.createElement( "a" ); | |
ajaxLocation.href = ""; | |
ajaxLocation = ajaxLocation.href; | |
} | |
// Segment location into parts | |
ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; | |
// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport | |
function addToPrefiltersOrTransports( structure ) { | |
// dataTypeExpression is optional and defaults to "*" | |
return function( dataTypeExpression, func ) { | |
if ( typeof dataTypeExpression !== "string" ) { | |
func = dataTypeExpression; | |
dataTypeExpression = "*"; | |
} | |
var dataType, list, placeBefore, | |
dataTypes = dataTypeExpression.toLowerCase().split( core_rspace ), | |
i = 0, | |
length = dataTypes.length; | |
if ( jQuery.isFunction( func ) ) { | |
// For each dataType in the dataTypeExpression | |
for ( ; i < length; i++ ) { | |
dataType = dataTypes[ i ]; | |
// We control if we're asked to add before | |
// any existing element | |
placeBefore = /^\+/.test( dataType ); | |
if ( placeBefore ) { | |
dataType = dataType.substr( 1 ) || "*"; | |
} | |
list = structure[ dataType ] = structure[ dataType ] || []; | |
// then we add to the structure accordingly | |
list[ placeBefore ? "unshift" : "push" ]( func ); | |
} | |
} | |
}; | |
} | |
// Base inspection function for prefilters and transports | |
function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR, | |
dataType /* internal */, inspected /* internal */ ) { | |
dataType = dataType || options.dataTypes[ 0 ]; | |
inspected = inspected || {}; | |
inspected[ dataType ] = true; | |
var selection, | |
list = structure[ dataType ], | |
i = 0, | |
length = list ? list.length : 0, | |
executeOnly = ( structure === prefilters ); | |
for ( ; i < length && ( executeOnly || !selection ); i++ ) { | |
selection = list[ i ]( options, originalOptions, jqXHR ); | |
// If we got redirected to another dataType | |
// we try there if executing only and not done already | |
if ( typeof selection === "string" ) { | |
if ( !executeOnly || inspected[ selection ] ) { | |
selection = undefined; | |
} else { | |
options.dataTypes.unshift( selection ); | |
selection = inspectPrefiltersOrTransports( | |
structure, options, originalOptions, jqXHR, selection, inspected ); | |
} | |
} | |
} | |
// If we're only executing or nothing was selected | |
// we try the catchall dataType if not done already | |
if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) { | |
selection = inspectPrefiltersOrTransports( | |
structure, options, originalOptions, jqXHR, "*", inspected ); | |
} | |
// unnecessary when only executing (prefilters) | |
// but it'll be ignored by the caller in that case | |
return selection; | |
} | |
// A special extend for ajax options | |
// that takes "flat" options (not to be deep extended) | |
// Fixes #9887 | |
function ajaxExtend( target, src ) { | |
var key, deep, | |
flatOptions = jQuery.ajaxSettings.flatOptions || {}; | |
for ( key in src ) { | |
if ( src[ key ] !== undefined ) { | |
( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; | |
} | |
} | |
if ( deep ) { | |
jQuery.extend( true, target, deep ); | |
} | |
} | |
jQuery.fn.load = function( url, params, callback ) { | |
if ( typeof url !== "string" && _load ) { | |
return _load.apply( this, arguments ); | |
} | |
// Don't do a request if no elements are being requested | |
if ( !this.length ) { | |
return this; | |
} | |
var selector, type, response, | |
self = this, | |
off = url.indexOf(" "); | |
if ( off >= 0 ) { | |
selector = url.slice( off, url.length ); | |
url = url.slice( 0, off ); | |
} | |
// If it's a function | |
if ( jQuery.isFunction( params ) ) { | |
// We assume that it's the callback | |
callback = params; | |
params = undefined; | |
// Otherwise, build a param string | |
} else if ( typeof params === "object" ) { | |
type = "POST"; | |
} | |
// Request the remote document | |
jQuery.ajax({ | |
url: url, | |
// if "type" variable is undefined, then "GET" method will be used | |
type: type, | |
dataType: "html", | |
data: params, | |
complete: function( jqXHR, status ) { | |
if ( callback ) { | |
self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] ); | |
} | |
} | |
}).done(function( responseText ) { | |
// Save response for use in complete callback | |
response = arguments; | |
// See if a selector was specified | |
self.html( selector ? | |
// Create a dummy div to hold the results | |
jQuery("<div>") | |
// inject the contents of the document in, removing the scripts | |
// to avoid any 'Permission Denied' errors in IE | |
.append( responseText.replace( rscript, "" ) ) | |
// Locate the specified elements | |
.find( selector ) : | |
// If not, just inject the full result | |
responseText ); | |
}); | |
return this; | |
}; | |
// Attach a bunch of functions for handling common AJAX events | |
jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){ | |
jQuery.fn[ o ] = function( f ){ | |
return this.on( o, f ); | |
}; | |
}); | |
jQuery.each( [ "get", "post" ], function( i, method ) { | |
jQuery[ method ] = function( url, data, callback, type ) { | |
// shift arguments if data argument was omitted | |
if ( jQuery.isFunction( data ) ) { | |
type = type || callback; | |
callback = data; | |
data = undefined; | |
} | |
return jQuery.ajax({ | |
type: method, | |
url: url, | |
data: data, | |
success: callback, | |
dataType: type | |
}); | |
}; | |
}); | |
jQuery.extend({ | |
getScript: function( url, callback ) { | |
return jQuery.get( url, undefined, callback, "script" ); | |
}, | |
getJSON: function( url, data, callback ) { | |
return jQuery.get( url, data, callback, "json" ); | |
}, | |
// Creates a full fledged settings object into target | |
// with both ajaxSettings and settings fields. | |
// If target is omitted, writes into ajaxSettings. | |
ajaxSetup: function( target, settings ) { | |
if ( settings ) { | |
// Building a settings object | |
ajaxExtend( target, jQuery.ajaxSettings ); | |
} else { | |
// Extending ajaxSettings | |
settings = target; | |
target = jQuery.ajaxSettings; | |
} | |
ajaxExtend( target, settings ); | |
return target; | |
}, | |
ajaxSettings: { | |
url: ajaxLocation, | |
isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ), | |
global: true, | |
type: "GET", | |
contentType: "application/x-www-form-urlencoded; charset=UTF-8", | |
processData: true, | |
async: true, | |
/* | |
timeout: 0, | |
data: null, | |
dataType: null, | |
username: null, | |
password: null, | |
cache: null, | |
throws: false, | |
traditional: false, | |
headers: {}, | |
*/ | |
accepts: { | |
xml: "application/xml, text/xml", | |
html: "text/html", | |
text: "text/plain", | |
json: "application/json, text/javascript", | |
"*": allTypes | |
}, | |
contents: { | |
xml: /xml/, | |
html: /html/, | |
json: /json/ | |
}, | |
responseFields: { | |
xml: "responseXML", | |
text: "responseText" | |
}, | |
// List of data converters | |
// 1) key format is "source_type destination_type" (a single space in-between) | |
// 2) the catchall symbol "*" can be used for source_type | |
converters: { | |
// Convert anything to text | |
"* text": window.String, | |
// Text to html (true = no transformation) | |
"text html": true, | |
// Evaluate text as a json expression | |
"text json": jQuery.parseJSON, | |
View raw
(Sorry about that, but we can’t show files that are this big right now.)
View raw
(Sorry about that, but we can’t show files that are this big right now.)
View raw
(Sorry about that, but we can’t show files that are this big right now.)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment