Draw a line from one element to multiple elements on click - javascript

I'm trying to draw a line from an element [.identifier] to the clicked element [ A, B, C series ]. I'm able to display the line but in the other direction, not sure why it is displaying in such a direction.
Here is my fiddle: https://jsfiddle.net/SampathPerOxide/u2afymxs/11/
Can someone help me to display a line between ".identifier" and the respective series element?
Expected result on clicking A series:
on clicking B series:
$('.seriesli').click(function() {
function adjustLine(from, to, line) {
var fT = from.offsetTop + from.offsetHeight / 2;
var tT = to.offsetTop + to.offsetHeight / 2;
var fL = from.offsetLeft + from.offsetWidth / 2;
var tL = to.offsetLeft + to.offsetWidth / 2;
var CA = Math.abs(tT - fT);
var CO = Math.abs(tL - fL);
var H = Math.sqrt(CA * CA + CO * CO);
var ANG = 180 / Math.PI * Math.acos(CA / H);
if (tT > fT) {
var top = (tT - fT) / 2 + fT;
} else {
var top = (fT - tT) / 2 + tT;
}
if (tL > fL) {
var left = (tL - fL) / 2 + fL;
} else {
var left = (fL - tL) / 2 + tL;
}
if ((fT < tT && fL < tL) || (tT < fT && tL < fL) || (fT > tT && fL > tL) || (tT > fT && tL > fL)) {
ANG *= -1;
}
top -= H / 2;
line.style["-webkit-transform"] = 'rotate(' + ANG + 'deg)';
line.style["-moz-transform"] = 'rotate(' + ANG + 'deg)';
line.style["-ms-transform"] = 'rotate(' + ANG + 'deg)';
line.style["-o-transform"] = 'rotate(' + ANG + 'deg)';
line.style["-transform"] = 'rotate(' + ANG + 'deg)';
line.style.top = top + 'px';
line.style.left = left + 'px';
line.style.height = H + 'px';
}
adjustLine(
document.getElementById('div1'),
document.getElementById('div2'),
document.getElementById('line')
);
});
.identifier {
width: 10px;
height: 10px;
background-color: red;
position: absolute;
right: 45%;
top: 50%;
}
.series-div {
position: absolute;
right: 5%;
bottom: 30%;
}
.series-ul li {
list-style: none;
color: grey;
font-size: 1em;
font-weight: 600;
border: 2px solid grey;
display: table;
padding: 0.3em 0.1em;
text-align: center;
margin: 0.5em;
cursor: pointer;
}
#line {
position: absolute;
width: 2px;
margin-top: -1px;
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div style="position;relative;">
<div class="identifier" id="div2"></div>
<div class="series-div">
<ul class="series-ul">
<li class="seriesli" id="div1">A series</li>
<li class="seriesli">B series</li>
<li class="seriesli">C series</li>
</ul>
</div>
<div id="line"></div>
<img src="https://stat.overdrive.in/wp-content/odgallery/2020/06/57263_2020_Mercedes_Benz_GLS.jpg" class="img-responsive firstcar-detail" style="width: 100%;">
</div>

