Zoom in and out : canvas offset - fabricjs

I'm working on a zoom functionnality like this :
public wheelEventHandler(ev) {
var pointer = this.canvas.getPointer(ev.e);
var posx = pointer.x;
var posy = pointer.y;
if (ev.wheelDelta > 0) {
//zoom in
let valeurZoom = this.canvas.getZoom() * 1.1 <= this.maxZoom ? this.canvas.getZoom() * 1.1 : this.maxZoom;
this.canvas.zoomToPoint(new fabric.Point(posx, posy), valeurZoom);
}
else {
//zoom out
let valeurZoom = this.canvas.getZoom() / 1.1 >= 1 ? this.canvas.getZoom() / 1.1 : 1;
this.canvas.zoomToPoint(new fabric.Point(posx, posy), valeurZoom);
}
}
Problem is when i zoom in, and then zoom out, the initial view have an offset, and i don't know what to do, when my zoom is back to 1, i want that canvas shows exactly what it showed before, with image centered and no offset.
How can i do?
this is what i have in the begening and what i want when zoom is back to 1
this is what i have when i zoom back to 1 and i don't want the offset in red

Lempkin,
When you zoom out to initial zoom (to 1) try use this functionality:
var centerOfCanvas = new fabric.Point(canvas.getWidth() / 2, canvas.getHeight() / 2);
canvas.zoomToPoint(centerOfCanvas , 1);
canvas.renderAll();
When you want to zoom out on a center all the time use this logic:
var centerOfCanvas = new fabric.Point(canvas.getWidth() / 2, canvas.getHeight() / 2);
canvas.zoomToPoint(centerOfCanvas , canvas.getZoom() / 1.1);
canvas.renderAll();
If you want to zoom out/zoom in in the mouse position use your logic, but when you zoom is equal to 1 reset to center position of the mouse.
Reset to default:
canvas.viewportTransform = [1,0,0,1,0,0]

Related

UIScrollView is stopping too soon

I'm using a scrollview to make a image gallery for my app and I have it mostly working. it'll allow me to scroll through the images one by one but the very last image always get cut off and I'm not sure why.
this is the bulk of the operation:
var idx = 0;
foreach (var mediaItem in _mediaItems)
{
var xPosition = UIScreen.MainScreen.Bounds.Width * idx;
var imageView = new UIImageView();
imageView.SetImage(new NSUrl(mediaItem), UIImage.FromBundle("image_placeholder"));
imageView.Frame = new CGRect(xPosition, 0, svGallery.Frame.Width + 50, svGallery.Frame.Height);
imageView.ContentMode = UIViewContentMode.ScaleAspectFit;
svGallery.ContentSize = new CGSize
{
Width = svGallery.Frame.Width * (idx + 1)
};
svGallery.AddSubview(imageView);
idx++;
}
minus that flaw, this works perfectly and as I expect it to.
From shared code , the Width of ContenSize is:
Width = svGallery.Frame.Width * (idx + 1)
However, each Width(svGallery.Frame.Width + 50) of ImageView is greater than vGallery.Frame.Width:
imageView.Frame = new CGRect(xPosition, 0, svGallery.Frame.Width + 50, svGallery.Frame.Height);
Therefore, the actually Width of ContenSize can not contains all the ImageView's Content. And if the number of ImageView is larger, the last picture will be cut off more.
You can modif the Width of ContentSize as follow to check whether it works:
svGallery.ContentSize = new CGSize
{
Width = (svGallery.Frame.Width + 50) * (idx + 1)
};

scale SVG pathPoints

I am scaling a polygon and set the actual scaled points into the pathArray
const pointsCal = this.findPoints(allocatedTable.tableType.shape.pathArray);//calculating max x,y min x,y of pathArray
const diameterX = (pointsCal.highX - pointsCal.lowX)/2;
const diameterY = (pointsCal.highY - pointsCal.lowX)/2;
const scalex = (diameterX + this.settings.tableTableSpace) / diameterX;
const scaleY = (diameterY + this.settings.tableTableSpace) / diameterY;
pathArray.forEach((point) => {
if (point.command !== 'z') {
point.x -= tableCenterPoint.x;
point.y -= tableCenterPoint.y;
point.x *= scalex;
point.y *= scaleY;
point.x += tableCenterPoint.x;
point.y += tableCenterPoint.y;[enter image description here][1]
}
});
but for the regular rectangle it is working properly but for the rotated Shapes it is not scling propely
I think I had made a mistake in logic in calculating scale X and scaleY value
Why the divide by 2?
Try something like this:
const width = pointsCal.highX - pointsCal.lowX;
const height = pointsCal.highY - pointsCal.lowY;
const scalex = this.settings.tableTableSpace / width;
const scaleY = this.settings.tableTableSpace / height;
If that doesn't work, then you'll need to provide a minimal workable example
Update
I'm still not 100% sure what you want. But looking at the code, I assume you are wanting to scale the original shape so that it fills the SVG. But also allowing for some padding around it.
If so, you'll want to do something like this:
DrawScalledRectangle() {
// Get the size of the original polygon
const bbox = this.tableGroup.getBBox();
// Get the size of the <svg> element.
// This will be the value at the time this function is run. But the <svg> has width
// and height of "100%" so it may change if the window is resized.
const mainSvg = document.getElementById("mainSVG");
const svgWidth = mainSvg.clientWidth;
const svgHeight = mainSvg.clientHeight;
// The scale will be svgSize / originalSize (but we subtract the padding from the svgSize first)
const scaleX = (svgWidth - this.tableTableSpace * 2) / bbox.width;
const scaleY = (svgHeight- this.tableTableSpace * 2) / bbox.height;
this.pathArray.forEach(point => {
if (point.command !== "z") {
// New point location = padding + (oldPoint - shapePosition) * scale
point.x = this.tableTableSpace + (point.x - bbox.x) * scaleX;
point.y = this.tableTableSpace + (point.y - bbox.y) * scaleY;
}
});
console.log(this.pathArray);
...snip...
}
https://stackblitz.com/edit/angular-thb9w5?file=src/app/app.component.ts

