Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I have lots of images in my page and I am looking for a way to draw a line that will connect one image to the other ( it doesn't have to be an arrow, just a normal line. ).For example, let us consider ($) as an image:
$
$
Now how can I connect those 2 images ($) with a line?
Thanks!
Since you seem to be asking about basic JavaScript, HTML, and CSS, here's a simple method using only those. It's nice to understand the math and theory behind doing these kinds of graphical calculations instead of entirely relying on libraries.
Use a HTML div as a line by calculating the distance and angle between two images.
// Get the position of the first image
var imgOnePosition = document.getElementById("one").getBoundingClientRect();
// Get the position of the second image
var imgTwoPosition = document.getElementById("two").getBoundingClientRect();
// Calculate the angle between the two images' positions.
// Math.atan2() returns a value in radians so convert it to degrees as well
var angle = Math.atan2(imgOnePosition.top - imgTwoPosition.top, imgOnePosition.left - imgTwoPosition.left) * (180 / Math.PI);
// Calculate the distance, hopefully you remember this from basic algebra :)
var distance = Math.sqrt(Math.pow(imgOnePosition.top - imgTwoPosition.top, 2) + Math.pow(imgOnePosition.left - imgTwoPosition.left, 2));
// Create a new DIV to represent our line
var line = document.createElement("div");
// Now we style it
line.style.position = "absolute"; // so that we can change left and top
line.style.width = distance + "px";
line.style.height = "2px";
line.style.left = "50%"; // Center the element in its parent
line.style.top = "50%"; // Center the element in its parent
line.style.background = "#000";
line.style.transformOrigin = "0% 50%"; // Rotate around one edge instead of the middle
line.style.transform = "rotate(" + (angle) + "deg)";
// Add the line to the SECOND image's parent element.
// It's the 2nd image instead of 1st because of the order we did the math in calculating the angle
document.getElementById("two").appendChild(line);
body, img {
margin: 0;
padding: 0;
display: block;
}
#container {
position: relative;
background: #ddd;
width: 320px;
height: 240px;
}
.img-container {
position: absolute;
}
<div id="container">
<div id="one" class="img-container" style="left: 50px; top: 100px;" >
<img src="http://imgur.com/8B1rYNY.png" />
</div>
<div id="two" class="img-container" style="left: 150px; top: 190px;" >
<img src="http://imgur.com/8w6LAV6.png" />
</div>
</div>
If you want the line to appear behind the images instead of in front, you could modify their z-index values so they're ordered properly.
Edit: The above works if the images are the exact same size. If they are different sizes, calculate the center point of the images and use that instead of just the top left corner of the getBoundingClientRect().
// Get the position of the first image
var imgOneRect = document.getElementById("one").getBoundingClientRect();
var imgOnePosition = {
left: (imgOneRect.left + imgOneRect.right) / 2,
top: (imgOneRect.top + imgOneRect.bottom) / 2
}
// Get the position of the second image
var imgTwoRect = document.getElementById("two").getBoundingClientRect();
var imgTwoPosition = {
left: (imgTwoRect.left + imgTwoRect.right) / 2,
top: (imgTwoRect.top + imgTwoRect.bottom) / 2
}
div tag: with a background-color, width, height, transform: rotate(50deg) and well positioning properties
SVG tag
PNG image
Canvas
Related
I have this code:
<span><img id="user" src="http://placehold.it/100x100" alt="img"></span>
<span><h2 id="textToChange">text here</h2></span>
When I change #textToChange the #user moves automatically because the text changes and because it's a span it moves it. I would like to animate #user so it will move in a linear animation instead of just getting to the x value.
Is something like to possible to achieve or am I crazy? Thanks.
This is an interesting little problem. Let me break it down into steps:
Find the image's current position
Find where it needs to move to
Move it
Change the text
Now, the hard parts are steps 2 and 3.
For step 2, you have to calculate the length of the new text. This is tricky because there are no built-in functions to tell you how wide text will be with a given set of styles. You pretty much have to create a duplicate element and measure it instead.
For step 3, you have to move the element without causing a jump before or after the text changes. My way of doing this is to use position: absolute and set left to the current position (thus eliminating any jerking there). I then transition to the correct position using transform (doing a little math to account for the current position), for performance. At the end of the transition, take away the style attribute and change the text.
One other thing to watch out for is the text jumping around when the image becomes position: absolute. For simplicity, I put the entire line in a display: flex container. If you don't want to use flex, you can use inline-block or block on the text and adjust the padding/height so it will keep the proper amount of space.
Here's what I came up with (also on JSFiddle):
var $img = document.getElementById('user');
var $text = document.getElementById('textToChange');
var $estimator = document.getElementById('estimator');
var extraWidth = $img.offsetLeft - $text.offsetWidth;
function estimate(text) {
$estimator.textContent = text;
var width = $estimator.offsetWidth;
$estimator.textContent = '';
return width;
}
document.getElementById('change-text')
.addEventListener('click', function() {
var newText = randomText();
var left = $img.offsetLeft;
$img.style.position = 'absolute';
$img.style.left = left + 'px';
$img.style.transition = 'transform linear 1s';
$img.style.transform = 'translateX(0)';
window.requestAnimationFrame(function() {
$img.style.transform = 'translateX(' + (extraWidth + estimate(newText) - left) + 'px)';
window.setTimeout(function() {
$text.textContent = newText;
$img.removeAttribute('style');
}, 1000);
});
});
// For testing
function randomText() {
var length = Math.floor(Math.random() * 43) + 3;
return 'Lorem ipsum dolor sit amet portris noc tefweep'.slice(0, length);
}
h2 {
position: relative;
height: 100px;
display: flex;
align-items: flex-end;
}
/* For measuring text width. I don't want it to be seen. */
.not-shown {
visibility: hidden;
color: transparent;
position: absolute;
z-index: -1;
}
<h2>
<span id="textToChange">text here</span>
<img id="user" src="http://placehold.it/100x100" alt="img">
</h2>
<h2 class="not-shown"><span id="estimator"></span></h2>
<button id="change-text">Change text</button>
Note that this does not work well if the text goes to multiple lines. I chose not to worry about that scenario.
I am looking at this fiddle:
http://jsfiddle.net/kDs2Q/45/
Is there a way to layer the divs/line in a way so that the line will be behind the other divs? I want to be able to draw the line from the center of one div to the center of the other but not see the line cross over the actual boxes.
This is how I would to the center-to-center:
var off1 = getOffset(div1);
var off2 = getOffset(div2);
var x1 = off1.left + off1.width/2;
var y1 = off1.top + off1.height/2;
var x2 = off2.left + off1.width/2;
var y2 = off2.top + off1.height/2;
Yes use z-index in your style.
z-index:-1
JSFiddle http://jsfiddle.net/D24uC/
Use z-indexes, the DIVs need to have a higher z-index than the 'line-div'.
Give it a try, set the DIVs z-index to 1000 or something and see the result:
http://jsfiddle.net/kDs2Q/884/
<div id="div1" style="position:absolute; z-index:1000; background-color:blue; width:100px; height: 200px;top: 200px; left: 100px;">
How do I get rid of that undesired white border on the right of the page?
The website basically dynamically resizes images on a grid, here's a video: https://vine.co/v/h2wtnw6K3H0
CSS:
body {
height: 100%;
width: 100%;
margin: 0;
}
grid {
height: 100%;
width: 100%;
}
.gridImage {
vertical-align: bottom;
margin-left: 0px;
margin-right: 0px;
margin-top: 0px;
margin-bottom: 0px;
}
JS:
function resize() {
console.log($(window).width());
var newBody = "";
for (var i = 0; i <= 100; i++) {
newBody += '<img class="gridImage" src="Images/image2.jpg" width="' + $(window).width() / Math.floor(($(window).width() / 100)) + 'px" height="' + $(window).width() / Math.floor(($(window).width() / 100)) + 'px">';
}
document.getElementById("grid").innerHTML = newBody;
}
If my margins are zero, why is this showing up? Anything I'm missing? Thanks.
Ridcully has covered what the problem is, but here’s a solution.
First you would need to calculate the desired width of each image. This is simply your current equation wrapped in Math.ceil().
var windowWidth = $(window).width() // A slight performance improvement, plus cleaner code
var maxImageWidth = <your value here>
var unroundedImageWidth = windowWidth / Math.floor(windowWidth / maxImageWidth)
var roundedImageWidth = Math.ceil(unroundedImageWidth)
Unless your images fit perfectly, this will make each row slightly wider than the window, causing the final image on each line to wrap to the next. To prevent this, you need to set the gridContainer’s width to that of each row.
$('.gridContainer').width(windowWidth * roundedImageWidth / unroundedImageWidth)
Everything should look good, except for one thing: the horizontal scrollbar. This is easily fixed, however. Add this to your CSS:
.gridContainer {
overflow-x: hidden;
}
This will hide both the scrollbar and the final few pixels on each line. Perfect! Well, not quite.
The problem with this method is that one image per row takes the hit (loses pixels) for all of the others. If you have small images and a lot of images per row, you could end up losing a significant portion of your final column.
To avoid this, you can round your image widths upwards and distribute the overflow amongst all images in the row. This is a little more complicated than the previous method, but it does give a better result.
There are three more numbers you need to calculate.
var imagesPerRow = windowWidth / unroundedImageWidth
var numOfRows = Math.ceil($('.gridContainer img').length / imagesPerRow)
var spillage = windowWidth / roundedImageWidth - windowWidth // Pixels we have to lose
Now it’s just a matter of distributing the spillage.
var i = 0 // Loop counter
while (spillage !== 0) {
// Set the width of all images in column i to the width of that column - 1
$('.gridContainer img:nth-child(' + imagesPerRow + 'n-' + (i+1) + ')')
.width($('.gridContainer img:nth-child(' + (i+1) + ')').width() - 1)
spillage--
i++
}
There should no longer be more than a single pixel difference between the widths of the images.
It's because of rounding errors. What you do is fill the grid with 100 scaled images, depending on the browser to wrap to a new line when the image doesn't fit in the current row any more.
Now imagine a width of 305 pixels. Your formula gives an image width of 100 for that, so you get 3 images in a row and the next one wraps to the next row, leaving 5 pixels blank at the right border.
i think you should also add padding:0; to body its missing from your code.
Try it and even better just make a jsfiddle then it would be easier to check for everyone.
I have span, and it's styles are represented below. My problem is, it was designed to fill 60px*60px span. But now, I have to make it to fill another span with 50px*50px size. But it can't work with background position, because if i change the background-size, all position slips away. So is there any way (css or javascript hack) to resize an image or a block element with bacground-image after the image has been drawn? I want to avoid rewriting all background positions (I've got classes for each icons like ".entertainment").
<span class="icon icon2 entertainment"></span>
span.icon2 {
float: left;
width: 50px;
height: 50px;
margin: 5px 0 0 0;
}
#wrapper span.icon.entertainment {
background-position: -60px -360px;
}
#wrapper span.icon {
background: url(https://teeg.hu/image/icon.png);
}
Thanks for any help!
There is no pure css solution.
There is a js solution. Resize the background (background-size) as you did, then for each element move the position with the difference between sizes / 2 (in your case 5px).
You don't rewrite the classes, just iterate through elements.
Note: This might become an extensive operation, it is better to rewrite classes, even though that is what you want to avoid (40 is not so much... at most 30 min - testing included).
Ok, I've written some hack. I resized the background:
background-size: 100px 1550px;
and did it with jQuery:
$(function() {
$("span.icon2").each(function(index, value) {
var pos = $(this).css("background-position").split(' ');
var newPos = [];
newPos[0] = parseInt(pos[0].replace("px", "")) / 60 * 50;
newPos[1] = parseInt(pos[1].replace("px", "")) / 60 * 50;
$(this).css("background-position", newPos[0] + "px " + newPos[1] + "px");
});
});
I want to place many divs in a form of a circle. I will use relative positioning for the divs. For a start I am trying to place four divs around the circle
div 1 - top 50,
left 100
div 2 - top 100,
left 150
div3 -
top 150,
left 100
div 4 -
top 100,
left 50
I will be calculating the values in the actual case and setting them but for now it does not matter.Is it possible to create four divs (in an actual case it will be a large number)inside an outer div. But I need to assign differenet sequential ids to these divs and place them at the positions menntioned.
I will have to calculate and then assign top and left positions using script. So could you show how to assign these values using script.
This is really a nice question, as it requires also some math backgrounds.
So, first, let's say what we are going to do:
0. you must decide the center of the circle and its radius
1. we must decide at which angle, on a circle, we should put our divs
2 we should then make a function which, given the angle, gives you the position of the div
So, what do we do wth all that?
decide which should be the center of the circle (if it has to stay in the center of the page
decide the radius (could be calculated as well according to windows dimension)
some trigonometry: to understand the angle iterval, just divide 360° by the number of divs: if you have two divs, then you angle interval is 360/2=180 (ugly). If you have 10 divs your intrval is 36°
Very good, now we're ready to code.
get center: I just redirect you to t it at this stackoverflow link
use the same code to decide tha radius
the function which takes, as input, the number of divs, the radius, the center, and gives you back an array with the divs coord. the center is a 2 places array (x and y). In the function we make some adjustment to output the actual postion of the div.
.
function getCoords(divNum, radius, center){
var num= divNum;
var angleInt= (6.28/num);
var outArray=[];
for (i=0;i<divNum;i++){
outArray.push([(Math.cos(angleInt*i)*radius+center[0]),(Math.sin(angleInt*i)*radius+center[1])]);
}
return outArray;
}
Well, it's done, now you can place your divs with any jquery method, like in this example:
var localization=getCoords(10,200,[400,400]);
var i=1;
for (var element in localization){
var posTop=localization[element][0];
var posLeft=localization[element][1];
var element= $("<div class='inner'>"+i+"</div>");
$(element).css({ position: "absolute",
marginLeft: 0, marginTop: 0,
top: posTop, left: posLeft });
$("body").append(element);
i=i+1;
}
hope this helps
<script>
$(document).ready(function() {
"use strict";
var NR_OF_ITTERATIONS = 4,
RADIUS = 40,
i,
$wrapper = $("#wrapper");
for(i=0;i<NR_OF_ITTERATIONS;i+=1) {
$wrapper.append(
$("<div/>")
.css({
top: /* Top position */,
left: /* Left position */
});
);
}
};
</script>
<style>
#wrapper > div {
position: absolute;
border: 1px solid black;
width: 40px;
height: 40px;
}
</style>
<div id="wrapper"></div>
Here is the code to generate divs. Put your top and left style in style attr of the div. You can ignore the random number. I used it just as place holder.
<div id="outterDiv" class="outterDivision"> </div>
var html = '';
var i;
for(i=0;i<=4;i++) {
var Random_Number = Math.ceil(Math.random()*500+i);
html +='<div id="inner'+i+'" class="anything" style="top:50px; left:100px;">'+Random_Number+'</div>';
}
$('#outterDiv').html(html);