// copy from https://github.com/pixijs/pixi.js/blob/dev/src/interaction/InteractionManager.js#L1018 function myProcessInteractive(interactionEvent, displayObject, func, hitTest, interactive) { if (!displayObject || !displayObject.visible) { return false; } const point = interactionEvent.data.global; // Took a little while to rework this function correctly! But now it is done and nice and optimised. ^_^ // // This function will now loop through all objects and then only hit test the objects it HAS // to, not all of them. MUCH faster.. // An object will be hit test if the following is true: // // 1: It is interactive. // 2: It belongs to a parent that is interactive AND one of the parents children have not already been hit. // // As another little optimisation once an interactive object has been hit we can carry on // through the scenegraph, but we know that there will be no more hits! So we can avoid extra hit tests // A final optimisation is that an object is not hit test directly if a child has already been hit. interactive = displayObject.interactive || interactive; let hit = false; let interactiveParent = interactive; // if the displayobject has a hitArea, then it does not need to hitTest children. // it has a mask! Then lets hit test that before continuing if (hitTest && displayObject._mask) { if (!displayObject._mask.containsPoint(point)) { hitTest = false; } } else if (displayObject.hitArea) { interactiveParent = false; } // ** FREE TIP **! If an object is not interactive or has no buttons in it // (such as a game scene!) set interactiveChildren to false for that displayObject. // This will allow PixiJS to completely ignore and bypass checking the displayObjects children. if (displayObject.interactiveChildren && displayObject.children) { const children = displayObject.children; for (let i = children.length - 1; i >= 0; i--) { const child = children[i]; // time to get recursive.. if this function will return if something is hit.. const childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent); if (childHit) { // its a good idea to check if a child has lost its parent. // this means it has been removed whilst looping so its best if (!child.parent) { continue; } // we no longer need to hit test any more objects in this container as we we // now know the parent has been hit interactiveParent = false; // If the child is interactive , that means that the object hit was actually // interactive and not just the child of an interactive object. // This means we no longer need to hit test anything else. We still need to run // through all objects, but we don't need to perform any hit tests. if (childHit) { if (interactionEvent.target) { hitTest = false; } hit = true; } } } } // no point running this if the item is not interactive or does not have an interactive parent. if (interactive) { // if we are hit testing (as in we have no hit any objects yet) // We also don't need to worry about hit testing if once of the displayObjects children // has already been hit - but only if it was interactive, otherwise we need to keep // looking for an interactive child, just in case we hit one if (hitTest && !interactionEvent.target) { if (displayObject.hitArea) { displayObject.worldTransform.applyInverse(point, this._tempPoint); if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y)) { hit = true; } } else if (displayObject.containsPoint) { if (displayObject.containsPoint(point)) { hit = true; } } } if (displayObject.interactive) { if (hit && !interactionEvent.target) { interactionEvent.target = displayObject; } if (func) { func(interactionEvent, displayObject, !!hit); } } } return hit; } var config = { view: document.querySelector('#chart'), width: 400, height: 400, roundPixels: true, resolution: 2, autoResize: true, transparent: true, }; var app = new PIXI.Application(config); app.renderer.plugins.interaction.processInteractive = myProcessInteractive; var c1 = new PIXI.Container(); for (let i = 0; i < 20; i++) { var point = new PIXI.Graphics(); point.beginFill(0xff0000, 1); point.drawCircle(0, 0, 6); point.x = 15 * i; point.y = 15 * i; point.buttonMode = true; point.interactive = true; point.mouseover = function() { alert("point mouseover" + i); } c1.addChild(point); } var m = new PIXI.Graphics(); var mask = m.drawRect(20, 20, 160, 160); c1.mask = mask; c1.interactive = true; c1.hitArea = new PIXI.Rectangle(0, 0, c1.width, c1.height); var moveEnable = false; var ox, oy; c1.mousedown = function(e) { moveEnable = true; ox = e.data.global.x; oy = e.data.global.y; } c1.mouseup = function() { moveEnable = false; } c1.mousemove = function(e) { if (moveEnable) { const { x, y } = e.data.global; var dx = x - ox; var dy = y - oy; c1.x += dx; c1.y += dy; ox = x; oy = y; } } var t = new PIXI.Text("Text May be clicked", { fill: 0x7fc3ff, fontSize: 14, }); t.x = 260; t.y = 200; t.buttonMode = true; t.interactive = true; t.click = function() { alert("text clicked") } app.stage.addChild(t); app.stage.addChild(c1);
<ul> <ol>1.I need the Container moveable </ol> <ol>2.points inside the container is clickable</ol> <ol>3.text outside the mask show be not affect by moving the container</ol> <ol>4.points outside the mask should be not clickable</ol> </ul> <canvas id="chart"> </canvas> <script src="https://cdn.bootcss.com/pixi.js/4.6.2/pixi.js"></script>
#chart { border: 1px solid #ddd; margin: 20px auto; }