Limit Area Pan Fabircjs - fabricjs

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

Related

How are trigonometric functions used in this sketch to make one object move towards another?

So I asked a someone to help me with a small project ( ball chases ball you control one)
and he gave me a trigonometric thing, it works very well can someone explain trigonometry to me?
Heres the code he gave me:
var aiX = 0;
var aiY = 0;
var playerX = 200;
var playerY = 200;
draw = function () {
background(255);
playerX = mouseX;
playerY = mouseY;
fill(0, 255, 0);
ellipse(playerX, playerY, 50, 50);
fill(255, 0, 0);
ellipse(aiX, aiY, 50, 50);
var angle = atan2(playerY - aiY, playerX - aiX);
aiX += cos(angle);
aiY += sin(angle);
if (dist(playerX, playerY, aiX, aiY) < 50) {
text("ouch!", 100, 100);
}
};
How i changed it:
var aiX = 200;
var aiY = 0;
function setup() {
playerX = 200;
playerY = 200;
}
draw = function () {
createCanvas(400, 400);
background(255);
let h = hour();
//scare anyone
if (h === 3) {
console.log("I SEE YOU");
let img = createImg(imageData, "YOU CANT HIDE EVEN IF I WONT LOAD");
}
if (isKeyPressed && keyCode === UP_ARROW) {
playerY = playerY - 5;
}
if (isKeyPressed && keyCode === DOWN_ARROW) {
playerY = playerY + 5;
}
if (isKeyPressed && keyCode === RIGHT_ARROW) {
playerX = playerX + 5;
}
if (isKeyPressed && keyCode === LEFT_ARROW) {
playerX = playerX - 5;
}
fill(0, 255, 0);
ellipse(playerX, playerY, 50, 50);
fill(255, 0, 0);
ellipse(aiX, aiY, 50, 50);
function reset() {
playerX = 200;
playerY = 200;
aiX = 200;
aiY = 15;
}
var angle = atan2(playerY - aiY, playerX - aiX);
aiX += cos(angle);
aiY += sin(angle);
if (dist(playerX, playerY, aiX, aiY) < 50) {
console.log("GAMEOVER");
reset();
}
};
const imageData =
"data:image/jpeg;base64,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";
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
I just started learning p5js about a week ago, so sorry if my code is bad or sloppy...
Editor:https://editor.p5js.org/
Ironically the use of trigonometry in this example is actually unnecessary. The objective is to move a circle positioned at aiX, aiY closer to a second circle positioned at payerX, playerY. It is trivial to compute a vector from the ai position to the player position by taking the difference between the two components in each direction: playerX - aiX is the offset from ai to player in the horizontal direction, and playerY - aiY is the offset from ai to player in the vertical direction. Obviously you won't want to change the position of the ai circle by the entire offset, since that would be instant game over. If you want to fix the speed of movement at a particular level, you simply need to divide each component by the length of the vector, and then if you want a speed other than 1, multiply by the desired speed. Here is the code that does this without any trigonometry:
let aiX = 200;
let aiY = 0;
let playerX = 200;
let playerY = 200;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(255);
if (isKeyPressed && keyCode === UP_ARROW) {
playerY = playerY - 5;
}
if (isKeyPressed && keyCode === DOWN_ARROW) {
playerY = playerY + 5;
}
if (isKeyPressed && keyCode === RIGHT_ARROW) {
playerX = playerX + 5;
}
if (isKeyPressed && keyCode === LEFT_ARROW) {
playerX = playerX - 5;
}
fill(0, 255, 0);
ellipse(playerX, playerY, 50, 50);
fill(255, 0, 0);
ellipse(aiX, aiY, 50, 50);
let offsetX = playerX - aiX;
let offsetY = playerY - aiY;
// pythagorean theorem: given a right triangle, the length of the
// hypotenuse is the square root of side A squared plus side B squared
let length = sqrt(offsetX * offsetX + offsetY * offsetY);
offsetX = offsetX / length;
offsetY = offsetY / length;
// The total distance moved when incrementing will now be 1
aiX += offsetX;
aiY += offsetY;
if (dist(playerX, playerY, aiX, aiY) < 50) {
console.log("GAMEOVER");
reset();
}
}
function reset() {
playerX = 200;
playerY = 200;
aiX = 200;
aiY = 15;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
However, since you asked about the trigonometry, here's how the original example works:
The atan2 function, which implements the inverse tangent function (a.k.a arctangent), takes the vertical offset between two points and the horizontal offset between the two points, and returns the angle of the line between the two points relative to some reference direction (the positive X direction). This is the inverse of the tangent function which takes an angle, and returns the ratio of the opposite to the adjacent sides of a right triangle with that angle. The reason for using atan2 which takes the two offsets separately vs. the atan function which takes the ratio as a single value, is that atan will not return correct angles when the x offset is negative.
Now, once you have the angle of a line from the ai position to the player position, you can use other trigonometric functions to convert back to offsets: namely sine and cosine (i.e. sin and cos). The sine function takes an angle and returns the ratio of the opposite side of a right triangle with that angle and its hypotenuse. The cosine function takes an angle and returns the ratio of the adjacent side of a right triangle with that angle and its hypotenuse. So if you use sin(angle) as the vertical offset to move by, and cos(angle) as the horizontal offset, then you are moving in the direction of angle by an offset of 1.
To better understand all of this I recommend you watch the first few chapters of The Nature of Code by Daniel Shiffman.
I also think this p5.js sketch by spencer eastcott is helpful for visualizing these concepts.

Phaser Scrollable Text Box Tutorial not working on mobile

I recreated the scrolling text box tutorial in my game. However, it is running a bit glitchy on mobile. For example, if I swipe up, the text first goes down for a second and then follows my finger up. You’ll see the problem if you open the tutorial on mobile. Any thoughts? I copied my code below.
var graphics = scene.make.graphics();
graphics.fillRect(x, y + 10, width, height - 20);
var mask = new Phaser.Display.Masks.GeometryMask(scene, graphics);
var text = scene.add.text(x + 20, y + 20, content, {
fontFamily: 'Assistant',
fontSize: '28px',
color: '#000000',
wordWrap: { width: width - 20 }
}).setOrigin(0);
text.setMask(mask);
var minY = height - text.height - 20;
if (text.height <= height - 20) {
minY = y + 20;
}
// The rectangle they can 'drag' within
var zone = scene.add.zone(x, y - 3, width, height + 6).setOrigin(0).setInteractive({useHandCursor: true});
zone.on('pointermove', function (pointer) {
if (pointer.isDown) {
text.y += (pointer.velocity.y / 10);
text.y = Phaser.Math.Clamp(text.y, minY, y + 20);
}
});
I had the same issue. My solution is using "pointer.y" instead of "pointer.velocity.y".
Here is my code:
var previousPointerPositionY;
var currentPointerPositionY;
zone.on('pointerdown', function (pointer) {
previousPointerPositionY = pointer.y;
});
zone.on('pointermove', function (pointer) {
if (pointer.isDown) {
currentPointerPositionY = pointer.y;
if(currentPointerPositionY > previousPointerPositionY){
text.y += 5;
} else if(currentPointerPositionY < previousPointerPositionY){
text.y -= 5;
}
previousPointerPositionY = currentPointerPositionY;
text.y = Phaser.Math.Clamp(text.y, -360, 150);
}
});

FabricJS Update Bounding Box

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.

Frame rate drops / efficiency problem in three.js [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 4 years ago.
Improve this question
Upon running there is a slow but consistent drop in fps. I have tried to identify the responsible function and it seems to be that:
updatepoints() and rotateTriangle() seem to be the main culprits but it's clear I have misunderstood something or used an inefficient means of calculating something somewhere
Upon further inspection using browser tools it seems to be an array and an object that are filling up the memory which I'm guessing is what is causing the frame drops.
I have also noticed that the buffer in the performance tab for the browser tools is filling up
I know bufferGeometry is the more efficient means of creating objects but I'd still like to know the cause the performance issues
Sorry to just dump code but I feel as though it'll be something obvious.
Any advice or ways of going about finding the problem and solution would be greatly appreciated
//every scene needs these
var scene, camera, renderer, controls;
//links div with canvas
var canvas = document.getElementById('canvas');
// What I need are number of particles and the length the curve goes to be uncoupled
// Each part of degree array serves one particles
// If I added a factor so:
// factor * coord *
//creating particles
var particleCount = 360;
var particles = [];
var particles2 = [];
var particles3 = [];
var SPEED = 0.01;
var radians, y, x;
var centerX = 0;
var centerY = 0;
var radius = 231.84;
var pointPositions=[];
var vupdateXvertices, updateYvertices, updateXvertices2, updateYvertices2,
updateXvertices3, updateYvertices3;
var pivot1;
var parent;
var pointsX = [];
var pointsY = [];
var particleMaterial = new THREE.MeshBasicMaterial({
color: 0x7a7a7a,
transparent: true,
opacity: 0.8
});
init();
animate();
function init() {
scene = new THREE.Scene();
//setup camera for scene
//PerspectiveCamera(fov, aspect, near, far [In terms of camera frustum plane])
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 1000;
//setup renderer for scene (generation of whatever you've made)
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0x31AED1, 1);
renderer.setSize( window.innerWidth, window.innerHeight );
//OrbitControls(Camera, HTMLDOMElement)
controls = new THREE.OrbitControls( camera, renderer.domElement );
// Set to true to enable damping (inertia), which can be used to give a sense
//of weight to the controls. Default is false.
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = false;
console.log("Called");
fillSceneWithParticles();
fillSceneWithShapes();
canvas.appendChild( renderer.domElement );
renderer.render( scene, camera );
}
function fillSceneWithParticles() {
var particleGeometry = new THREE.SphereGeometry(3, 32, 32);
parent = new THREE.Object3D();
scene.add(parent);
for (var i = 0; i < particleCount; i++) {
particles[i] = new THREE.Mesh( particleGeometry, particleMaterial );
particles[i].position.x = 0;
particles[i].position.y = 0;
particles[i].position.z = (0);
particles2[i] = new THREE.Mesh( particleGeometry, particleMaterial );
particles2[i].position.x = (200);
particles2[i].position.y = (-115.57);
particles2[i].position.z = (0);
particles3[i] = new THREE.Mesh( particleGeometry, particleMaterial );
particles3[i].position.x = (0);
particles3[i].position.y = (231.84);
particles3[i].position.z = (0);
scene.add(particles[i]);
scene.add(particles2[i]);
scene.add(particles3[i]);
}
}
function fillSceneWithShapes() {
//Add a 2d Triangle W centre = 200, 115.57
var geometry = new THREE.Geometry();
geometry.vertices.push( new THREE.Vector3(-200, -115.57, 0));
geometry.vertices.push( new THREE.Vector3( 200, -115.57, 0 ));
geometry.vertices.push( new THREE.Vector3( 0, 231.84, 0 ));
geometry.vertices.push( new THREE.Vector3( -200, -115.57, 0 ));
var material = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 10 } );
line = new THREE.Line( geometry, material );
scene.add(line);
}
function rotateTriangle() {
var geom = line.geometry.clone();
geom.applyMatrix(line.matrix);
updateXvertices = geom.vertices[0].x;
//The circle that we use to place our points
var centerX = 0;
var centerY = 0;
var radius = 231.84;
for(var degree = 90; degree < 450; degree++){
var radians = degree * Math.PI/180;
var x = centerX + radius * Math.cos(radians);
var y = centerY + radius * Math.sin(radians);
pointsX[degree - 90] = x;
pointsY[degree - 90] = y;
}
}
function updatePoints() {
//link counter with number of degrees initially created
//These are intialised because V1 = 120 degrees from V0 and V2 = 240 degrees
var counter = 120;
var counter2 = 240;
var zCounter = 0;
var curveFactor = 1;
var material = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 10 } );
var secondTriangle = new THREE.Geometry();
for (var i = 0; i < particleCount; i++) {
parent.add(particles[i]);
//Plot points around the circle relative to vertices of triangle
particles[i].position.x = (pointsX[i]);
particles[i].position.y = (pointsY[i]);
particles[i].position.z = zCounter * curveFactor;
//If array index out of bounds then loop back to the start of array
//i.e. Go back around the circle relative to the triangle vertices
parent.add(particles2[i]);
if (counter == 360) {
counter = 0;
}
particles2[i].position.x = (pointsX[counter]);
particles2[i].position.y = (pointsY[counter]);
particles2[i].position.z = zCounter * curveFactor;
counter++;
if (counter2 == 360) {
counter2 = 0;
}
parent.add(particles3[i]);
particles3[i].position.x = (pointsX[counter2]);
particles3[i].position.y = (pointsY[counter2]);
particles3[i].position.z = zCounter * curveFactor;
counter2++;
zCounter++;
}
//Give the second triangle the position of the last particles in array
secondTriangle.vertices.push( new THREE.Vector3(particles[particleCount-1].position.x, particles[particleCount-1].position.y, particles[particleCount-1].position.z ));
secondTriangle.vertices.push( new THREE.Vector3(particles2[particleCount-1].position.x, particles2[particleCount-1].position.y, particles2[particleCount-1].position.z ));
secondTriangle.vertices.push( new THREE.Vector3(particles3[particleCount-1].position.x, particles3[particleCount-1].position.y, particles3[particleCount-1].position.z ));
secondTriangle.vertices.push( new THREE.Vector3(particles[particleCount-1].position.x, particles[particleCount-1].position.y, particles[particleCount-1].position.z ));
line1 = new THREE.Line( secondTriangle, material );
scene.add(line1);
parent.add(line1);
}
function animate() {
requestAnimationFrame( animate );
controls.update();
rotateTriangle();
updatePoints();
line1.rotation.z -= SPEED *2;
line.rotation.z -= SPEED *2;
parent.rotation.z -= SPEED *2;
renderer.render( scene, camera );
}
In retrospect it seems obvious what the problem was.
Since I had geometry.vertices.push inside my animate loop it was continuously pushing new Vectors to a buffer.
I just had to move the pushing of those vertices and that solved any frame rate and memory problems I was having

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();

Resources