I fixed your fiddle: https://jsfiddle.net/c4ju6a0p/
Code changes:
// Get actual position relative to viewport.
// See https://stackoverflow.com/a/11396681/117030
fromBCR = from.getBoundingClientRect();
toBCR = to.getBoundingClientRect();
var fT = fromBCR.top + from.offsetHeight / 2;
var tT = toBCR.top + to.offsetHeight / 2;
// Don't add offsetWidth. This connects to the middle, not the left edge.
var fL = fromBCR.left //+ from.offsetWidth / 2;
var tL = toBCR.left + to.offsetWidth / 2;
The problem was the line was being calculated with the incorrect position due to relative positioning. This can be seen more clearly when the relative CSS is commented out: https://jsfiddle.net/vust5nxf/
Also, don't add the offsetWidth if you want the line to go to the left edge.
update: didn't notice the code snippet... applied changes there, too. I also made one more change:
You need to pass the element that was clicked to adjustLine(), otherwise currently the line is drawn between the same two elements every time because the elements are hardcoded with ids.
As a style note: I would move the definition of function adjustLine() outside the click handler. This will make the code easier to read, and the function will only be created once, instead of every time a click is handled.
adjustLine(
this, // Element that was clicked.
document.getElementById('div2'),
document.getElementById('line')
);
$('.seriesli').click(function() {
function adjustLine(from, to, line) {
// Get actual position relative to viewport.
// See https://stackoverflow.com/a/11396681/117030
fromBCR = from.getBoundingClientRect();
toBCR = to.getBoundingClientRect();
var fT = fromBCR.top + from.offsetHeight / 2;
var tT = toBCR.top + to.offsetHeight / 2;
// Don't add offsetWidth. This connects to the middle, not the left edge.
var fL = fromBCR.left //+ from.offsetWidth / 2;
var tL = toBCR.left + to.offsetWidth / 2;
var CA = Math.abs(tT - fT);
var CO = Math.abs(tL - fL);
var H = Math.sqrt(CA * CA + CO * CO);
var ANG = 180 / Math.PI * Math.acos(CA / H);
if (tT > fT) {
var top = (tT - fT) / 2 + fT;
} else {
var top = (fT - tT) / 2 + tT;
}
if (tL > fL) {
var left = (tL - fL) / 2 + fL;
} else {
var left = (fL - tL) / 2 + tL;
}
if ((fT < tT && fL < tL) || (tT < fT && tL < fL) || (fT > tT && fL > tL) || (tT > fT && tL > fL)) {
ANG *= -1;
}
top -= H / 2;
line.style["-webkit-transform"] = 'rotate(' + ANG + 'deg)';
line.style["-moz-transform"] = 'rotate(' + ANG + 'deg)';
line.style["-ms-transform"] = 'rotate(' + ANG + 'deg)';
line.style["-o-transform"] = 'rotate(' + ANG + 'deg)';
line.style["-transform"] = 'rotate(' + ANG + 'deg)';
line.style.top = top + 'px';
line.style.left = left + 'px';
line.style.height = H + 'px';
}
adjustLine(
this, // Element that was clicked.
document.getElementById('div2'),
document.getElementById('line')
);
});
.identifier {
width: 10px;
height: 10px;
background-color: red;
position: absolute;
right: 45%;
top: 50%;
}
.series-div {
position: absolute;
right: 5%;
bottom: 30%;
}
.series-ul li {
list-style: none;
color: grey;
font-size: 1em;
font-weight: 600;
border: 2px solid grey;
display: table;
padding: 0.3em 0.1em;
text-align: center;
margin: 0.5em;
cursor: pointer;
}
#line {
position: absolute;
width: 2px;
margin-top: -1px;
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div style="position;relative;">
<div class="identifier" id="div2"></div>
<div class="series-div">
<ul class="series-ul">
<li class="seriesli" id="div1">A series</li>
<li class="seriesli">B series</li>
<li class="seriesli">C series</li>
</ul>
</div>
<div id="line"></div>
<img src="https://stat.overdrive.in/wp-content/odgallery/2020/06/57263_2020_Mercedes_Benz_GLS.jpg" class="img-responsive firstcar-detail" style="width: 100%;">
</div>

Related

how do i change image in start of transition and end?

