How to use/set stopDelegation with jointjs paper options (basing on Angular 6 Kitchensink sample) - jointjs

I'm trying to use that "new" stopDelegation feature. I want to provide a "readonly" view of the paper and am nearly done - last thing missing is movability (drag) of the paper. Well, it is movable, but not when grabbing an element/shape/link.
How is that option supposed to use?
I'm actually using v2.4.0 trial (Angular 6).
According to the documentation my guess was "stopDelegation" is a property of CellView.InteractivityOptions (or ElementView.InteractivityOptions). But that doesn't seem to work.
const self = this;
const paper = (this.paper = new joint.dia.Paper({
width: 1000,
height: 1000,
gridSize: 10,
drawGrid: true,
model: graph,
cellViewNamespace: appShapes,
defaultLink: <joint.dia.Link>new appShapes.app.Link(),
interactive: function(cellView, event) {
return {
linkMove: self.isEditable,
labelMove: self.isEditable,
arrowheadMove: self.isEditable,
vertexMove: self.isEditable,
vertexAdd: self.isEditable,
vertexRemove: self.isEditable,
useLinkTools: self.isEditable,
elementMove: self.isEditable,
addLinkFromMagnet: self.isEditable,
stopDelegation: self.isEditable
} as joint.dia.CellView.InteractivityOptions;
}
}));
When self.isEditable == false, the paper should be movable when grabbing an element, but it isn't (it's still only movable when pointing on a void place on the paper).
(I also had to tweak rappis.d.ts a bit to allow interactive to be a function returning a CellView.InteractivityOptions object...).
Am I doing something wrong or is this a bug?
Or isn't it intended/designed to use it that way (to allow moving of the paper only instead of a parent "element")?

The stopDelegation property is relevant to embedded elements only. Since paper is not "parent" to any elements, the interactivity can never be delegated to the paper. The locking of the paper movement is a Rappid PaperScroller feature.
Rappid PaperScroller
var paperScroller = new joint.ui.PaperScroller({
paper: paper,
cursor: 'grab'
});
paperScroller.lock();

Related

How to access Object3D material after adding the GLTF

