I have a slider which consists of iframes that are 1366px x 768px which I scale to fit on window resize. However, when 1366 is divided I can randomly get decimals on the actual width of the element which causes what I call as 'pixel breaking'.
Notice the while line on the second image. This is actually the second slide which is my problem. Example; 1366px becomes 1045.234234px so they don't line up properly.
I know I can also add a width by removing the decimals as parseInt(scaleAmount * 1366) but I don't think that can always be accurate with different resolutions.
Anything I can try to resolve or minimise this?
var $el = $(element);
var elHeight = 768;
var elWidth = 1366;
var $wrapper = $(parent);
function doResize(event, ui) {
var scale, origin;
scale = Math.min(
ui.size.width / elWidth,
ui.size.height / elHeight
);
$el.css({
'transform': "scale(" + scale + ")",
'-webkit-transform': "scale(" + scale + ")"
});
}
Since you're converting to a string, you can just trim off the decimal part of the number using scale.toFixed(0).
OK I think I've resolved it. I convert the transform scale to pixel value. Round up the pixel. And finally, convert the rounded pixel back to a transform scale. So the scaled pixel will always be an even number so therefore the pixels would not break anymore.
scale = Math.min(
ui.size.width / elWidth,
ui.size.height / elHeight
);
var scaleInPixels = scale * elWidth;
var evenPixel = 2 * Math.round(scaleInPixels / 2);
var finalScale = evenPixel / elWidth;
Related
I have a rectangular SVG object which is rotated via transform="rotate(45,0,0)". Using getBoundingClientRect() on the object gives the width and height of the bounding box which is not correct with the rotation.
I have searched and tried many calculations to get the original width and height taking off the rotation.
var rectangle = object.getBoundingClientRect()
var width = Math.sin(radian) * rectangle.height + Math.cos(radian) * rectangle.width
var height = Math.sin(radian) * rectangle.width + Math.cos(radian) * rectangle.height
And many other variations on this i have found, any help on the correct formula to use would be great. All i have is the values from getBoundingClientRect() and the radian.
I have a simple canvas on my page that looks like this:
The canvas is responsive so the size can increase and decrease depending on the screen you are looking at. What remains the same is the resolution of the result. This will always be scaled to a pre-set default of 1000x1000px.
This works with a scaling ratio.
Example: the canvas is 500x500 px on your screen, this means the scaling ratio is 0.5, if your screen is big enough to fit the 1000x1000 canvas on it. The ratio will be 1.0 and so on.
The canvas also has the option to add an image to it. Those images have to size accordingly to your screen size as well and just like the complete canvas, it will be resized to it's proper size before saving(1000x1000).
When you upload an image it is usually quite big on the canvas like so:
Right now the size of the image is too big to completely show on the canvas and at this point it's individual scaling ratio is 1.0 while the scale ratio of the canvas remains at 0.5.
If i want to resize the image so it fits nicely within the canvas I get the following :
To make sure the size of the image is not returned to it's default scale of 1.0 like when I uploaded it I added the following code :
canvas.on('object:modified', function (options) {
options.target.set({
width: options.target.getWidth(),
height: options.target.getHeight(),
scaleX: 1, scaleY: 1,
});
});
This will set the X and Y scale to 1 after resizing/modifying. This way every time you change it's size, that point will be the new 1.0 scale.
To scale all my objects i wrote the following function :
function scaleObjects()
{
// page has been resized therefore we recalculate the aspect ratio for the canvas.
$windowWidth = $(window).width();
$windowHeight = $(window).height();
//currentCanvasWidth = $windowWidth;
var PrevHeightRatio = canvas.getHeight() / canvasHeightDefault;
var PrevWidthRatio = canvas.getWidth() / canvasWidthDefault;
resizeCanvas();
var HeightRatio = canvas.getHeight() / canvasHeightDefault;
var WidthRatio = canvas.getWidth() / canvasWidthDefault;
var objects = canvas.getObjects();
for (var i = 0; i < objects.length; i++) {
objects[i].scaleX = WidthRatio;
objects[i].scaleY = HeightRatio;
var multiplierW = 1 / PrevWidthRatio;
var multiplierH = 1 / PrevHeightRatio;
var originalStartX = objects[i].left * multiplierW;
var originalStartY = objects[i].top * multiplierH;
objects[i].left = originalStartX * WidthRatio;
objects[i].top = originalStartY * HeightRatio;
objects[i].setCoords();
}
canvas.renderAll();
}
This will run every time a resize or a canvas save occurs.
The problem is that whenever I save or resize my canvas the current scale of the canvas gets applied to my images/objects. In this case my image is at a scale of 1.0 and my canvas at 0.5, saving or resizing will apply the 0.5 scale to the object and decrease its size. I would however like it to scale exactly like the rest of my canvas so nothing gets out of proportion.
How can i achieve this?
Here is an image of the canvas "After" resizing the page once :
Here is a jsfiddle : https://jsfiddle.net/L6hob1e4/2/
After some research and some testing i found the following solution.
I changed the for loop that scales the objects to this:
for (var i = 0; i < objects.length; i++) {
var previousH = (((objects[i].getHeight() / canvas.getHeight()) * canvasHeightDefault) * PrevHeightRatio);
var previousW = (((objects[i].getWidth() / canvas.getWidth()) * canvasWidthDefault) * PrevWidthRatio);
console.log(previousH + " - " + previousW);
var multiplierSizeH = 1 / PrevHeightRatio;
var multiplierSizeW = 1 / PrevWidthRatio;
var onMaxH = objects[i].getHeight() * multiplierSizeH;
var onMaxW = objects[i].getWidth() * multiplierSizeW;
objects[i].height = onMaxH * HeightRatio;
objects[i].width = onMaxW * WidthRatio;
var multiplierW = 1 / PrevWidthRatio;
var multiplierH = 1 / PrevHeightRatio;
var originalStartX = objects[i].left * multiplierW;
var originalStartY = objects[i].top * multiplierH;
objects[i].left = originalStartX * WidthRatio;
objects[i].top = originalStartY * HeightRatio;
objects[i].setCoords();
}
This will keep track of the size before and after the scaling which fixes the issue.
I am trying to scale/move an SVG path created with the Raphael api. I want the path to fit neatly within a container, no matter the size of the container. I have searched the reference, the web and I'm still struggling to get this to work.
If anyone can tell me why this isn't working, I would be very happy.
This fiddle shows you what I'm doing: http://jsfiddle.net/tolund/3XPxL/5/
JavaScript:
var draw = function(size) {
var $container = $("#container").empty();
$container.css("height",size+"px").css("width",size+"px");
var paper = Raphael("container");
var pathStr = "M11.166,23.963L22.359,17.5c1.43-0.824,1.43-2.175,"+
"0-3L11.166,8.037c-1.429-0.826-2.598-0.15-2.598,"+
"1.5v12.926C8.568,24.113,9.737,24.789,11.166,23.963z";
// set the viewbox to same size as container
paper.setViewBox(0, 0, $container.width(), $container.height(), true);
// create the path
var path = paper.path(pathStr)
.attr({ fill: "#000", "stroke-width": 0, "stroke-linejoin": "round", opacity: 1 });
// get the path outline box (may be different size than view box.
var box = path.getBBox();
// move the path as much to the top/left as possible within container
path.transform("t" + 0 + "," + 0);
// get the width/height based on path box relative to paper (same size as container)
var w = (paper.width) / box.width;
var h = (paper.height) / box.height;
// scale the path to the container (use "..." to compound transforms)
path.transform('...S' + w + ',' + h + ',0,0');
}
$(function() {
var currentSize = 30;
draw(currentSize);
$("#smaller").click(function(){
currentSize = currentSize < 10 ? currentSize : currentSize * 0.5;
draw(currentSize);
});
$("#bigger").click(function(){
currentSize = 300 < currentSize ? currentSize : currentSize * 2;
draw(currentSize);
});
});
HTML:
<button id="smaller">-</button>
<button id="bigger">+</button>
<div id="container" style="border: 1px #ddd solid; margin: 30px">
</div>
Thanks,
Torgeir.
I think your problem is a fundamental misunderstanding of what the viewbox is useful for. In your code, you're attempting to set the viewbox of the svg element so that it matches the coordinate space of the screen, and then transform the path to match that coordinate space. There's no technical reason you can't do this, but it does effectively take the "Scalable" out of "Scalable Vector Graphics." The entire point of the viewbox is to make the translation between the vector coordinate space and the screen relative.
The best way to solve your problem, then, is not to transform the path to match the SVG element, but to use the viewbox to let SVG's intrinsic scalability do this for you.
First things first: create your path so we have an object to work with. We don't care what the viewbox is at this point.
var pathStr = "..."; // The content of the path and its coordinates are completely immaterial
var path = paper.path(pathStr)
.attr({ fill: "#000", "stroke-width": 0, "stroke-linejoin": "round", opacity: 1 });
Now all we need to do is use the viewbox to "focus" the SVG on the coordinate space we're interested in.
var box = path.getBBox();
var margin = Math.max( box.width, box.height ) * 0.1; // because white space always looks nice ;-)
paper.setViewBox(box.x - margin, box.y - margin, box.width + margin * 2, box.height + margin * 2);
And that's it. The SVG (regardless of its size) will translate from the internal coordinates specified in the viewbox to its physical coordinates on screen.
Here's a fork of your fiddle as proof-of-concept.
I'm creating a Fabric.js based image editor, but I have a problem with final image resolution. I need generated image in high resolution but dimension for my editor are in pixel in low resolution.
For example: canvas has 800px x 600px and I need an final image with 100 cm x 400 cm, in other words, in real size.
Let me put some idea from my experience here -
if the final resolution is large, but not extreme large, you can do zoom canvas to its size before generate image data (toDataURL, for instance)
if the final resolution is extreme large, I suggest you can deal with it from PHP directly
For the first one -
var originWidth = canvas.getWidth();
function zoom (width)
{
var scale = width / canvas.getWidth();
height = scale * canvas.getHeight();
canvas.setDimensions({
"width": width,
"height": height
});
canvas.calcOffset();
var objects = canvas.getObjects();
for (var i in objects) {
var scaleX = objects[i].scaleX;
var scaleY = objects[i].scaleY;
var left = objects[i].left;
var top = objects[i].top;
objects[i].scaleX = scaleX * scale;
objects[i].scaleY = scaleY * scale;
objects[i].left = left * scale;
objects[i].top = top * scale;
objects[i].setCoords();
}
canvas.renderAll();
}
zoom (2000);
// here you got width = 2000 image
var imageData = canvas.toDataURL({
format: 'jpeg',
quality: 1
});
zoom (originWidth);
I never tried it on 100cm x 400cm, because it's really large, so if you can't do it from fabric.js, do it in PHP or else, this link may be help Convert SVG image to PNG with PHP
100cm = 39.3inch and 400cm = 39.3 * 4inch, if you have 300dpi image for final output. You will need width = 39.3 * 300 and height 39.3 * 4 * 300 size, if browser can handle it or not, I am not sure.
I have this function set up
if (window.innerWidth && window.innerHeight) {
var winW = window.innerWidth;
}
var xM = winW/180;
var axis = 0;
$(window).bind('mousemove',function(e){
var xCoord = Math.floor(e.pageX/xM);
axis = 0.6 * Math.sin(xCoord);
var pageCoords = "( " + e.pageX + ", " + e.pageY + ", " + xCoord + " )";
$("span#showme").text(pageCoords);
});
setInterval(function() {
$("#welcome-background").fadeTo(0, 0.4 + axis);
}, 100);
(for additional reference and working visual- http://jsfiddle.net/ySjqh/2/ )
The code works in theory to divide the page evenly into segments from 0-180, then calculates which segment the mouse appears in. Then uses the Math.sin() function to derive how much opacity to apply, based on a padded starting point of 0.4 opacity (jQuery style), and should use the mouse position to determine how much of the remaining 0.6 to apply based on its distance from center, where mouse at center-page should yield full opacity.
What I don't get is why the script behaves this way, rolling through an entire sine wave when I've limited the input to the Math.sin(x) function to 1 < x < 180. If you replace xCoord with axis in the place where I build the jQuery text for #showme, you'll see that it throws negative numbers- which shouldn't be happening! ... so I don't get what the problem/behavior results from!!! Frustrating!!!
Just use:
xCoord = (xCoord * Math.PI) / 180; // Convert value to Radians
and it works..
Sample
http://jsfiddle.net/ySjqh/4/
axis = 0.6 * (1 - Math.abs(e.pageX - winW/2)/(winW/2));
Using the X distance from the center instead of sin.