I've looked through the collection of examples, that go with the library, but unfortunatelly, all examples, devoted to composite figures, are based on parsing json file.
reader.unmarshal(canvas, jsonDocument);
However, what I want to see is how to create composite figures from basic ones, something like:
var figure_1 = new draw2d.shape.basic.Rectangle(....);
var figure_1 = new draw2d.shape.basic.Diamond(....);
... then do something, so that figure_1 and figure_2 are now part of
... a composite figure
PS. I think what I need is StrongComposite, but I do not know how to use it. Hope someone can help!
EDIT
This is what I tried:
var baseRectangle = new draw2d.shape.composite.StrongComposite({width: 200, height: 200, x: conf.x, y: conf.y});
var top = new draw2d.shape.basic.Oval({width: 120, height: 40, x: conf.x, y: conf.y});
var bottom = new draw2d.shape.basic.Oval({width: 120, height: 40, x: conf.x, y: conf.y + 60});
baseRectangle.assignFigure(top);
baseRectangle.assignFigure(bottom);
canvas.add(baseRectangle);
But it does not work. I only see a gray box. I also tried this:
var baseRectangle = new draw2d.shape.composite.StrongComposite({width: 200, height: 200, x: conf.x, y: conf.y});
var top = new draw2d.shape.basic.Oval({width: 120, height: 40, x: conf.x, y: conf.y});
var bottom = new draw2d.shape.basic.Oval({width: 120, height: 40, x: conf.x, y: conf.y + 60});
baseRectangle.assignFigure(top);
baseRectangle.assignFigure(bottom);
canvas.add(top);
canvas.add(bottom);
But as a result, I got absolutely independent ovals.
You also have to add baseRectangle to canvas.
var baseRectangle = new draw2d.shape.composite.StrongComposite({
width: 200,
height: 200,
x: conf.x,
y: conf.y
});
canvas.add(baseRectangle);
var top = new draw2d.shape.basic.Oval({
width: 120,
height: 40,
x: conf.x,
y: conf.y
});
var bottom = new draw2d.shape.basic.Oval({
width: 120,
height: 40,
x: conf.x,
y: conf.y + 60
});
baseRectangle.assignFigure(top);
baseRectangle.assignFigure(bottom);
canvas.add(top);
canvas.add(bottom);
In addition to needing to put the child elements on the canvas (sorry, can't comment on existing answer yet): I found I need to wait a frame (nextTick with Vue) before assignFigure can work. Otherwise draw2d throws exception:
TypeError: Cannot read properties of null (reading 'paper')
at Class.createShapeElement (null:23614:34)
at Class.getShapeElement (null:8492:33)
at Class.toFront (null:8351:22)
at Class.toFront
Related
I'm trying to center a circle in a given rectangle. One of the approaches to do the job could be graphics working with Phaser.Display.Align.In.Center and I'm having trouble doing that. Here is the code.
class BootScene extends Phaser.Scene {
constructor() {
super({
key: 'BootScene'
});
}
create() {
let btn = this.add.rectangle(800, 600, 200, 150, '#000').setOrigin(1);
let txt = this.add.text(0, 0, 'click');
Phaser.Display.Align.In.Center(txt, btn, );
let graphics = this.add.graphics({
x: 750,
y: 550
});
var shape = new Phaser.Geom.Circle(0, 0, 24);
graphics.fillStyle(0xff0000, 1);
graphics.fillCircleShape(shape);
//Phaser.Display.Align.In.Center(graphics, btn);
}
}
var config = {
width: 800,
height: 600,
backgroundColor: '#555',
scene: [BootScene]
}
var game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
There are 3 visual parts in the code above: the btn rectangle, the txt text and the graphics.
Phaser.Display.Align.In.Center works well with btn and txt.
graphics works well with btn using
this.add.graphics({
x: 750,
y: 550
});
However, if I uncomment the following line below out
Phaser.Display.Align.In.Center(graphics, btn);
the graphics is gone, not matter I set the config as { x: 750, y: 550 } or { x: 0, y: 0 }.
What am I missing?
I know I could use something like
let circle2 = this.add.circle(0, 0, 32, 0xf00000);
Phaser.Display.Align.In.Center(btn_circle, circle2);
I'd just like to know why it doesn't work when I combine graphics and Phaser.Display.Align.In.Center together.
Update: it seems to be a bug of phaser (or a mistake in the documentation), since after calling Phaser.Display.Align.In.Center on the graphics object, the x and y properties are set to NaN, and acording the documenation Align should accept a GameObject, which the Graphics object is.
Here is a possible solution:
You could simply generate a texture out of the graphics object, with the function generateTexture on the graphics object
Align the newly created image with the btn
I just added a setDepth call to the txt object, so it would be visible
class BootScene extends Phaser.Scene {
constructor() {
super({
key: 'BootScene'
});
}
create() {
let btn = this.add.rectangle(300, 175, 200, 150, '#000').setOrigin(1);
let txt = this.add.text(0, 0, 'click');
Phaser.Display.Align.In.Center(txt, btn );
let graphics = this.make.graphics({
x: 24,
y: 24,
});
var shape = new Phaser.Geom.Circle(24, 24, 24);
graphics.fillStyle(0xff0000, 1);
graphics.fillCircleShape(shape);
graphics.generateTexture('gCircle', 48, 48);
let image = this.add.image(200, 200, 'gCircle');
Phaser.Display.Align.In.Center(image, btn);
// only to make the Button visible
txt.setDepth(2);
}
}
var config = {
width: 400,
height: 200,
backgroundColor: '#555',
scene: [BootScene]
}
var game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
See Fiddle: I am trying to render a background image on a FabricJS polygon, but for some reason the scale of the pattern is different on different devices / browsers for no obvious reason.
Here is the code:
HTML:
<canvas id="tcanvas" width="200" height="200" />
JavaScript:
function testPattern(id) {
var url = 'https://dummyimage.com/200x200/aff/000',
tCanvas = new fabric.Canvas(id);
new fabric.Image.fromURL(url, function(img) {
var tPoints = [{
x: 0,
y: 0
},
{
x: 0,
y: 200
},
{
x: 200,
y: 200
},
{
x: 200,
y: 0
}
];
var tPatternWidth = 200;
var tPatternHeight = 200;
var tImgXScale = tPatternWidth / img.width;
var tImgYScale = tPatternHeight / img.height;
img.set({
left: 0,
top: 0,
scaleX: tImgXScale,
scaleY: tImgYScale
});
var tPatternSourceCanvas = new fabric.StaticCanvas();
tPatternSourceCanvas.add(img);
tPatternSourceCanvas.renderAll();
var tPattern = new fabric.Pattern({
offsetX: 0,
offsetY: 0,
source: function() {
tPatternSourceCanvas.setDimensions({
width: tPatternWidth,
height: tPatternHeight
});
tPatternSourceCanvas.renderAll();
return tPatternSourceCanvas.getElement();
},
repeat: 'no-repeat'
});
var tImgPoly = new fabric.Polygon(tPoints, {
left: 100,
top: 100,
originX: 'center',
originY: 'center',
fill: tPattern,
objectCaching: false,
selectable: false,
stroke: 'red',
strokeWidth: 1
});
tCanvas.add(tImgPoly);
tCanvas.renderAll();
});
}
testPattern('tcanvas');
This is what I see on my desktop Chrome:
... and this what I see on a (Samsung) tablet Chrome:
How can I fix the code so that the both patterns look the same, i.e., like the first one?
It s a retina support side effect.
When initializing the canvas for the Pattern, please pass as option:
enableRetinaScaling: false
var tPatternSourceCanvas = new fabric.StaticCanvas(null, {enableRetinaScaling: false});
This will avoid fabric trying to enhance the canvas twice.
I'm working on a simple game with Javascript, involving changes to an HTML5 canvas. Have a number (10+) of objects entered in an array:
var boxes = [];
boxes.push({
x: 0,
y:canvas.height - 370,
width: 400,
height: 20});
boxes.push({
x: 300,
y:canvas.height - 100,
width: 150,
height: 90});
The entire array is then run through an update function, which changes the x value depending on the player's position:
for (var i = 0; i < boxes.length; i++) {
if (boxes[1].x > -3000 + canvas.width) {
boxes[i].x -= robot.speed * modifier;
robot.x = canvas.width - 300;
};
};
When the player dies a reset function is run:
var reset = function () {
robot.x = 0;
robot.y = 500;
++deaths;
};
I'm looking for a way to reset all the values of the boxes array to the original values when this function runs, essentially resetting the map, without having to enter each one manually, ie boxes[1].x = 300
https://jsfiddle.net/to31b612/
Simply initialize from a single function:
var boxes;
initBoxes();
function initBoxes() {
boxes = [];
boxes.push({
x: 0,
y:canvas.height - 370,
width: 400,
height: 20});
boxes.push({
x: 300,
y:canvas.height - 100,
width: 150,
height: 90});
}
Then just recall initBoxes() every time you need to initialize it.
You could just initialize boxes inside the reset() function, and make sure to call call reset() before the first run of the game, too.
var deaths = -1;
var boxes = [];
function reset() {
robot.x = 0;
robot.y = 500;
boxes = [{
x: 0,
y:canvas.height - 370,
width: 400,
height: 20
}, {
x: 300,
y:canvas.height - 100,
width: 150,
height: 90
}];
++deaths;
}
It sounds like you want to use the Memento Pattern
just use 2 variables
var initBoxes = [];
initBoxes.push({
x: 0,
y:canvas.height - 370,
width: 400,
height: 20});
initBoxes.push({
x: 300,
y:canvas.height - 100,
width: 150,
height: 90});
var boxes = initBoxes;
Then when ever you need to reset boxes just
boxes = initBoxes;
I try to crop image with this way
var crop = new Kinetic.Image({
image: img ,
x: 100, y: 100, width: 100, heigth: 100,
crop : {
x: 0, y: 0, width: 100, heigth: 100
}
});
and it doesn't work see in http://jsfiddle.net/cm5jj/
and then I try to fill rect with image
var rect = new Kinetic.Rect({
x: 100,
y: 100,
width: 100,
height: 100,
fill:{
image: img,
crop:{
x: 0,
y: 0,
width: 100,
height: 100
},
}
});
and still doesn't work http://jsfiddle.net/cm5jj/1/
please help.
thank so much.
I believe the problem is that you're cropping the image to the exact dimensions of the image size, which means that you aren't cropping at all. try setting width and height to values greater than the crop width and height values.
Also, if you're wanting to animate the sprite, you should be using Kinetic.Sprite() instead
In your first code snippet, you mistyped height with heigth. Maybe spell check will help with this.
As to your second code snippet, to fill a rect with an image, you need fillPatternImage property, which requires an image object, and fill is used to fill with color.
fill example:
var rect = new Kinetic.Rect({
x: 100,
y: 100,
width: 100,
height: 100,
fill: 'blue'
});
fillPatternImage example:
var img = new Image();
img.onload = function() {
var rect = new Kinetic.Rect({
x: 100,
y: 100,
width: 100,
height: 100,
fillPatternImage: img
});
// Add rect to your layer, and do drawing
};
img.src = 'http://cdn.sstatic.net/img/share-sprite-new.svg';
I have this code:
var rect2 = new drawRect({
h: 100,
w: 100,
x: 280,
y: 20,
colour: '8CB5CF',
name: 'Office 2'
}
Is it possible for read the properties that I am passing to drawRect?
My first thought was:
alert(rect2.h)
But that results in undefined, didn't expect it to work really but I don't know how else to approach this.
I am fairly new to javascript. Thanks.
EDIT: Sorry here is drawRect:
function drawRect(rectOptions){
var ctx = document.getElementById('canvas').getContext('2d');
ctx.fillStyle = rectOptions.colour;
ctx.fillRect(rectOptions.x,rectOptions.y,rectOptions.h,rectOptions.w);
ctx.font = '12px sans-serif';
ctx.fillText(rectOptions.name, rectOptions.w + rectOptions.x, rectOptions.h + rectOptions.y);
}
here is the full code: Full code
Inside of the drawRect function you could add a line to add an option property to objects constructed by drawRect.
function drawRect(rectOptions) {
this.options = rectOptions;
//...
}
Then you could do
var rect2 = new drawRect({ /* ... */ });
alert(rect2.options.h);
Alternatively, you could have drawRect return the options passed to it.
function drawRect(rectOptions) {
//...
return rectOptions;
}
Then you could do, as you originally tried,
alert(rect2.h);
var rect2 = new drawRect({
h: 100,
w: 100,
x: 280,
y: 20,
colour: '8CB5CF',
name: 'Office 2'
})
function drawRect(rectOptions){
//your code
return rectOptions;//you have to return the value
}
alert(rect2.h);//alerts 100
link to jsfiddle