fabricjs programmatically pan canvas on mobile browser - fabricjs

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

Related

Zoom in and out : canvas offset

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]

OpenSCAD: inner curved edges between 2 circles

I'm not sure what to search for or how to ask the question as I can't draw. Please bear with me.
If I have a rectangle with circular end caps. I want to remove some of the edges of the rectangle so there is a smooth path all round. Kinda like of you were to stretch the ends, the middle gets thinner.
I was trying to work out the chord of a larger, outer circle until I got stuck trying to work out where the circles should touch.
I can see some relationships for trigonometry, but my brain just won't go the extra mile.
Can anyone please help point me in the right direction.
Thanks.
Here is the answer:
// Small value for CSG
Delta = 0.01;
2Delta = 2 * Delta;
$fa=1; $fs=$fa;
module roudedArm(xl=50, yt=10, zh=5, in=2, bh=0.8) {
EndRadius = yt/2; // size of outer ends
EndSpacing = xl-yt; // distance between end point radii
ArmConcavity = in; // how much in does it go in on each side
ArmThickness = zh; // height in z
// Negative curve to narrow the Arm (calculated by pythagoras)
ArmCurveRadius = (pow((EndSpacing / 2), 2) - 2 * EndRadius * ArmConcavity + pow(ArmConcavity, 2)) / (2 * ArmConcavity);
// The orthogonal distance between the middle of the Arm the point it touches the round pillar sections
ArmSectionLength = (EndSpacing / 2) * ArmCurveRadius / (ArmCurveRadius + EndRadius);
// end points
lbxcylinder(r=EndRadius, h=ArmThickness);
translate([EndSpacing, 0, 0]) lbxcylinder(r=EndRadius, h=ArmThickness);
// inner curve
difference()
{
translate([EndSpacing / 2 - ArmSectionLength, -EndRadius -ArmThickness, 0])
translate([ArmSectionLength, (EndRadius + ArmThickness),0])
lbxcube([ArmSectionLength * 2, 2 * (EndRadius + ArmThickness), ArmThickness], bh=bh);
// Cut out Arm curve
translate([EndSpacing / 2, ArmCurveRadius + EndRadius - ArmConcavity, -Delta])
lbxcylinder(r = ArmCurveRadius, h = ArmThickness + 2Delta, bh=-bh);
translate([EndSpacing / 2, -(ArmCurveRadius + EndRadius - ArmConcavity), -Delta])
lbxcylinder(r = ArmCurveRadius, h = ArmThickness + 2Delta, bh=-bh);
}
}
module lbxcube(size, bh=0.8) {
// don't support bevelling in demo
translate([-size[0]/2, -size[1]/2, 0]) cube(size);
}
module lbxcylinder(r, h, bh=0.8) {
// don't support bevelling in demo
cylinder(r=r, h=h);
}
roudedArm(xl=50, yt=10, zh=5, in=2, bh=0.8);
Thanks to Rupert and his Curvy Door Handle on Thingiverse.

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!

Best way to serve / produce silhoutte of the US States?

I'm responsible for delivering pages to display primary results for the US elections State by State. Each page needs a banner with an image of the State, approx 250px by 250px. Now all I need to do is figure out how to serve / generate those images...
I've dug into the docs / examples for Protovis and think I
could probably lift the State coordinate outlines- I would have to
manually transform the coordinate data to be justified and sized
properly (ick)
At the other end of the clever/brute spectrum is an enormous sprite
or series of sprites. Even with png 8 compression the file size of
a grid of 50 non-overlapping 250x250px sprites is a concern, and
sadly such a file doesn't seem to exist so I'd have to create it
from hand. Also unpleasant.
Who's got a better idea?
Answered: the right solution is to switch to d3.
What we hacked in for now:
drawStateInBox = function(box, state, color) {
var w = $("#" + box).width(),
h = $("#" + box).height(),
off_x = 0,
off_y = 0;
borders = us_lowres[state].borders;
//Preserve aspect ratio
delta_lat = pv.max(borders[0], function(b) b.lat) - pv.min(borders[0], function(b) b.lat);
delta_lng = pv.max(borders[0], function(b) b.lng) - pv.min(borders[0], function(b) b.lng);
if (delta_lat / h > delta_lng / w) {
scaled_h = h;
scaled_w = w * delta_lat / delta_lng;
off_x = (w - scaled_w) / 2;
} else {
scaled_h = h * delta_lat / delta_lng;
scaled_w = w;
off_y = (h - scaled_h) / 2;
}
var scale = pv.Geo.scale()
.domain(us_lowres[state].borders[0])
.range({x: off_x, y: off_y},
{x: scaled_w + off_x, y: scaled_h + off_y});
var vis = new pv.Panel(state)
.canvas(box)
.width(w)
.height(h)
.data(borders)
.add(pv.Line)
.data(function(l) l)
.left(scale.x)
.top(scale.y)
.fillStyle(function(d, l, c) {
return(color);
})
.lineWidth(0)
.strokeStyle(color)
.antialias(false);
vis.render();
};
d3 seems to have the capability to do maps similar to what you want. The example shows both counties and states so you would just omit the counties and then provide the election results in the right format.
There is a set of maps on 50states.com, e.g. http://www.50states.com/maps/alabama.htm, which is about 5KB. Roughly, then, that's 250KB for the whole set. Since you mention using these separately, there's your answer.
Or are you doing more with this than just showing the outline?

Resize image to one resolution

I have a bunch of images, with different resolution.
Also there is a mix of landscape and portrait pictures. I need to resize the images to one resolution (1024x768). If i have a portrait picture, the max height needs to be 768, and my landscape pictures has to have a max width of 1024.
The space that is over, has to be made black.
Right now i use mogrify -resize 1024x768 -verbose *.jpg
I know i can use 1024x!768 , but like i said i'm using different kind of pictures.
My exif information also doesn't contains information about if a picture is landscape or not.
I use ImageMagick for such tasks. When installed, you have the "convert" command, which is very common, and does your task easyly.
You will have to crop the image to get the same aspect ratio, then you can resize the image to get the desired resolution. Example code using nodejs (imagemagick command line tools):
var width = 166;
var height = 117;
var ratio_new = width/height;
var ratio_old = image_file.width_orig/image_file.height_orig;
var pixels_too_much = 0;
var geometry = '';
if (ratio_old > ratio_new)
{
config.debug && console.log ("remove horizontal pixel!");
pixels_too_much = parseInt(image_file.width_orig - (image_file.height_orig * ratio_new))-1;
geometry = parseInt(image_file.height_orig * ratio_new + 0.5) + 'x' + image_file.height_orig;
geometry += "+" + parseInt(pixels_too_much/2) + "+0\!";
}
else if (ratio_old < ratio_new)
{
config.debug && console.log ("remove vertikal pixel");
pixels_too_much = parseInt(image_file.height_orig - (image_file.width_orig / ratio_new));
geometry = image_file.width_orig + 'x' + (image_file.width_orig / ratio_new);
geometry += "+0+" + parseInt(pixels_too_much/2)+"\!";
}
im.convert([image_file.path, '-crop', geometry, '-resize', width + 'x' + height, thumb_path],function(){});

Resources