Fabric.js: How to observe object:scaling event and update properties dynamically? - javascript

I'm trying to get the shape properties to dynamically update when the shape is being scaled.
Here's a fiddle: http://jsfiddle.net/anirudhrantsandraves/DAjrp/
The console log commands:
console.log('Width = '+scaledObject.currentWidth);
console.log('Height = '+scaledObject.currentHeight);
are supposed to dynamically display the height and width of the shape as it is being scaled.
The properties remain the same in the console when the shape gets scaled. However, when I select the object again and scale it, the previous values of the properties are displayed.
Is there a way to make this dynamic?

getWidth() and getHeight() are used to get the current width and height in Fabric.js.
So in "object:scaling" event:
canvas.on('object:scaling', onObjectScaled);
function onObjectScaled(e)
{
var scaledObject = e.target;
console.log('Width = '+scaledObject.getWidth());
console.log('Height = '+scaledObject.getHeight());
}
will serve your purpose.
Updated fiddle — http://jsfiddle.net/DAjrp/2/

Just in case, if you wanted to get the scaled height
canvas.on("object:scaling", (e) => {
canvas.getActiveObjects().forEach((o) => {
// if it's scaled then just multiple the height by scaler
const objHeight = o.scaleY ? o.height * o.scaleY : o.height;
// ...
});
});

Related

How to ensure uploaded SVG has width and height Attributes

My users can upload image files, which could be SVGs.
I need to make sure that all SVGs have a width and height attribute for something that's occurring later on.
If I have the SVG as a file (via an input type="file") how can I add a width and height to it if it is missing?
I ended up doing the following, though Im sure it could be improved/done in a much better way
let svgReader = new FileReader();
svgReader.onload = function (e) {
let svg = $(e.target.result);
for(let i =0;i<svg.length;i++) {
if (svg[i] instanceof SVGElement) {
svg = $(svg[i]);
break;
}
}
let width = svg.attr("width");
let height = svg.attr("height");
if (height == null || height == undefined) {
svg.attr("height", 300);
}
if (width == null || width == undefined) {
svg.attr("height", 300);
}
let svgFile = new XMLSerializer().serializeToString(svg[0]);
let new file = new File([svgFile], files[index].name, {type: "image/svg+xml"});
};
svgReader.readAsText(files[0]);
I had to go through the SVG to find an instance of SVG element, as some of the SVGs I tested with had additional tags or comments that messed it up otherwise. Also, the 300 value for width and height was just made up, but seems to be ok, probably could have used the view box dimensions instead, but it works for me

Get width of selected layer with Sketch API

Writing my first Sketch plugin and I'm trying to get the width of a selected layer.
export default function(context) {
const selectedLayers = context.selection;
const selectedCount = selectedLayers.length;
if (selectedCount === 0) {
context.document.showMessage('Please select a circle shape layer');
} else {
selectedLayers.forEach(function (layer) {
log(layer.frame.width);
})
}
}
The log shows:
<MOUndefined: 0x6040000048f0>
The documentation states that the frame of the layer is a Rectangle and that a Rectangle has x, y, width and height properties. So I don't understand why I'm getting undefined.
I tried log(layer.frame) and I do get:
<MOMethod: 0x60400263b420 : target=0x7f9dbf5b8ee0<MSShapeGroup: 0x7f9dbf5b8ee0> Oval (691540C6-7B18-4752-9BA6-A3A298754C9A), selector=frame>
So I'm targetting it right.
try with
layer.frame().width()

Paper.js Subraster Selecting Wrong Area