I am trying to make a walking animation, the program does that the character goes to the mouse click. but I can't make it when it's moving to change the image and when it's stopping return to the first image.
here is the code for the js file and the css file:
import "./styles.css";
var theThing = document.querySelector("#thing");
var cont = document.querySelector("#contentCont");
cont.addEventListener("click", getClickPosition, false);
function getClickPosition(e) {
theThing.src = "ddd2.gif";
var parentPosition = getPosition(cont);
var xPosition = e.clientX - parentPosition.x - theThing.offsetWidth / 2;
var yPosition = e.clientY - parentPosition.y - theThing.offsetHeight / 2;
var translate3dValue =
"translate3d(" + xPosition + "px," + yPosition + "px,0)";
theThing.style.transform = translate3dValue;
}
function getPosition(element) {
var xPos = 0;
var yPos = 0;
while (element) {
xPos += element.offsetLeft - element.scrollLeft + element.clientLeft;
yPos += element.offsetTop - element.scrollTop + element.clientTop;
element = element.offsetParent;
}
return {
x: xPos,
y: yPos
};
}
body {
background-color: #fff;
padding: 50px;
margin: 0;
}
#contentCont {
width: 600px;
height: 600px;
border: 15px #ededed solid;
overflow: hidden;
background-color: #f2f2f2;
cursor: pointer;
}
#thing {
width: 80px;
height: 80px;
transition: transform 0.7s ease-in;
}
right now its start at image 1 and change to image 2 when walking but doesnt return to image 1 when stopping.

How to prevent element from exceeding his container borders

