FabricJS Update Bounding Box - fabricjs

I'm unable to get the bounding box of a canvas to update after panning. I've tried to requestRenderAll and to reset the coordinates of each object, but the bounding box stays in the same location.
Is there a different function I should be calling?
Things I've tried:
if (!pausePanning && e.self.x && e.self.y && e.e.type) {
currentX = e.self.x;
currentY = e.self.y;
xChange = currentX - panX;
yChange = currentY - panY;
if( (Math.abs(xChange) <= 100) &&
(Math.abs(yChange) <= 100) ) {
var delta = new fabric.Point(xChange, yChange);
canvas.relativePan(delta);
}
panX = e.self.x;
panY = e.self.y;
// attempting to redraw bounding
canvas.getObjects().forEach(function(o) {
o.setCoords();
});
// this also doesn't work
canvas.requestRenderAll();
}
}

Ended up filing a ticket and heard back; the issue was that you need to specify the updated canvas when you select items after panning or zooming.
An example if your canvas is named as canvas variable:
var sel = new fabric.ActiveSelection(selection, { canvas: canvas });
canvas.setActiveObject(sel).requestRenderAll();
And a jsfiddle showing the zoom/panning with the updated selection.

Related

three.js orbit object around a changing axis

I have a simple 3D object and I am able to rotate i.e., move with my left mouse button, around the centre of axis - works fine. When I pan using the right mouse button the axis also shifts, as such it no longer moves around it’s present axis.
How can I move the object around it’s current axis, no matter where I drag the object?
Below is the complete code of script.js
var scene = new THREE.Scene();
var axisHelper = new THREE.AxisHelper(100);
scene.add(axisHelper);
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
camera.position.y = -200;
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = true;
var keyLight = new THREE.DirectionalLight(new THREE.Color('hsl(30, 100%, 75%)'), 1.0);
keyLight.position.set(-100, 0, 100);
var fillLight = new THREE.DirectionalLight(new THREE.Color('hsl(240, 100%, 75%)'), 0.75);
fillLight.position.set(100, 0, 100);
var backLight = new THREE.DirectionalLight(0xffffff, 1.0);
backLight.position.set(100, 0, -100).normalize();
scene.add(keyLight);
scene.add(fillLight);
scene.add(backLight);
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setTexturePath('assets/');
mtlLoader.setPath('assets/');
mtlLoader.load('180319_object01.mtl', function (materials) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials(materials);
objLoader.setPath('assets/');
objLoader.load('180319_object01.obj', function (object) {
object.scale.set( 200, 200, 200 );
scene.add(object);
object.position.x = -100;
object.position.y = -100;
object.position.z = 0;
});
});
var animate = function () {
requestAnimationFrame( animate );
controls.update();
renderer.render(scene, camera);
};
animate();
It is because your camera is being moved by the controller and not the object itself, rather than update the cameras position and direction ((ie which is what the orbit controller is doing).in your render method you'll want to update position and Euler angle on the object itself to achieve the desired effect. To do this you'll want to track and update the position and angle of rotation about the (y?) Axis of the object,in the object (model) space.hope that makes sense, let me know if you need me to elaborate.

Limit Area Pan Fabircjs

I have a canvas, which is infinite right now, I can make PAN up to the coordinates that I want. But our users, are lost after an intense use of it, because they can not find the objects.
I want to implement a limit that the user puts in the canvas.
I know how to limit the bread when, the work size is smaller than the size of the canvas, simply not letting the bread tool do its job.
But I have problems when the user asks me for a bread size larger than the size of the canvas
The default canvas size is 900 x 600, and my user needs to be able to work on 2000x2000. The canvas would still be 900x600 but the PAN tool is enabled, and can move within the canvas, up to the 2000x2000 limit
I have seen in the fabric demos, that there is a tutorial of Pan, but it is not compatible with my problem, because in that example, the canvas is fixed
I have solved my problem with the following code
var maxWidth = 1000;
var maxHeight = 1000:
if(obj.currentHeight > maxHeight || obj.currentWidth > maxHeight){
return;
}
obj.setCoords();
// top-left corner
if(obj.getBoundingRect(true).top < 0 || obj.getBoundingRect(true).left < 0){
obj.top = Math.max(obj.top, obj.top-obj.getBoundingRect(true).top)+5;
obj.left = Math.max(obj.left, obj.left-obj.getBoundingRect(true).left)+5;
}
// bot-right corner
if(obj.getBoundingRect(true).top+obj.getBoundingRect(true).height > maxHeight || obj.getBoundingRect(true).left+obj.getBoundingRect(true).width > maxWidth){
obj.top = Math.min(obj.top, (maxHeight-5)-obj.getBoundingRect(true).height+obj.top-obj.getBoundingRect(true).top);
obj.left = Math.min(obj.left, (maxWidth-5)-obj.getBoundingRect(true).width+obj.left-obj.getBoundingRect(true).left);
}
canvas.on('mouse:down', function(e){
var evt = e.e
this.lastPosX = evt.clientX;
this.lastPosY = evt.clientY;
});
canvas.on('mouse:move', function (e) {
if (global_panning && e && e.e && global_mover) {
zoom = canvas.getZoom();
if(zoom<0.4){
this.viewportTransform[4] = 200 - maxWidth * zoom /2;
this.viewportTransform[5] = 200 - maxHeight * zoom /2;
}else{
this.viewportTransform[4] += e.e.clientX - this.lastPosX;
this.viewportTransform[5] += e.e.clientY - this.lastPosY;
if (this.viewportTransform[4] >= 0) {
this.viewportTransform[4] = 0;
} else if (this.viewportTransform[4] < canvas.getWidth() - maxWidth * zoom) {
this.viewportTransform[4] = canvas.getWidth() - maxWidth * zoom;
}
if (this.viewportTransform[5] >= 0) {
this.viewportTransform[5] = 0;
} else if (this.viewportTransform[5] < canvas.getHeight() - maxHeight *zoom) {
this.viewportTransform[5] = canvas.getHeight() - maxHeight * zoom;
}
//console.log(this.viewportTransform);
}
this.requestRenderAll();
this.lastPosX = e.e.clientX;
this.lastPosY = e.e.clientY;
}
});
In fabricJS I have used the code that comes in the demos of Zoom, in tutorial 5, customizing it to my needs. In my case, the size of the limit is decided by the user, so I have defined a variable, which collects that value, and replace the value of the size of the canvas that is in the FabricJS instance for mine.
I hope this can help you in the future, who needs help with this topic

fabricjs - Allow single click text-editing, but distinguish between text click and border click

I currently have my IText elements set up to enter editing mode on single click, but I still want the user to be able to move the text around. I've added padding to the text elements in the hopes that I can distinguish between a click on the border (user wants to move the text) vs. a click directly on the text (editing). Any help would be greatly appreciated..
For anyone interested in this, I figured out a solution. Granted this isn't ideal, but it works. You'll want your IText elements to have a padding of 5 or more pixels to get a good result..
isOnBorder(mouseX, mouseY, coords, padding) {
let topLeftX = coords.tl.x + padding;
let topRightX = coords.tr.x - padding;
let topLeftY = coords.tl.y + padding;
let bottomLeftY = coords.bl.y - padding;
if (mouseX < topLeftX || mouseX > topRightX) {
return true;
} else if (mouseY < topLeftY || mouseY > bottomLeftY) {
return true;
}
return false;
}
Listen for object:selected event on canvas
'object:selected': (event) => {
let object = event.target;
let mouseX = object._mousedownX;
let mouseY = object._mousedownY;
let coords = object.oCoords;
let padding = object.padding;
if (this.isOnBorder(mouseX, mouseY, coords, padding)) {
return;
}
If user didn't click within padding px of the border, enter editing on single click
object.enterEditing();

Drawing rectangle underneath PIXI.Text

In a word game I am trying to draw score as white numbers above a blue (or red) rectangle:
For example, in the above screenshot it is the number "13".
Here is my entire class Score.js (with currently hardcoded WIDTH and HEIGHT):
"use strict";
function Score(color) {
PIXI.Container.call(this);
this.interactive = false;
this.buttonMode = false;
this.visible = false;
this.bgGraphics = new PIXI.Graphics();
this.bgGraphics.beginFill(color, 1);
this.bgGraphics.drawRect(0, 0, Score.WIDTH, Score.HEIGHT);
this.bgGraphics.endFill();
this.addChild(this.bgGraphics);
this.text = new PIXI.Text('XXX', {font: '20px Arial', fill: 0xFFFFFF});
this.text.x = 1;
this.text.y = 1;
this.addChild(this.text);
}
Score.prototype = Object.create(PIXI.Container.prototype);
Score.prototype.constructor = Score;
Score.WIDTH = 36;
Score.HEIGHT = 24;
Score.prototype.setText = function(str) {
this.text.text = str;
}
I wonder, how to modify my setText() function, so that a new rectangle is drawn on each call - as a bounding rectangle for the str argument?
I have looked at the PIXI.Text.getBounds() method, but it returns a Matrix and not a Rectangle...
I think you can just use this.text.width. This has historically had some bugs associated with it, but it should be working right in the latest version.

Phaser BitmapData Sprite Immovable on Drag

I am a noob with Phaser games in general but I am trying to make a scrabble like game.
I made my tiles as BitmapData and added to sprite. I want to be able to drag and drop them on my scrabble board but not be able to place one tile in a spot where another tile is.
For debugging purposes Ive been just trying to get the individual tiles to respect each other's physics when you drag and drop. The behavior I want is, when dragging, to bump into another tile with that tile "holding its ground" and the dragging tile unable to cross on top of the other tile. Currently the dragged tile just goes on top of other tiles. I've looked at a lot of examples and feel that my issue may be either because my sprite is made with bitmapData or something around the drag event...
function makeTile (tileIndex, tile) {
var bmd = game.add.bitmapData(canvasZoom, canvasZoom);
// draw to the canvas context
bmd.ctx.beginPath();
bmd.ctx.rect(0, 0, canvasZoom, canvasZoom);
bmd.ctx.fillStyle = '#efefef';
bmd.ctx.fill();
bmd.ctx.fillStyle = '#234234';
bmd.ctx.font="20px Georgia";
bmd.ctx.fillText(tile.tileName, 7,23);
// use the bitmap data as the texture for the sprite
var tileSprite = game.make.sprite((tileIndex * canvasZoom) + canvasZoom, canvasZoom, bmd);
game.physics.arcade.enable([tileSprite]);
tileHandGroup.add(tileSprite);
tileSprite.inputEnabled = true;
var bounds = new Phaser.Rectangle(canvasZoom, canvasZoom, spriteWidth * canvasZoom, (spriteHeight * canvasZoom) + (canvasZoom * 2));
tileSprite.input.boundsRect = bounds;
tileSprite.name = 'tileSpriteName' + tileIndex;
tileSprite.input.enableDrag(true);
tileSprite.input.enableSnap(canvasZoom, canvasZoom, true, false);
tileSprite.immovable = true;
tileSprite.body.moves = false;
tileSprite.events.onDragStart.add(onDragStart, this);
tileSprite.events.onDragStop.add(onDragStop, this);
}
function firstTileHand() {
tileHandGroup = game.add.physicsGroup(Phaser.Physics.ARCADE);
game.physics.enable(tileHandGroup, Phaser.Physics.ARCADE);
tileHandGroup.enableBody = true;
tileHandGroup.name = 'tileHandGroup';
for (var i = 0; i < tiles.length; i++)
{
makeTile(i, tiles[i]);
}
}

Resources