Scaling elements based on another element - javascript

I have elements positioned on top of am img in the following way:
<div style={{ display: "inline-block", position: "relative" }} >
<img />
<div style={{ position: "absolute", left: 0, right: 0, top: 0, bottom: 0, width: "100%", height: "100%" }} >
<child elements I'm trying to position />
</div>
</div>
The child elements use the top, left, width, height properties to position themselves on top of the image.
I'm trying to make them scale with the image (- when the image's width and height changes I want them to stay in the same place and scale to the image):
width: Math.round(((box.x2 - box.x1) / imgWidth) * 100) + "%",
height: Math.round(((box.y2 - box.y1) / imgHeight) * 100) + "%",
left: Math.round((box.x1 / imgWidth) * 100) + "%",
top: Math.round((box.y1 / imgHeight) * 100) + "%"
But the results when using percentage are a little off than just using the coordinates.
Is there a better way to position the elements (boxes) so they scale with the image? Is there something wrong with the formula I'm using?
Edit:
For example:
The squares are the child elements I mentioned and when the user zooms in or out of the page or if the image's size changes I want the squares position on the image to be preserved and their scale match the image's scale

Ok, so this may not fit into your project straight off the bat but you should be able to get it working with a little bit of tweaking.
Use some JavaScript to calculate the absolute positioning of the child elements to a percentage.
var imgWrapper = document.getElementById("wrapper");
var children = document.getElementsByClassName("child");
window.onresize = function(event) {
var imgWidth = imgWrapper.offsetWidth;
var imgHeight = imgWrapper.offsetHeight;
for (var i = 0; i < children.length; i++)
{
// - Current child element
var child = children.item(i);
// - Child positions
var currentTop = child.offsetTop;
var currentLeft = child.offsetLeft;
var currentBottom = imgHeight - (currentTop + child.offsetHeight);
var currentRight = imgWidth - (currentLeft + child.offsetWidth);
var newTop = (100 * currentTop / imgHeight);
var newLeft = (100 * currentLeft / imgWidth);
var newBottom = (100 * currentBottom / imgHeight);
var newRight = (100 * currentRight / imgWidth);
child.style.top = newTop + "%";
child.style.left = newLeft + "%";
child.style.bottom = newBottom + "%";
child.style.right = newRight + "%";
}
};
http://next.plnkr.co/edit/E8RbqFTClYklW4w7

Related

FabricJS - How to prevent leaving object from the given object?

I was able to prevent leaving objects from the canvas but I was not able to prevent leaving child objects from the given object.
I tried to do it in this way (see code example below) but this locks the object leaving in the same size (width, height) of the locked object but positioned absolutely (top, left). I need to prevent leaving in the same coords there the parent object is positioned (see please the attached image).
Any ideas are welcome.
preventLeavingInsideBox(e: IEvent) {
let activeObject = e.target;
if ((activeObject.get('left') - (activeObject.get('width') * activeObject.get('scaleX') / 2) < 0))
activeObject.set('left', activeObject.get('width') * activeObject.get('scaleX') / 2);
if ((activeObject.get('top') - (activeObject.get('height') * activeObject.get('scaleY') / 2) < 0))
activeObject.set('top', activeObject.get('height') * activeObject.get('scaleY') / 2);
if (activeObject.get('left') + (activeObject.get('width') * activeObject.get('scaleX') / 2) > this.rect.width)
{
var positionX = this.rect.width - (activeObject.get('width') * activeObject.get('scaleX')) / 2;
activeObject.set('left', positionX > this.rect.width / 2 ? positionX : this.rect.width / 2);
}
if (activeObject.get('top') + (activeObject.get('height') * activeObject.get('scaleY') / 2) > this.rect.height)
{
var positionY = this.rect.height - (activeObject.get('height') * activeObject.get('scaleY') / 2);
activeObject.set('top', positionY > this.rect.height / 2 ? positionY : this.rect.height / 2);
}
//below just prevention for object from getting width or height greater than canvas width and height
if (activeObject.get('width') * activeObject.get('scaleX') > this.rect.width)
{
activeObject.set('scaleX', this.rect.width / activeObject.get('width'));
}
if (activeObject.get('height') * activeObject.get('scaleY') > this.rect.height)
{
activeObject.set('scaleY', this.rect.height / activeObject.get('height'));
}
}
I was trying to achieve the same result. I had an object with an image inside that I didn't want to be able to be moved outside of it and I also did the resize too.
So I had to get the object that frame which held the image originally and then adds the image after.
What you need to take into account is the top & left of the holding object and the movable object.
So I have a ID on my object of feature image so I get access to it from that. and get the original top, left, height & width.
const featureImageBoxDetails = {
top: featureImageBox.top,
left: featureImageBox.left,
right: featureImageBox.left + featureImageBox.width * featureImageBox.scaleX,
bottom: featureImageBox.top + featureImageBox.height * featureImageBox.scaleY,
width: featureImageBox.width * featureImageBox.scaleX,
height: featureImageBox.height * featureImageBox.scaleY,
};
Then I have my preventLeavingInsideBox function:
const preventLeavingInsideBox = (e: IEvent) => {
const activeObject = e.target;
const activeObjectDetails = {
top: activeObject.top,
left: activeObject.left,
right: activeObject.left + activeObject.width * activeObject.scaleX,
bottom: activeObject.top + activeObject.height * activeObject.scaleY,
width: activeObject.width * activeObject.scaleX,
height: activeObject.height * activeObject.scaleY,
};
// right
if (activeObjectDetails.right <= featureImageBoxDetails.right) {
activeObject.set({
left: featureImageBoxDetails.right - activeObjectDetails.width,
});
}
// left
if (activeObjectDetails.left >= featureImageBoxDetails.left) {
activeObject.set({
left: featureImageBoxDetails.left,
});
}
// bottom
if (activeObjectDetails.bottom <= featureImageBoxDetails.bottom) {
activeObject.set({
top: featureImageBoxDetails.top + featureImageBoxDetails.height - activeObjectDetails.height,
});
}
// Top
if (activeObjectDetails.top >= featureImageBoxDetails.top) {
activeObject.set({
top: featureImageBoxDetails.top,
});
}
};
Then you just need to add in the:
canvas.on('object:moving', preventLeavingInsideBox);
I have same need but need more
i just need this same feature. and its working fine but when we do the same with rotated object its works strange. can you please