I have a square, when clicked it appears in a random location and it also change size (so for example if I have a 30px box but it is 10px from the left border I still get 10px outside the gamespace).
sometimes the square exceed his container border
How can I make sure that the square will never exceed his container?
function position() {
var positionTop = Math.random() * 100;
var positionLeft = Math.random() * 100;
var position = "position:relative;top:" + positionTop + "%;left:" + positionLeft + "%;"
return position;
}
document.getElementById("shape").onclick = function() {
document.getElementById("shape").style.cssText = position();
}
#gameSpace {
width: 100%;
height: 470px;
background: blue;
margin: 0;
padding-top: 30px;
}
#playSpace {
width: 90%;
height: 90%;
margin: 0 auto;
margin-top: 10px;
border: 1px black solid;
}
#shape {
width: 100px;
height: 100px;
background-color: red;
}
<div id="gameSpace">
<div id="playSpace">
<!-- here we put the shape -->
<div id="shape"></div>
</div>
</div>
You need to set position: relative; to the parent element and position: absolute; to the shape element. Then use max min value for random where max is the parent width/height and subtract the shape width/height ...
This is snippet before update
function position() {
var playSpace = document.querySelector('#playSpace');
var shape = document.getElementById("shape");
var maxHeight = playSpace.offsetHeight - shape.offsetHeight;
var maxWidth = playSpace.offsetWidth - shape.offsetWidth;
var positionTop = Math.random() * (maxHeight - 0) + 0;
var positionLeft = Math.random() * (maxWidth - 0) + 0;
// think of this like so:
// var positionTop = Math.random() * (max - min) + min;
// more information about it https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
var position = "position:absolute;top:" + positionTop + "px;left:" + positionLeft + "px;"
return position;
}
document.getElementById("shape").onclick = function() {
document.getElementById("shape").style.cssText = position();
}
#gameSpace {
width: 100%;
height: 470px;
background: blue;
margin:0;
padding-top: 30px;
}
#playSpace {
position: relative; /* add this line */
width: 90%;
height: 90%;
margin: 0 auto;
border: 1px black solid;
}
#shape {
width: 100px;
height: 100px;
background-color: red;
}
<div id="gameSpace">
<div id="playSpace">
<!-- here we put the shape -->
<div id="shape"></div>
</div>
</div>
Updated after comment
Not sure how you added the size() function but probably the problem was with using ...cssText that you overwrote the changes. So now I changed the code with passing the element to the functions and then only change the single CSS statements which need to be changed.
function position(element) {
var playSpace = document.querySelector('#playSpace');
var shape = document.getElementById("shape");
var maxHeight = playSpace.offsetHeight - shape.offsetHeight;
var maxWidth = playSpace.offsetWidth - shape.offsetWidth;
var positionTop = Math.random() * (maxHeight - 0) + 0;
var positionLeft = Math.random() * (maxWidth - 0) + 0;
// think of this like so:
// var positionTop = Math.random() * (max - min) + min;
// more information about it https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
element.style.position = 'absolute';
element.style.top = positionTop + "px";
element.style.left = positionLeft + "px";
}
function size(element) {
var sizeMath = (Math.random() * 200) + 50;
element.style.width = sizeMath + "px";
element.style.height = sizeMath + "px";
}
document.getElementById("shape").onclick = function() {
size(document.getElementById("shape"));
position(document.getElementById("shape"));
}
#gameSpace {
width: 100%;
height: 470px;
background: blue;
margin:0;
padding-top: 30px;
}
#playSpace {
position: relative; /* add this line */
width: 90%;
height: 90%;
margin: 0 auto;
border: 1px black solid;
}
#shape {
width: 100px;
height: 100px;
background-color: red;
}
<div id="gameSpace">
<div id="playSpace">
<!-- here we put the shape -->
<div id="shape"></div>
</div>
</div>
You can use a specify the range (min/max) in Math.random function and then use this function Math.floor(Math.random() * (max - min + 1)) + min; to limit the returned value of the random function between min and max.
maxTop : height of the container - height of shape
maxLeft : width of the container - width of shape
minTop : 0
minLeft : 0
You need to use position:absolute and px value on shape for this to work
See code snippet:
function position() {
var minTop = 0;
var maxTop = document.getElementById("playSpace").clientHeight - document.getElementById("shape").clientHeight;
var minLeft = 0;
var maxLeft = document.getElementById("playSpace").clientWidth - document.getElementById("shape").clientWidth ;
var positionTop = Math.floor(Math.random() * (maxTop - minTop + 1) + minTop);
var positionLeft = Math.floor(Math.random() * (maxLeft - minLeft + 1) + minLeft);
var position = "position:absolute;top:" + positionTop + "px;left:" + positionLeft + "px;"
return position;
}
document.getElementById("shape").onclick = function() {
document.getElementById("shape").style.cssText = position();
}
#gameSpace {
width: 100%;
height: 470px;
background: blue;
margin: 0;
padding-top: 30px;
text-align:center;
}
#playSpace {
width: 90%;
height: 90%;
border: 1px black solid;
position:relative;
display:inline-block;
}
#shape {
width: 100px;
height: 100px;
background-color: red;
}
<div id="gameSpace">
<div id="playSpace">
<!-- here we put the shape -->
<div id="shape"></div>
</div>
</div>
With CSS calc, limit the position inside playSpace area (you can use different units, here % and px).
Then with offsetTop/offsetLeft, get the real position of the square and avoid negative positions (when positionTop < 100px or positionLeft < 100px).
function position() {
var positionTop = Math.random() * 100;
var positionLeft = Math.random() * 100;
var position = "position:relative;top: calc(" + positionTop + "% - 100px);left: calc(" + positionLeft + "% - 100px);";
return position;
}
document.getElementById("shape").onclick = function() {
var shapeDiv = document.getElementById("shape");
shapeDiv.style.cssText = position();
var top = shapeDiv.offsetTop;// Result of calc(" + positionTop + "% - 100px) in px
if(top < 0) {
shapeDiv.style.top = '0px';
}
var left = shapeDiv.offsetLeft;// Result of calc(" + positionLeft + "% - 100px) in px
if(left < 0) {
shapeDiv.style.left = '0px';
}
}
Don't forget to add position: relative to #playSpace, to get offsetTop/left correct
#playSpace {
position:relative;/* mandatory */
}
You can get the parent element size, so that in your scirpt, use a condition to prevent the square to exceed.
function position() {
var maxWidth = document.getElementById("playSpace").offsetWidth;
var maxTop = document.getElementById("playSpace").offsetHeight;
var positionTop = Math.random() * 100;
var positionLeft = Math.random() * 100;
if (positionTop > maxTop) { positionTop = maxTop;)
if (positionLeft > maxWidth) { positionLeft = maxWidth;)
var position = "position:relative;top:" + positionTop + "%;left:" + positionLeft + "%;"
return position;
}
I'm not sure if .offsetWidth and .offsetHeight works well, but you got the idea :)
By tweaking just a little your positionTop and positionLeft variable, I managed to keep the square inside. You just need to change the maximum % that it needs to have to not exceed the container. I found that 75% for the top and 80% for the left seems to be the max!
var positionTop = Math.floor(Math.random() * 75) ;
var positionLeft = Math.random() * 80;
Here's a fiddle
If you set the containing element to position: relative; and the inner element with position: absolute; the inner elements top left right and bottom properties will calculate from the borders of the containing element.
Here is a good source of css positioning.
In your case additional validation should be set to positionTop and positionLeft.
positionTop should be in the interval [( shapeHeight/2 ) - (100 - shapeHeight/2 ) ]
positionLeft should be in the interval [( shapeWidth/2 ) - (100 - shapeWeight/2 ) ]