fabricjs programmatically pan canvas on mobile browser

I have a website with fabric and it renders fine a pdf(as images). with mobile browser it displays fine and I enabled allowtouchscrolling and can pan the image (almost equal to scroll but not as effective as scrolling) . I have annotations on the image rendered which user has to respond. as of now its tedious to find each annotation object. Is there a way I can programmatically pan the fabric canvas centered to a specific x,y?
thanks
prem
Pan canvas so that [0,0] appears in center of viewport.
To achieve this do canvas.absolutePan(new fabric.Point(-canvas.getWidth() / 2, -canvas.getHeight() / 2)
And then additionally offset canvas to your object coordinates (in my example I use [left,top] + [halfWidth, halfHeight] to calc offset of object center.
Thus conclude making canvas.absolutePan to [-canvas.getWidth() / 2 + obj.left + obj.width / 2, -canvas.getHeight() / 2 + obj.top + obj.height / 2
Working example you may find here: http://jsfiddle.net/mmalex/2rsevdLa/
function panTo(canvas, obj) {
let w = canvas.getWidth();
let h = canvas.getHeight();
let targetX = obj.left + obj.width / 2;
let targetY = obj.top + obj.height / 2;
canvas.absolutePan(new fabric.Point(-w/2+targetX, -h/2+targetY))
}
function recenterCanvas() {
panTo(canvas, refRect);
canvas.bringToFront(refRect);
canvas.renderAll();
}

How to center scaling of a JointJS paper

I've implemented the scaling of a paper and it works great.
I linked it to the scrolling of the mousewheel, but I still encounter one problem: In the API the scale function is defined as scale paper.scale(sx, sy, [ox, oy]) and I figured that ox and oy can center the zooming to a specific position. In my case this position should be the pointer. But although I hand over the coordinates (offsetX and offsetY of the mouse event), it has absolutly no effect.
Can someone give me an example of how to use ox and oy?
Don't forget to transform the mouse coordinates into the viewport coordinate system first.
function offsetToLocalPoint(offsetX, offsetY, paper) {
var svgPoint = paper.svg.createSVGPoint();
svgPoint.x = offsetX;
svgPoint.y = offsetY;
var offsetTransformed = svgPoint.matrixTransform(paper.viewport.getCTM().inverse());
return offsetTransformed
}
And reset the previous viewport translate transformation before you call paper.scale() with the origin [ox, oy] of scale transformation specified. You can see this in the mousewheel event handler example below.
function onMouseWheel(e) {
e.preventDefault();
e = e.originalEvent;
var delta = Math.max(-1, Math.min(1, e.wheelDelta)) / SPEED;
var newScale = V(paper.viewport).scale().sx + delta;
if (newScale > MIN_SCALE && newScale < MAX_SCALE) {
paper.setOrigin(0, 0); // reset the previous 'translate'
var p = offsetToLocalPoint(e.offsetX, e.offsetY);
paper.scale(newScale, newScale, p.x, p.y);
}
}
A cross-browser version fiddle here.

How to animate rectangle to fixed width in steps with createjs?

I'm trying to create loading bar for my game. I create basic rectangle and added to the stage and caluclated size acording to the number of files so I get fixed width. Everything works, but for every step (frame) it creates another rectangle, how do I get only one object?
this is my code:
function test(file) {
r_width = 500;
r_height = 20;
ratio = r_width / manifest.length;
if (file == 1) {
new_r_width = 0
// Draw
r = new createjs.Shape();
r_x = (width / 2) - (r_width / 2);
r_y = (height / 2) - (r_height / 2);
new_r_width += ratio;
r.graphics.beginFill("#222").drawRect(r_x, r_y, new_r_width, r_height);
stage.addChild(r);
} else {
stage.clear();
new_r_width += ratio;
r.graphics.beginFill("#" + file * 100).drawRect(r_x, r_y + file * 20, new_r_width, r_height);
stage.addChild(r);
}
stage.update();
}
https://space-clicker-c9-zoranf.c9.io/loading/
If you want to redraw the rectangle, you will have to clear the graphics first, and then ensure the stage is updated. In your code it looks like you are clearing the stage, which is automatically handled by the stage.update() unless you manually turn off updateOnTick.
There are some other approaches too. If you just use a rectangle, you can set the scaleX of the shape. Draw your rectangle at 100% of the size you want it at, and then scale it based on the progress (0-1).
r.scaleX = 0.5; // 50%
A new way that is supported (only in the NEXT version of EaselJS, newer than 0.7.1 in GitHub), you can save off the drawRect command, and modify it.
var r = new createjs.Shape();
r.graphics.beginFill("red");
var rectCommand = r.graphics.drawRect(0,0,100,10).command; // returns the command
// Later
rectCommand.w = 50; // Modify the width of the rectangle
Hope that helps!

Resources