Show:

File: src/constraint/MouseConstraint.js

                                /**
                                * The `Matter.MouseConstraint` module contains methods for creating mouse constraints.
                                * Mouse constraints are used for allowing user interaction, providing the ability to move bodies via the mouse or touch.
                                *
                                * See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
                                *
                                * @class MouseConstraint
                                */
                                
                                var MouseConstraint = {};
                                
                                module.exports = MouseConstraint;
                                
                                var Vertices = require('../geometry/Vertices');
                                var Sleeping = require('../core/Sleeping');
                                var Mouse = require('../core/Mouse');
                                var Events = require('../core/Events');
                                var Detector = require('../collision/Detector');
                                var Constraint = require('./Constraint');
                                var Composite = require('../body/Composite');
                                var Common = require('../core/Common');
                                var Bounds = require('../geometry/Bounds');
                                
                                (function() {
                                
                                    /**
                                     * Creates a new mouse constraint.
                                     * All properties have default values, and many are pre-calculated automatically based on other properties.
                                     * See the properties section below for detailed information on what you can pass via the `options` object.
                                     * @method create
                                     * @param {engine} engine
                                     * @param {} options
                                     * @return {MouseConstraint} A new MouseConstraint
                                     */
                                    MouseConstraint.create = function(engine, options) {
                                        var mouse = (engine ? engine.mouse : null) || (options ? options.mouse : null);
                                
                                        if (!mouse) {
                                            if (engine && engine.render && engine.render.canvas) {
                                                mouse = Mouse.create(engine.render.canvas);
                                            } else if (options && options.element) {
                                                mouse = Mouse.create(options.element);
                                            } else {
                                                mouse = Mouse.create();
                                                Common.warn('MouseConstraint.create: options.mouse was undefined, options.element was undefined, may not function as expected');
                                            }
                                        }
                                
                                        var constraint = Constraint.create({ 
                                            label: 'Mouse Constraint',
                                            pointA: mouse.position,
                                            pointB: { x: 0, y: 0 },
                                            length: 0.01, 
                                            stiffness: 0.1,
                                            angularStiffness: 1,
                                            render: {
                                                strokeStyle: '#90EE90',
                                                lineWidth: 3
                                            }
                                        });
                                
                                        var defaults = {
                                            type: 'mouseConstraint',
                                            mouse: mouse,
                                            element: null,
                                            body: null,
                                            constraint: constraint,
                                            collisionFilter: {
                                                category: 0x0001,
                                                mask: 0xFFFFFFFF,
                                                group: 0
                                            }
                                        };
                                
                                        var mouseConstraint = Common.extend(defaults, options);
                                
                                        Events.on(engine, 'beforeUpdate', function() {
                                            var allBodies = Composite.allBodies(engine.world);
                                            MouseConstraint.update(mouseConstraint, allBodies);
                                            MouseConstraint._triggerEvents(mouseConstraint);
                                        });
                                
                                        return mouseConstraint;
                                    };
                                
                                    /**
                                     * Updates the given mouse constraint.
                                     * @private
                                     * @method update
                                     * @param {MouseConstraint} mouseConstraint
                                     * @param {body[]} bodies
                                     */
                                    MouseConstraint.update = function(mouseConstraint, bodies) {
                                        var mouse = mouseConstraint.mouse,
                                            constraint = mouseConstraint.constraint,
                                            body = mouseConstraint.body;
                                
                                        if (mouse.button === 0) {
                                            if (!constraint.bodyB) {
                                                for (var i = 0; i < bodies.length; i++) {
                                                    body = bodies[i];
                                                    if (Bounds.contains(body.bounds, mouse.position) 
                                                            && Detector.canCollide(body.collisionFilter, mouseConstraint.collisionFilter)) {
                                                        for (var j = body.parts.length > 1 ? 1 : 0; j < body.parts.length; j++) {
                                                            var part = body.parts[j];
                                                            if (Vertices.contains(part.vertices, mouse.position)) {
                                                                constraint.pointA = mouse.position;
                                                                constraint.bodyB = mouseConstraint.body = body;
                                                                constraint.pointB = { x: mouse.position.x - body.position.x, y: mouse.position.y - body.position.y };
                                                                constraint.angleB = body.angle;
                                
                                                                Sleeping.set(body, false);
                                                                Events.trigger(mouseConstraint, 'startdrag', { mouse: mouse, body: body });
                                
                                                                break;
                                                            }
                                                        }
                                                    }
                                                }
                                            } else {
                                                Sleeping.set(constraint.bodyB, false);
                                                constraint.pointA = mouse.position;
                                            }
                                        } else {
                                            constraint.bodyB = mouseConstraint.body = null;
                                            constraint.pointB = null;
                                
                                            if (body)
                                                Events.trigger(mouseConstraint, 'enddrag', { mouse: mouse, body: body });
                                        }
                                    };
                                
                                    /**
                                     * Triggers mouse constraint events.
                                     * @method _triggerEvents
                                     * @private
                                     * @param {mouse} mouseConstraint
                                     */
                                    MouseConstraint._triggerEvents = function(mouseConstraint) {
                                        var mouse = mouseConstraint.mouse,
                                            mouseEvents = mouse.sourceEvents;
                                
                                        if (mouseEvents.mousemove)
                                            Events.trigger(mouseConstraint, 'mousemove', { mouse: mouse });
                                
                                        if (mouseEvents.mousedown)
                                            Events.trigger(mouseConstraint, 'mousedown', { mouse: mouse });
                                
                                        if (mouseEvents.mouseup)
                                            Events.trigger(mouseConstraint, 'mouseup', { mouse: mouse });
                                
                                        // reset the mouse state ready for the next step
                                        Mouse.clearSourceEvents(mouse);
                                    };
                                
                                    /*
                                    *
                                    *  Events Documentation
                                    *
                                    */
                                
                                    /**
                                    * Fired when the mouse has moved (or a touch moves) during the last step
                                    *
                                    * @event mousemove
                                    * @param {} event An event object
                                    * @param {mouse} event.mouse The engine's mouse instance
                                    * @param {} event.source The source object of the event
                                    * @param {} event.name The name of the event
                                    */
                                
                                    /**
                                    * Fired when the mouse is down (or a touch has started) during the last step
                                    *
                                    * @event mousedown
                                    * @param {} event An event object
                                    * @param {mouse} event.mouse The engine's mouse instance
                                    * @param {} event.source The source object of the event
                                    * @param {} event.name The name of the event
                                    */
                                
                                    /**
                                    * Fired when the mouse is up (or a touch has ended) during the last step
                                    *
                                    * @event mouseup
                                    * @param {} event An event object
                                    * @param {mouse} event.mouse The engine's mouse instance
                                    * @param {} event.source The source object of the event
                                    * @param {} event.name The name of the event
                                    */
                                
                                    /**
                                    * Fired when the user starts dragging a body
                                    *
                                    * @event startdrag
                                    * @param {} event An event object
                                    * @param {mouse} event.mouse The engine's mouse instance
                                    * @param {body} event.body The body being dragged
                                    * @param {} event.source The source object of the event
                                    * @param {} event.name The name of the event
                                    */
                                
                                    /**
                                    * Fired when the user ends dragging a body
                                    *
                                    * @event enddrag
                                    * @param {} event An event object
                                    * @param {mouse} event.mouse The engine's mouse instance
                                    * @param {body} event.body The body that has stopped being dragged
                                    * @param {} event.source The source object of the event
                                    * @param {} event.name The name of the event
                                    */
                                
                                    /*
                                    *
                                    *  Properties Documentation
                                    *
                                    */
                                
                                    /**
                                     * A `String` denoting the type of object.
                                     *
                                     * @property type
                                     * @type string
                                     * @default "constraint"
                                     * @readOnly
                                     */
                                
                                    /**
                                     * The `Mouse` instance in use. If not supplied in `MouseConstraint.create`, one will be created.
                                     *
                                     * @property mouse
                                     * @type mouse
                                     * @default mouse
                                     */
                                
                                    /**
                                     * The `Body` that is currently being moved by the user, or `null` if no body.
                                     *
                                     * @property body
                                     * @type body
                                     * @default null
                                     */
                                
                                    /**
                                     * The `Constraint` object that is used to move the body during interaction.
                                     *
                                     * @property constraint
                                     * @type constraint
                                     */
                                
                                    /**
                                     * An `Object` that specifies the collision filter properties.
                                     * The collision filter allows the user to define which types of body this mouse constraint can interact with.
                                     * See `body.collisionFilter` for more information.
                                     *
                                     * @property collisionFilter
                                     * @type object
                                     */
                                
                                })();