How to use % instead of px with draggable element?

I'm stucked and I need help. I'm making map with markers. I can add markers etc.
My main container have 100% width and height. When I click somewhere my marker has % values for example top: 34%; left: 35%;
After dragging marker new position have px value. I want to save % values.
Any ideas?
map.js
jQuery(document).ready(function($){
// basic add
$("button#remove").click(function(){
$(".marker").remove();
});
//add with position
var map = $(".map");
var pid = 0;
function AddPoint(x, y, maps) {
// $(maps).append('<div class="marker"></div>');
var marker = $('<div class="marker ui-widget-content"></div>');
marker.css({
"left": x,
"top": y
});
marker.attr("id", "point-" + pid++);
$(maps).append(marker)
$('.marker').draggable().resizable();
}
map.click(function (e) {
// var x = e.pageX - this.offsetLeft;
// var y = e.pageY - this.offsetTop;
var x = e.offsetX/ $(this).width() * 100 + '%';
var y = e.offsetY/ $(this).height() * 100 + '%';
// $(this).append('<div class="marker"></div>');
AddPoint(x, y, this);
});
// drag function
$(".ui-widget-content").draggable({
drag: function( event, ui ) {
var x = e.offsetX/ $(this).width() * 100 + '%';
var y = e.offsetY/ $(this).height() * 100 + '%';
}
});
});
style.css
.wrapper {
margin: 0 auto;
width: 100%;
min-height: 400px;
overflow: hidden;
}
.map {
width: 100%;
position: relative;
}
.map > img {
max-width: 100%;
max-height: 100%;
}
.marker {
width: 10px;
height: 10px;
border-radius: 50%;
background: rgba(255, 0, 0, 1);
position: absolute;
left: 50%;
top: 50%;
z-index: 999;
}
#mapa {
width: 30px;
height: 30px;
border-radius: 50%;
background: rgba(255, 0, 0, 1);
z-index: 999;
}
some html code
<div class="wrapper">
<div class="map">
<img src="http://i.imgur.com/HtxXGR5.jpg" width="100%" height="auto" margin="15px 0;" alt="">
</div>
<button id="remove">Remove all markers</button>
</div>
If you want to capture the position, after the drag is ended (fire 1 time per drag) you can do this:
$('.marker').draggable({
stop: function() {
var offset = $(this).offset();
var mapOffest = $('.map').offset();
var x = ((offset.left - mapOffest.left)/ ($(".map").width() / 100))+"%";
var y = ((offset.top - mapOffest.top)/ ($(".map").height() / 100))+"%";
// We need to do something with thoses vals uh?
$(this).css('left', x);
$(this).css('top', y);
// or
console.log('X:'+x + '||Y:'+y);
}
});
Fiddle here
Take note that the event has been set on the marker directy, this was probably your mistake.
The little calcul needs to take care of the map offset, which you don't need if your map is a full width/height (window size)
If you need, or prefer use the drag event rather than the stop, theses lines won't have any effects
$(this).css('left', x);
$(this).css('top', y);
But you'll still be able to capture the position, the console values will be goods.
Hope it may helps you.
problem solved, DFayet thank's again
final code
jQuery(document).ready(function($){
// basic add
$("button#remove").click(function(){
$(".marker").remove();
});
//add with position
var map = $(".map");
var pid = 0;
function AddPoint(x, y, maps) {
var marker = $('<div class="marker"></div>');
marker.css({
"left": x,
"top": y
});
marker.attr("id", "point-" + pid++);
$(maps).append(marker);
$('.marker').draggable({
stop: function(event, ui) {
var thisNew = $(this);
var x = (ui.position.left / thisNew.parent().width()) * 100 + '%';
var y = (ui.position.top / thisNew.parent().height()) * 100 + '%';
thisNew.css('left', x);
thisNew.css('top', y);
console.log(x, y);
}
});
}
map.click(function (e) {
var x = e.offsetX/ $(this).width() * 100 + '%';
var y = e.offsetY/ $(this).height() * 100 + '%';
AddPoint(x, y, this);
});
});