transform-origin of a rotated element inside a rotated parent

I want to append a div as a child of an other div without changing its position (from a user point of view).
The "futur" parent is rotated of -30° the element that will become a child is rotated of -30°.
how to compute the right (left, top) position of the futur child ?
I tried to cancel the rotation of the futur parent
transform:rotate(0°)
and do the same for the futur child
transform:rotate(60°)
but with a transform-origin set to the transform-origin of the futur parent that means
Left(futur child)-tranform-originx (parent)
top(futur child)-transform-originy (parent)
but it does not seem to run
any idea ?
HTML :
<div id="futurParentFrame" style="z-index:1000;position:absolute;left:100px;top:100px;background-color:red;border:black 6px dashed;width:800px;height:500px;transform:rotate(-30deg)">
</div>
<div id="futurChildDiv" style="z-index:1002;position:absolute;left:493px;top:192px;background-color:gray;border-left:blue 4px dashed;border-right:blue 2px dashed;width:250px;height:150px;transform:rotate(30deg);"></div>
The math is somehow complex. I have tried to done it in the most simple way possible.
Click on the button to create the new child. The old one is semitransparent so that you can see them overlapping
function createChild () {
var parent = document.getElementById("futurParentFrame");
var child = document.getElementById("futurChildDiv");
var parentCoor = getCoor (parent);
var childCoor = getCoor (child);
var newChild = child.cloneNode(true);
newChild.id = "newChild";
newChild.style.transform = "rotate(60deg)";
var r = Math.hypot (parentCoor.x - childCoor.x, parentCoor.y - childCoor.y);
var alpha = -30 * Math.PI / 180;
var relativeX = childCoor.x - parentCoor.x;
var relativeY = childCoor.y - parentCoor.y;
var rotatedX = relativeX * Math.cos(alpha) + relativeY * Math.sin(alpha);
var rotatedY = relativeX * -Math.sin(alpha) + relativeY * Math.cos(alpha);
var left = (parentCoor.width * 0.5) - parentCoor.borderLeft - (childCoor.width * 0.5) + rotatedX;
var top = (parentCoor.height * 0.5) - parentCoor.borderTop - (childCoor.height * 0.5) + rotatedY;
newChild.style.left = left + "px";
newChild.style.top = top + "px";
parent.appendChild(newChild);
}
function getCoor (element) {
var left = element.offsetLeft;
var top = element.offsetTop;
var width = element.offsetWidth;
var height = element.offsetHeight;
var centerX = left + width * 0.5;
var centerY = top + height * 0.5;
var borderLeft = parseInt (element.style.borderLeftWidth);
var borderTop = parseInt (element.style.borderTopWidth);
return {left: left,
top: top,
width: width,
height: height,
x: centerX,
y: centerY,
borderLeft: borderLeft,
borderTop: borderTop};
}
#futurChildDiv {
opacity: 0.5;
}
<div id="futurParentFrame" style="z-index:1000;position:absolute;left:100px;top:100px;background-color:red;border:black 6px dashed;width:800px;height:500px;transform:rotate(-30deg)">
</div>
<div id="futurChildDiv" style="z-index:1002;position:absolute;left:493px;top:192px;background-color:gray;border-left:blue 4px dashed;border-right:blue 2px dashed;width:250px;height:150px;transform:rotate(30deg);"></div>
<button onclick="createChild();">run</button>