I'm working in a Paper.js project where we're essentially doing image editing. There is one large Raster. I'm attempting to use the getSubRaster method to copy a section of the image (raster) that the user can then move around.
After the raster to edit is loaded, selectArea is called to register these listeners:
var selectArea = function() {
if(paper.project != null) {
var startDragPoint;
paper.project.layers[0].on('mousedown', function(event) { // TODO should be layer 0 in long run? // Capture start of drag selection
if(event.event.ctrlKey && event.event.altKey) {
startDragPoint = new paper.Point(event.point.x + imageWidth/2, (event.point.y + imageHeight/2));
//topLeftPointOfSelectionRectangleCanvasCoordinates = new paper.Point(event.point.x, event.point.y);
}
});
paper.project.layers[0].on('mouseup', function(event) { // TODO should be layer 0 in long run? // Capture end of drag selection
if(event.event.ctrlKey && event.event.altKey) {
var endDragPoint = new paper.Point(event.point.x + imageWidth/2, event.point.y + imageHeight/2);
// Don't know which corner user started dragging from, aggregate the data we have into the leftmost and topmost points for constructing a rectangle
var leftmostX;
if(startDragPoint.x < endDragPoint.x) {
leftmostX = startDragPoint.x;
} else {
leftmostX = endDragPoint.x;
}
var width = Math.abs(startDragPoint.x - endDragPoint.x);
var topmostY;
if(startDragPoint.y < endDragPoint.y) {
topmostY = startDragPoint.y;
} else {
topmostY = endDragPoint.y;
}
var height = Math.abs(startDragPoint.y - endDragPoint.y);
var boundingRectangle = new paper.Rectangle(leftmostX, topmostY, width, height);
console.log(boundingRectangle);
console.log(paper.view.center);
var selectedArea = raster.getSubRaster(boundingRectangle);
var selectedAreaAsDataUrl = selectedArea.toDataURL();
var subImage = new Image(width, height);
subImage.src = selectedAreaAsDataUrl;
subImage.onload = function(event) {
var subRaster = new paper.Raster(subImage);
// Make movable
subRaster.onMouseEnter = movableEvents.showSelected;
subRaster.onMouseDrag = movableEvents.dragItem;
subRaster.onMouseLeave = movableEvents.hideSelected;
};
}
});
}
};
The methods are triggered at the right time and the selection box seems to be the right size. It does indeed render a new raster for me that I can move around, but the contents of the raster are not what I selected. They are close to what I selected but not what I selected. Selecting different areas does not seem to yield different results. The content of the generated subraster always seems to be down and to the right of the actual selection.
Note that as I build the points for the bounding selection rectangle I do some translations. This is because of differences in coordinate systems. The coordinate system where I've drawn the rectangle selection has (0,0) in the center of the image and x increases rightward and y increases downward. But for getSubRaster, we are required to provide the pixel coordinates, per the documentation, which start at (0,0) at the top left of the image and increase going rightward and downward. Consequently, as I build the points, I translate the points to the raster/pixel coordinates by adding imageWidth/2 and imageHeight/2`.
So why does this code select the wrong area? Thanks in advance.
EDIT:
Unfortunately I can't share the image I'm working with because it is sensitive company data. But here is some metadata:
Image Width: 4250 pixels
Image Height: 5500 pixels
Canvas Width: 591 pixels
Canvas Height: 766 pixels
My canvas size varies by the size of the browser window, but those are the parameters I've been testing in. I don't think the canvas dimensions are particularly relevant because I'm doing everything in terms of image pixels. When I capture the event.point.x and event.point.y to the best of my knowledge these are image scaled coordinates, but from a different origin - the center rather than the top left. Unfortunately I can't find any documentation on this. Observe how the coordinates work in this sketch.
I've also been working on a sketch to illustrate the problem of this question. To use it, hold Ctrl + Alt and drag a box on the image. This should trigger some logging data and attempt to get a subraster, but I get an operation insecure error, which I think is because of security settings in the image request header. Using the base 64 string instead of the URL doesn't give the security error, but doesn't do anything. Using that string in the sketch produces a super long URL I can't paste here. But to get that you can download the image (or any image) and convert it here, and put that as the img.src.
The problem is that the mouse events all return points relative to 0, 0 of the canvas. And getSubRaster expects the coordinates to be relative to the 0, 0 of the raster item it is extracting from.
The adjustment needs to be eventpoint - raster.bounds.topLeft. It doesn't really have anything to do with the image width or height. You want to adjust the event points so they are relative to 0, 0 of the raster, and 0, 0 is raster.bounds.topLeft.
When you adjust the event points by 1/2 the image size that causes event points to be offset incorrectly. For the Mona Lisa example, the raster size (image size) is w: 320, h: 491; divided by two they are w: 160, h: 245.5. But bounds.topLeft of the image (when I ran my sketch) was x: 252.5, y: 155.5.
Here's a sketch that shows it working. I've added a little red square highlighting the selected area just to make it easier to compare when it's done. I also didn't include the toDataURL logic as that creates the security issues you mentioned.
Here you go: Sketch
Here's code I put into an HTML file; I noticed that the sketch I put together links to a previous version of the code that doesn't completely work.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Rasters</title>
<script src="./vendor/jquery-2.1.3.js"></script>
<script src="./vendor/paper-0.9.25.js"></script>
</head>
<body>
<main>
<h3>Raster Bug</h3>
<div>
<canvas id="canvas"></canvas>
</div>
<div id="position">
</div>
</main>
<script>
// initialization code
$(function() {
// setup paper
$("#canvas").attr({width: 600, height: 600});
var canvas = document.getElementById("canvas");
paper.setup(canvas);
// show a border to make range of canvas clear
var border = new paper.Path.Rectangle({
rectangle: {point: [0, 0], size: paper.view.size},
strokeColor: 'black',
strokeWidth: 2
});
var tool = new paper.Tool();
// setup mouse position tracking
tool.on('mousemove', function(e) {
$("#position").text("mouse: " + e.point);
});
// load the image from a dataURL to avoid CORS issues
var raster = new paper.Raster(dataURL);
raster.position = paper.view.center;
var lt = raster.bounds.topLeft;
var startDrag, endDrag;
console.log('rb', raster.bounds);
console.log('lt', lt);
// setup mouse handling
tool.on('mousedown', function(e) {
startDrag = new paper.Point(e.point);
console.log('sd', startDrag);
});
tool.on('mousedrag', function(e) {
var show = new paper.Path.Rectangle({
from: startDrag,
to: e.point,
strokeColor: 'red',
strokeWidth: 1
});
show.removeOn({
drag: true,
up: true
});
});
tool.on('mouseup', function(e) {
endDrag = new paper.Point(e.point);
console.log('ed', endDrag);
var bounds = new paper.Rectangle({
from: startDrag.subtract(lt),
to: endDrag.subtract(lt)
});
console.log('bounds', bounds);
var sub = raster.getSubRaster(bounds);
sub.bringToFront();
var subData = sub.toDataURL();
sub.remove();
var subRaster = new paper.Raster(subData);
subRaster.position = paper.view.center;
});
});
var dataURL = ; // insert data or real URL here
</script>
</body>
</html>