getting position of collada model in three.js

I have created a simple life bar using css.
#enemy {
background-color: black;
border-radius: 7px;
padding: 3px;
width: 100px;
}
#enemy div {
background-color: green;
width: 100%;
height: 20px;
border-radius: 5px;
}
I have to move the bar on top of the head of my collada model. how can i assign position of model to bar using jQuery? here is the code i tried but it doesn't work
var count =0;
for (var i = ai.length-1; i >= 0; i--) {
var a = ai[i];
// Move AI
var r = Math.random();
var c = getMapSector(a.position);
$('#enemy div').css({'position':'relative', 'top':c.z, 'left':c.x,});
if (c.x < -1 || c.x > mapW || c.z < -1 || c.z > mapH) {
ai.splice(i, 1);
scene.remove(a);
addAI();
}
}
function getMapSector(v) {
var x = Math.floor((v.x + UNITSIZE / 2) / UNITSIZE + mapW/2);
var z = Math.floor((v.z + UNITSIZE / 2) / UNITSIZE + mapW/2);
return {x: x, z: z};
}

how to animate div from its center

I am trying to animate a div tag from center. Initially I want the div tag to be none visible. when user clicks on link then this div tag should animate from its center. How can I achieve this using jquery. Here is my current code.
link one<br><br><br><br>
<section class="one">one</section>
here is css
.one {
margin: 0 auto;
width: 200px;
height: 200px;
border: 1px solid red;
background: lightblue;
}
and here is my jquery
$('a').on('click', function (e) {
e.preventDefault();
var w = 200; //$('.one').outerWidth();
var h = 200; //$('.one').outerHeight();
var x = $('.one').width() / 2;
var y = $('.one').height() / 2;
var startW = h - y/2;
var startH = w - x/2;
var endTop = y - h/2;
var endLeft = x - w/2;
$('.one').animate({
opacity: 1,
width: (w+200) + 'px',
height: (h+200) + 'px',
top: endTop+'px',
left: endLeft+'px'
}, 1000);
console.log(endLeft);
});
Something like this:
http://jsfiddle.net/TJNTq/
$('.linkone').on('click', function (e) {
e.preventDefault();
var w = 200; //$('.one').outerWidth();
var h = 200; //$('.one').outerHeight();
var x = $('.one').width() / 2;
var y = $('.one').height() / 2;
var startW = h - y/2;
var startH = w - x/2;
var endTop = y - h/2;
var endLeft = x - w/2;
$('.one').show().animate({
opacity: 1,
width: (w+200) + 'px',
height: (h+200) + 'px',
marginTop: 0 + 'px'
}, 1000);
console.log(endLeft);
});
note that your animations of top and left weren't doing anything because the .one div isn't positioned absolutely or relatively.

Categories