I am a bit confused by the fact, that in my application it doesn't seem to work to define custom shapes using JointJs in combination with NodeJs. I was trying the following code:
const joint = require('jointjs')
const rectWidth = 130
const rectHeight = 65
joint.shapes.standard.Rectangle.define('examples.CustomRectangle', {
attrs: {
body: {
refWidth: '100%',
refHeight: '100%',
strokeWidth: 5,
stroke: '#000000',
strokeDasharray: rectWidth + ',' + rectHeight,
fill: 'white'
},
label: {
textVerticalAnchor: 'middle',
textAnchor: 'middle',
refX: '50%',
refY: '50%',
fontSize: 14,
fill: '#333333'
}
}
})
console.log(joint)
export class ElementFactory {
createDatastore (x, y) {
return new joint.shapes.examples.CustomRectangle({
position: { x: x - rectWidth / 2, y: y - rectHeight / 2 },
size: { width: rectWidth, height: rectHeight },
attrs: {
text: { textWrap: { width: rectWidth * 0.95, height: 20, ellipsis: true, text: 'Datastore' } }
}
})
}
}
Now my understanding is, that if I require the JointJs module at the beginning of the script, and define a custom shape under it, that it would appear in the module and if needed later (in the factory) I could still access it over the same variable. But instead I get the following error:
Uncaught TypeError: Cannot read property 'CustomRectangle' of
undefined
I am also logging the module right after I have defined the custom shape, but it still doesn't show up.
Am I missing something about NodeJs or JointJs? Does anyone have an idea what the problem is? Any help would be appreciated.
I believe the issue is with how you're attaching it to joint.
Try this:
joint.shapes.examples.CustomRectangle = joint.shapes.standard.Rectangle.define('examples.CustomRectangle', {
attrs: {
body: {
refWidth: '100%',
refHeight: '100%',
strokeWidth: 5,
stroke: '#000000',
strokeDasharray: rectWidth + ',' + rectHeight,
fill: 'white'
},
label: {
textVerticalAnchor: 'middle',
textAnchor: 'middle',
refX: '50%',
refY: '50%',
fontSize: 14,
fill: '#333333'
}
}
});
Despite what the docs (https://resources.jointjs.com/tutorial/custom-elements) strongly imply, define() doesn't attach it to joint.
Related
I'm trying to stretch an image dynamically so it expands in one direction in my Phaser 3 game. I've tried using a Tween with scaleX but there's a problem.
The first one is what I have. An image object in Phaser that I want to stretch. The second bar is what happens when I use scaleX. I guess it's what normally should happen, but not what I need. I need it like bar three. The left side of the image should stay aligned and only the right side should stretch. ALso I want to do this in an animation, so it should be something I can use with tweens or similar solutions. It needs to be possible to do it on any angle, so I can't just change the x-position. It has to be possible at any angle, when I don't know what the angle is going to be.
Does anyone know how to do that?
I'm not sure how your code looks like, but here is how I would solve it:
(If I would have to use scaleX and tween)
Although I don't know: what you want/need/mean with the "...on any angle..., here to know/see your code would be good.
just set the origin of the gameObject to 0 since the default is center
adjust the x position to compensate for the new origin position.
Here a runnable example:
(Tween starts a scaleX = 0 to better illustrate, where the origin is)
var config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#ffffff',
scene: {
create: create
}
};
var game = new Phaser.Game(config);
function create ()
{
var original = this.add.rectangle(225, 75, 200, 50, 0x0);
var defaultOrigin = this.add.rectangle(225, 150, 200, 50, 0x0);
// calculate the offset -100 = half width
var setOrigin = this.add.rectangle(225 - 100, 200, 200, 50, 0x0).setOrigin(0);
var setOriginAtAnAngle = this.add.rectangle(225 - 100, 275, 200, 50, 0x0)
.setOrigin(0)
.setAngle(25);
var setOriginAtAnAngle2 = this.add.rectangle(225 - 100, 375, 200, 50, 0x0)
.setOrigin(0, .5)
.setAngle(25);
// rotation in degrees
//setOriginAtAnAngle.angle = 25;
/* origin point */
this.add.rectangle(225, 75, 5, 5, 0xFFA701).setOrigin(0.5);
this.add.rectangle(225, 150, 5, 5, 0xFFA701).setOrigin(0.5);
this.add.rectangle(225 - 100, 200, 5, 5, 0xFFA701).setOrigin(0.5);
this.add.rectangle(225 - 100, 275, 5, 5, 0xFFA701).setOrigin(0.5);
this.add.rectangle(225 - 100, 375, 5, 5, 0xFFA701).setOrigin(0.5, 1);
/* Just code to improve the display */
this.add.line(0, 0, 150, 25, 150, 400, 0x0000ff).setOrigin(0);
this.add.text(150, 75, ' Base Box', { fontFamily: 'Arial', fontSize: '20px', color: '#fff' }).setOrigin(0, .5);
this.add.text(150, 150, ' Origin: default (Center)', { fontFamily: 'Arial', fontSize: '20px', color: '#f00' }).setOrigin(0, .5);
this.add.text(150, 200, ' Origin: 0 (TopLeft)', { fontFamily: 'Arial', fontSize: '20px', color: '#0f0' }).setOrigin(0, -.5);
this.add.text(150, 290, ' Origin: 0 (TopLeft) with angle', { fontFamily: 'Arial', fontSize: '20px', color: '#0f0' })
.setOrigin(0, -.5)
.setAngle(25);
this.add.text(150, 360, ' Origin: 0 (CenterLeft) with angle', { fontFamily: 'Arial', fontSize: '20px', color: '#0f0' })
.setOrigin(0, -.5)
.setAngle(25);
this.text = this.add.text(100, 12, 'Click to replay tween!', { fontFamily: 'Arial', fontSize: '20px', color: '#0000ff', backgroundColor: '#ffffff', fontStyle:'Bold' });
this.tween = this.tweens.add({
targets: [defaultOrigin, setOrigin, setOriginAtAnAngle, setOriginAtAnAngle2],
duration: 3000,
scaleX:{from:0, to:2},
ease: 'Power0',
onStart: _ => this.text.setText('Tween is running!'),
onActive: _ => this.text.setText('Tween is running!'),
onComplete: _=> this.text.setText('Click to replay tween!')
});
this.input.on('pointerdown', _=> {
if(!this.tween.isPlaying()){
this.tween.restart();
}
})
}
canvas {
transform: scale(.5) translate(-50%, -50%)
}
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.min.js"></script>
Update:
Origin's are now marked in the example, with a yellow point, for clarity.
I'm using rappidjs 3.2 and I'm trying to make a stencil shape that changes shape when I drop it to the paper. For testing purposes I want to just print in the console the type of shape throught dragEndClone (As far as I understood from documentation this is what I need to use).
Stencil :
var stencil = new joint.ui.Stencil({
paper: paper,
scaleClones: true,
width: 240,
groups: {
myShapesGroup1: { index: 1, label: 'My Shapes' }
},
dropAnimation: true,
groupsToggleButtons: true,
search: {
'*': ['type', 'attrs/label/text']
},
layout: true, // Use default Grid Layout
dragEndClone: function (el) {
console.log(el.get('type'));
}
});
document.querySelector('.stencil-container').appendChild(stencil.el);
Shape :
joint.dia.Element.define('standard.Rectangle', {
attrs: {
body: {
refWidth: '100%',
refHeight: '100%',
strokeWidth: 0,
stroke: '#000000',
fill: {
type: 'linearGradient',
stops: [
{ offset: '0%', color: '#FEB663' },
{ offset: '100%', color: '#31D0C6' }
],
// Top-to-bottom gradient.
attrs: { x1: '0%', y1: '0%', x2: '0%', y2: '100%' }
}
},
label: {
textVerticalAnchor: 'middle',
textAnchor: 'middle',
rx: '1%',
refX: '50%',
refY: '50%',
fontSize: 14,
fill: '#333333',
text: 'Siemans'
}
}
}, {
markup: [{ tagName: 'rect', selector: 'body' }, { tagName: 'text', selector: 'label' }]
});
Add shape to stencil :
stencil.render().load({ myShapesGroup1: [{ type: 'standard.Rectangle' }] });
The code previously shown gives me this error :
rappid.js:50779 Uncaught TypeError: Cannot read property 'getBBox' of undefined
at child.drop (rappid.js:50779)
at child.onDragEnd (rappid.js:50638)
at HTMLDocument.dispatch (jquery.js:5429)
at HTMLDocument.elemData.handle
dragEndClone needs to return an element.
dragEndClone: function (el) {
console.log(el.get('type'));
return el.clone();
}
I'm new to JointJS and I'm having trouble working with door positions.
I have 3 ports, 1 of type, 'Out', and 2 of type 'in'.
I'd like to change the position of only one of the 'in' type ports, but I'm not getting it.
Here I leave an image and a link of the code. Thanks for the help right away.
var m1 = new joint.shapes.devs.Model({
position: { x: 50, y: 50 },
size: { width: 100, height: 30 },
inPorts: ['in1','in2'],
outPorts: ['out'],
ports: {
groups: {
'in': {
position: "top",
attrs: {
'.port-body': {
r: "6",
fill: 'blue',
magnet: 'passive'
},
'.port-label': {
fill: "transparent"
}
}
},
'out': {
position: "bottom",
portLabelMarkup: '<text fill="yellow"/>',
attrs: {
'.port-body': {
r: "6",
fill: 'red'
},
'.port-label': {
fill: "transparent"
}
}
}
}
},
attrs: {
'.label': { text: 'node 1', 'ref-x': .5, 'ref-y': .2 },
rect: { fill: 'LightGrey', rx: 15, ry: 15 }
}
}).addTo(graph);
Link of the code
I'd suggest NOT to use the shapes based on the devs.Model as it's a legacy implementation of ports. Since the JointJS v1.0 you can add ports to any shape.
for example:
var m1 = new joint.shapes.standard.Rectangle({
position: { x: 425, y: 60 },
size: { width: 200, height: 100 },
ports: {
groups: {
'in': {
position: {
name: 'top',
args: { dr: 0, dx: 0, dy: -9 }
},
}
},
items: [
{ group: 'in', args: { y: -10 }, id: 'portId'}
]
}
});
Port positions is set using the layout functions. In your example there is the top layout - it means port positions is computed using the joint.layout.Port.top implementation. You can override the result using the args properties on a port:
// set args on newly added
m1.addPort({ group: 'in', args: { y: -20 } });
// update existing
m1.portProp('portId', 'args/y', -20)
for more information see the layout docs: https://resources.jointjs.com/docs/jointjs/v2.2/joint.html#layout.Port
Since i included the for loop i get this error: Warning: Uglification failed.
Unexpected token: punc (.).
This is the js code that im trying to build:
chart: {
type: 'column',
events: {
load: function () {
for (i = 0; i <= captionLabel.length; i++) {
var label = this.renderer.label(captionLabel[i]);
}
.css({
width: '400px',
fontSize: '9px'
})
.attr({
'r': 2,
'padding': 5
})
.add();
label.align(Highcharts.extend(label.getBBox(), {
align: 'center',
x: 20, // offset
verticalAlign: 'bottom',
y: 0 // offset
}), null, 'spacingBox');
}
},
marginBottom: 120
},
Any idea why i get this error when i try to build this file?
You have .(dot) right after closing }, which throws error. Try following code
chart: {
type: 'column',
events: {
load: function () {
for (i = 0; i <= captionLabel.length; i++) {
var label = this.renderer.label(captionLabel[i]);
label.css({
width: '400px',
fontSize: '9px'
})
.attr({
'r': 2,
'padding': 5
})
.add();
label.align(Highcharts.extend(label.getBBox(), {
align: 'center',
x: 20, // offset
verticalAlign: 'bottom',
y: 0 // offset
}), null, 'spacingBox');
}
}
},
marginBottom: 120
}
I use jointjs / rappid.
I would like to change the attributes of a port (e.g. the color of the inPort: in0_2) when the cell is moved. How can I get access to these attributes?
Example of a cell: http://www.epro.de/exchange/virtual-reality/jointjs/celltest.jpg
I guess it's easy - I have tried different ways but can't find a solution.
Any hints?
I use the following code to create the cell and the ports.
var graph = new joint.dia.Graph;
var paper = new joint.dia.Paper({
el: $('#paper-container'),
width: 1000,
height: 1000,
gridSize: 10,
drawGrid: true,
model: graph,
});
var l_st0 = myShapes ();
l_st0.set ('inPorts',(['in0_1', 'in0_2']));
l_st0.set ('outPorts',(['outx']));
l_st0.attr ('.label/text','MinTest');
l_st0.position (100,100);
graph.addCell(l_st0);
l_st0.on ('change:position', function() {
console.log (" change port color ");
});
function myShapes (){
joint.shapes.devs.GenericBasic = joint.shapes.devs.Model.extend({
portMarkup: '<rect class="port-body"/>',
defaults: joint.util.deepSupplement({
type: 'devs.GenericBasic',
inPorts: [],
outPorts: [],
attrs: {
'.label': {
'ref-x': .5,
'ref-y': 5,
'font-size': 12,
'text-anchor': 'middle',
fill: '#000'
},
'.body': {
'ref-width': '100%',
'ref-height': '100%',
stroke: '#000'
}
},
ports: {
groups: {
'in': {
attrs: {
'.port-label': {
'font-size': 12,
'text-anchor': 'start',
x: -10,
fill: '#000000'
},
'.port-body': {
stroke: '#000000',
'text-anchor': 'start',
x:-20,
width: 20,
height: 0.5
}
},
label: {
position: {
name: 'right',
args: {
y: 0
}
}
}
},
'out': {
attrs: {
'.port-label': {
'font-size': 12,
fill: '#000',
'text-anchor': 'start',
x: -40
},
'.port-body': {
stroke: '#000000',
width: 20,
height: 0.5
}
},
label: {
position: {
name: 'right',
args: {
y: 0
}
}
}
}
}
}
}, joint.shapes.devs.Model.prototype.defaults)
});
joint.shapes.devs.GenericModelView = joint.shapes.devs.ModelView;
var mx = new joint.shapes.devs.GenericBasic ({
size: { width: 80, height: 100 },
attrs: {
rect: {
stroke: 'black',
'stroke-width': 1
},
}
});
return mx;
}
I solved it this way - like it is described in the jointjs documentation.
l_st0.on ('change:position', function() {
//optimization is missing
var l_portsIn = this.get ('inPorts');
if (l_portsIn.length>0){
this.portProp (l_portsIn[0],'attrs/rect',{stroke: 'red' });
}
}