I want to duplicate my GLTF models with different positions/colors dynamically, to do so I have done:
const L_4_G = new Object3D();
...
const multiLoad_4 = (result, position) => {
const model = result.scene.children[0];
model.position.copy(position);
model.scale.set(0.05, 0.05, 0.05);
//
L_4_G.add(model.clone())
scene.add(model);
};
...
function duplicateModel4() {
L_4_G.translateX(-1.2)
L_4_G.translateY(0.0)//0.48
L_4_G.translateZ(1.2)
L_4_G.rotateY(Math.PI / 2);
scene.add(L_4_G);
}
I didn't find out how can I change the Object3D color from the documentation, can you please tell me how can I do that? thanks in advance.
Here is the full code that I'm using, and here are the models
Update
I have seen this solution, to store a set of colors in the object's userData and choose the color later:
L_2_G.userData.colors = {green : #00FF00, red : ..., ...}
L_2_G.children[0].material.color(userData.colors["green"])
But I'm getting an error that children[0] undefined, but I can see that this object has a child and a material, and color via the console: console.log(L_2_G.children), console.log(L_2_G.children.length)--> 0
Also I have tried getObjectByName as explained here:
scene.getObjectByName(name).children[0].material.color.set(color);
which also reslts: children[0] is undefined, scene.getObjectByName(name).children.length is 0.
THREE.Object3D is a base class for anything that can go in a scene graph, including lights, cameras, and empty objects. Not all Object3D instances have geometry or materials. You may be looking for the THREE.Mesh subclass which does have materials and colors.
In general, code like getObjectByName(...) and model = result.scene.children[0] is very content-specific. The file might contain many nested objects, and .children[0] just grabs the first part. It's usually best to traverse the scene graph instead, looking for the objects you want to modify (e.g. looking for all Meshes, or Meshes with a particular name).
const model = result.scene;
model.traverse((object) => {
if (object.isMesh) {
object.material.color.setHex( 0x404040 );
}
});
Then you can either add the entire group to your scene (scene.add(model)), or just add parts of it. Keep in mind that adding meshes to a new parent removes them from their previous parent, and you shouldn't do that while traversing the previous parent. Instead you can make a list of meshes, and add them in a second step:
const meshes = [];
result.scene.traverse((object) => {
if (object.isMesh) {
meshes.push(object);
}
});
for (const mesh of meshes) {
scene.add(mesh);
}
Finally, the position of an object is inherited from its parents. By removing the object from its original parents you might change its position in the scene. If you are planing to assign a new position to the object anyway, that is fine.

Detect collision direction in Phaser3

I'm trying to create a 'Bomber-man' like game using Phaser3 library.
For this purpose I'd like to define a collision relationship between the player and the bricks,
and more importantly - detect the collision direction relative the the player.
I've noticed body properties like touching or blocked but they are always set to false. (please see below)
//scene.js
// bricks static group
this.scene.physics.add.staticGroup({ immovable: true });
// player defined in external file (as sprite)
this.player = new Player(this, 90, 90)
// player.js
// ...
this.physics.add.collider(
this,
scene.bricks,
function(player, brick) {
if(player.body.touching.left) { //ALWAYS FALSE!!!
this.isBlockedFromLeft = true;
}, else if(player.body.touching.right) {
this.isBlockedFromRight = true; // ALWAYS FALSE!!!
}
},
null,
this
);
I'd appreciate any help. This is driving me crazy. Maybe there is a better way to do it and i'm missing something...
Thanks in advance.
So I finally figured it out.
The major issue was the way I defined the player movement. It should be
if (this.keyboard.right.isDown) {
this.body.setVelocityX(this.speed);
}
rather than
if (this.keyboard.right.isDown) {
this.x += this.speed;
}
The second way prevent collision detection and the body.touching and body.blocked properties to be updated.
Furthermore, I've found out that when it comes to top-down tiled games, it's really easier to build up the game using the tile-map feature.
official examples can be found here:
https://phaser.io/examples/v3/search?search=map
and here is a tutorial of how to make a tiled-map using a light-weight software called 'Tiled'
https://www.youtube.com/watch?v=2_x1dOvgF1E
Thank you all!

Mouse events sent as inputs to phaser scene

Can you please show me how the dom can communicate mouse pointer movement events as an input to a phaser scene. I've seen how mouse movement can be tracked within the scene area; but once the mouse leaves and goes to other areas of the DOM, that data is not tracked. I figure if perhaps there was a way to have an input to communicate data from "the outside world" then this could be possible. I am very grateful for help and direction you could share.
All you need to do is add an event listener to the DOM object you also want to track movement in using plain JavaScript. Then, you tie the event listener to the game method you want to execute when the event is triggered.
const body = document.querySelector('body');
body.onmousemove = (pointer) => {
updatePoint(pointer);
};
And then setup your game as normal:
const config = {
type: Phaser.CANVAS,
height: 400,
width: 400,
parent: 'gameContainer',
scene: {
create: create
}
};
const game = new Phaser.Game(config);
let dataText;
function create() {
this.input.on('pointermove', (pointer) => {
updatePoint(pointer);
});
dataText = this.add.text (10, 10, 'x, y');
}
function updatePoint(pointer) {
dataText.text = 'x: ' + pointer.offsetX + ', y: ' + pointer.offsetY;
}
You may have to refactor your code a little bit to get this to work, because the event listener on your DOM element needs to be able to access the game methods. I created a quick codepen showing the setup that worked for me.

Jointjs When dragging a link target, have it call a custom function

I would like to override the default link behaviour. I have a function that deals with connecting a link to a target following a certain set of rules. For example, LinkTypeA will can only connect to ObjectType1 and ObjectType2, and LinkTypeB will only connect with ObjectType3.
In the case that the user is creating LinkTypeA, and terminates when clicking on ObjectType3, a point (x, y) is created for the links target.
This is because ObjectType1 and ObjectType2 are often embedded above a ObjectType3.
I have that behaviour working correctly, but when you grab a links end and drag it, when letting go, it runs an internal function instead, which allows it to connect to ObjectType3.
I would like to override this and have it call my custom function. How can I do this?
linkValidation function should handle it even if the link is being dragged. In the example below only shapes with a same type can be linked (rect with rect, circle with circle).
var paper = new joint.dia.Paper({
el: $('#paper'),
width: 650,
height: 400,
model: graph,
linkPinning: false,
validateConnection: function(cellViewS, magnetS, cellViewT, magnetT, end, linkView) {
var source = cellViewS.model.get('type');
var target = cellViewT.model.get('type');
return source && source === target;
}
});
https://jsfiddle.net/vtalas/65uteht9/

JointJs creating custom shapes and specifying their default link

I'm trying to implement my own shape class with ports. However I want the links that these shapes generate to be smooth. Right now, the only way i know to make smooth links is
link.set('smooth', true).
But how do i do that not through code? How do i get smooth links by just dragging?
I extended Link class (MyLink) but how do i tell JointJS which Link class to use when i drag on the port?
joint.shapes.myclass.Link = joint.dia.Link.extend({
defaults: {
type: 'myclass.Link',
attrs: { '.connection' : { 'stroke-width' : 5 }},
smooth:true
}
});
Links created via the UI by dragging ports are defined in the defaultLink property of the paper. It can either be an object in which case it is a link model or a function that returns a link model:
var paper = new joint.dia.Paper({
defaultLink: new joint.shapes.myclass.Link,
...
})
or:
var paper = new joint.dia.Paper({
defaultLink: function(elementView, magnet) {
if (aCondition) return new joint.dia.Link;
else return joint.shapes.myclass.Link;
}
})
The function gives you flexibility in creating different links on the fly depending on what element is underneath or what magnet (SVG element for port) is being dragged.

Resources