Javascript/CSS Image height/width/margin Calculations not taking effect all at once

I am practicing my vanilla javascript, by writing an image gallery application.
The function I am working on is the swap from my imageRoll to my mainImage.
The swap works fine, and the height/width calculation works fine as well... but when I tell it to calculate the margin of the parent element and the new image, it fails unless you click the source image a second time.
JSFiddle: https://jsfiddle.net/un64w9hh/2/
Here's the function code:
function galleryToMainImg() {
var gNumList = this.parentNode.classList;
var gNum = gNumList[0].slice(1,2);
var imgId = "g" + gNum + "MainImage";
var imgName = document.getElementById(imgId);
var height = this.offsetHeight;
var width = this.offsetWidth
var styles;
var ratio;
imgName.src = this.src;
if (height > width) {
ratio = (width / height) * 100;
styles = "height:100%; margin: 0px " + ((imgName.parentNode.offsetWidth - imgName.offsetWidth) / 2) + "px;";
} else if (width > height){
ratio = (height / width) * 100;
styles = "width:100%; margin: " + ((imgName.parentNode.offsetHeight - imgName.offsetHeight) / 2) + "px 0px;";
} else {
ratio = 1;
styles = "width:100%; margin: " + ((imgName.parentNode.offsetHeight - imgName.offsetHeight) / 2) + "px 0px;";
}
imgName.style = styles;
}
Interestingly enough, as long as the images clicked from the gallery are the same layout (portrait vs landscape) it works every time after the first one. But if you switch layout, it breaks every time.
First click:
<img id="g1MainImage" src="./images/image01.png" alt="Caption" style="height: 100%; margin: 0px;">
Second click:
<img id="g1MainImage" src="http://ne.fario.us/designs/ImageGallery/images/image01.png" alt="Caption" style="height: 100%; margin: 0px 9px;">
I'm just not sure what is going on. Any help would be greatly appreciated.
I have been playing with your code for quite a while, your function galleryToMainImg() is just fine, ratio and .offsetWidth properties OK. I have eliminated every margin property from your .css and error persists.
Leaving calculations on the side, this works decently (no error, but I still have no margin properties applied by .css):
function galleryToMainImg() {
gNumList = this.parentNode.classList;
gNum = gNumList[0].slice(1,2);
imgId = "g" + gNum + "MainImage";
imgName = document.getElementById(imgId);
height = this.offsetHeight;
width = this.offsetWidth;
styles='';
ratio='';
imgName.src = this.src;
if (height > width) {
ratio = (width / height) * 100;
styles = 'height:100%; margin-left: 38%; margin-top: 0%'; /*+((imgName.parentNode.offsetWidth - imgName.offsetWidth) / 2)*/
} else if (width > height){
ratio = (height / width) * 100;
styles = "width:100%; margin-left: 7%; margin-top: 0%";/*+ ((imgName.parentNode.offsetHeight - imgName.offsetHeight) / 2) + "px;"*/
} /*else {
ratio = 1;
styles = 'width:100%; margin: "' + ((imgName.parentNode.offsetHeight - imgName.offsetHeight) / 2) + 'px;"';
}*/
imgName.style = styles;
}
Hope it is helpful for future examination.
that's normal because you change the image size on the click. I updated your fiddle to see the alerts. See hier jsfiddle.net/un64w9hh/4/

Adapt random image placement code for flexible layout