How to resize canvas with javascript to pixel amount

I am trying to resize the canvas width to a given pixel amount like this:
if (condition==true) {
canvasVar.width = pixel amount;
}
The if statement is executing, but the canvas is resizing weird. I've tried a number of methods:
var canvasVar = document.getElementById('canvasId');
var contextVar = canvasVar.getContext('2d');
//all numbers in pixels.
canvasVar.style.width = 20; //doesn't do anything.
canvasVar.width = 20; //resizes the HEIGHT!!!
contextVar.canvas.width = 20; //also resizes height.
The canvas width/height values after method 2 & 3 are appiled are 656 (normal value) & 1405 (normal value = 328).
NOTE: I am setting canvas default width/height with CSS and I am also using the Yii PHP framework.
Thanks.
EDIT: I've also tried to follow 20 by the px extension. Gives an error saying 'unexpected identifier'.
A canvas has "2" height and width properties. One of them specifiesthe resolution of the canvas, the other the size
canvasVar[0].width = 20; // canvas consists of 20 virtual px in width
canvasVar[0].style.width = '400 px' // canvas gets a width of 400 px

svg appending text element - gives me wrong width

i'm appending a text element to a svg via javascript. After appending i wanna set x and y coordinate, however, it returns me the wrong width of the text element when using it to calculate x.
Interesting:
In Chrome, when actualize the page via F5 or button it returns wrong width, when pressing enter in the adress bar, the width is right - strange!
Here is the small code:
var capt = document.createElementNS("http://www.w3.org/2000/svg", "text");
// Set any attributes as desired
capt.setAttribute("id","capt");
capt.setAttribute("font-family","Righteous");
capt.setAttribute("font-size","30px");
capt.setAttribute("fill", "rgb(19,128,183)");
var myText = document.createTextNode(this.options.captTxt);
capt.appendChild(myText);
this.elements.jSvgElem.append(capt);
capt.setAttribute("x", this.options.windowWidth-this.options.spacer-document.getElementById("capt").offsetWidth);
capt.setAttribute("y", this.options.captY+$('#capt').height());
OK, the problem seems to be that the browser doesn't calculate the correct width when using an other font. Not setting a font results in a correct width.
I solved the problem by setting the reference point ("alignment-point") to the upper right corner ot the text element by setting attributes:
capt.setAttribute("text-anchor", "end");
capt.setAttribute("alignment-baseline", "hanging");
This way i do not have to subtract the width and add the height of the element!
There is a bug:http://code.google.com/p/chromium/issues/detail?id=140472
it just pre init some functions that calculates text width so you should call this function before(i'm sure that there is several extra lines that can be deleted):
fixBug = function () {
var text = makeSVG("text", { x: 0, y: 0, fill: "#ffffff", stroke: '#ffffff'});
text.textContent = "";
var svg = $("svg")[0];
svg.appendChild(text);
var bbox = text.getBBox();
var Twidth = bbox.width;
var Theight = bbox.height;
svg.removeChild(text);
}
$("svg") - Jquery selector

Categories

Resources