I'm looking for an effect very similar to this:
http://jsfiddle.net/G5Xrz/
function rnd(max) { return Math.floor(Math.random()*(max+1)) }
function showImage(container, maxwidth, maxheight, imgsrc, imgwidth, imgheight) {
var id = "newimage" + rnd(1000000);
$(container).append(
"<img id='" + id + "' src='" + imgsrc +
"' style='display:block; float:left; position:absolute;" +
"left:" + rnd(maxwidth - imgwidth) + "px;" +
"top:" + rnd(maxheight - imgheight) + "px'>");
$('#' + id).fadeIn();
return id;
}
setInterval(
function() {
showImage("#container", 400, 600,
"http://placekitten.com/" + (90 + rnd(10)) + "/" + (90 + rnd(10)),
100, 100);
}, 700);
But i'd prefer a flexible layout, ie images not bound by a div with predefined height and width, instead responding to the dimensions of the browser.
The following piece of code seems to have a more appropriate way of generating the random positions:
http://jsfiddle.net/Xw29r/15/
function makeNewPosition(){
// Get viewport dimensions (remove the dimension of the div)
var h = $(window).height() - 50;
var w = $(window).width() - 50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh,nw];
}
function animateDiv(){
var newq = makeNewPosition();
var oldq = $('.a').offset();
var speed = calcSpeed([oldq.top, oldq.left], newq);
$('.a').animate({ top: newq[0], left: newq[1] }, speed, function(){
animateDiv();
});
};
However I'm very much a beginner with javascript and I don't know how to combine the two.
Can anyone help?
Thanks
Take this part from the second code:
// Get viewport dimensions (remove the dimension of the div)
var h = $(window).height() - 50;
var w = $(window).width() - 50;
and use those variables h and w with the browser height and width (minus 50) as the appropriate parameters in this part of the first code:
setInterval(
function() {
showImage("#container", 400, 600,
"http://placekitten.com/" + (90 + rnd(10)) + "/" + (90 + rnd(10)),
100, 100);
}, 700);
Also, the first code has this HTML:
<div id="container" style="width:400px; height:600px; background: green; position:relative"></div>
That hard-codes the height and width at pixel values. You can use a CSS percentage value to make the width respond to the parent container's size. However, you will need JS to set the height properly; a percentage for the height does nothing
Putting that all together (and removing the "minus 50" part), you get this:
jsFiddle demo
<div id="container" style="width:100%; height:100px; background: green; position:relative"></div>
function adjustContainerHeight(height) {
$('#container').height(height);
}
adjustContainerHeight($(window).height());
setInterval(
function() {
var h = $(window).height();
var w = $(window).width();
adjustContainerHeight(h);
showImage("#container", w, h,
"http://placekitten.com/" + (90 + rnd(10)) + "/" + (90 + rnd(10)),
100, 100);
}, 700);
This updates the height of the container when the page is first loaded, and once again whenever the random image is placed. More robust code would have a separate height-adjusting event handler that updates the height whenever the page size changes.

Adjusting height & width of pop up window on resize to maintain the aspect ratio

I am opening a pop up window using window.open function
window.open('some_page.htm','','width=950,height=500');
Now what I want is when user tries to resize the window, the aspect ratio should be maintained i.e., if width is reduced then accordingly height should also get reduced and vice versa. I just want to calculate the new dimensions. So far I have tried this
function ResizeWindow()
{
var iOrignalWidth = 950;
var iOrignalHeight = 500;
var iOuterHeight = window.outerHeight;
var iOuterWidth = window.outerWidth;
var iNewOuterWidth = Math.round((iOrignalWidth / iOrignalHeight) * iOuterHeight);
var iNewOuterHeight = Math.round((iOrignalHeight / iOrignalWidth) * iNewOuterWidth);
alert("New Width: "+ iNewOuterWidth + "\t" + "New Height" + iNewOuterHeight);
}
I know that there's something wrong up there since I am not getting desired results. ANy solution on this ?
You'll want to either adjust the width to the height or visa versa, not both.
In this code, I assumed you want the width adjusted to the height:
function ResizeWindow()
{
var iOrignalWidth = 1000;
var iOrignalHeight = 500;
var iOrginalRatio = iOrignalWidth/iOrignalHeight; // 2
var iOuterWidth = window.outerWidth; // example: 1083
var iOuterHeight = window.outerHeight; //example: 600
var iNewOuterHeight = iOuterHeight; // 600
var iNewOuterWidth = Math.round(iNewOuterHeight*iOrginalRatio); //600 * 2 = 1200
alert("New Width: "+ iNewOuterWidth + "\t" + "New Height" + iNewOuterHeight);
}​
I changed to original width to 1000 for the example, but you can change that back in your actual code.
You should do to accoording to one resize for maintain the aspect ratio. For example:
function ResizeWindow()
{
var iOrignalWidth = 950;
var iOrignalHeight = 500;
var iOuterHeight = window.outerHeight;
var iOuterWidth = window.outerWidth;
var w = (window.outerWidth - iOrignalWidth) / iOrignalWidth; // for exam: (1280-950) / 950= 0.34
var h = (window.outerHeight - iOrignalHeight) / iOrignalHeight; // for exam : (800 - 500) / 500= 0.60
var newWidth;
var newHeight;
if (w<h)
{
// If percentage of width is less than percentage of height, Resize should be according to percentage of width.
newWidth = iOrignalWidth * w * 100;
newHeight = iOrignalHeight * w *100;
}
else
{
// If percentage of height is less than percentage of width, Resize should be according to percentage of height.
newWidth = iOrignalWidth * h * 100;
newHeight = iOrignalHeight * h *100;
}
alert("New Width: "+ newWidth + "\t" + "New Height" + newHeight );
}
So that maintain the aspect ratio is always preserved.

Categories