<meta name="description" content="Drawing lines between DOM elements" />
<div id="textHolder">
<div class="text" id="text0" width=80>masă</div>
</div>
<div id="objectHolder">
<div id="obj0" class="obiecte" style="left:30%"><!--img class="obiecte" id="obj0" src="images/Macara.svg"></img-->beta</div>
</div>
<div id="status">status</div>
<div id="mova" style="position:absolute; z-index:100; background-color:blue; font-size:5px; width:5px"> </div>
<div id="movb" style="position:absolute; z-index:100; background-color:red; font-size:5px; width:5px"> </div>
.text {
float: left;
width:14%;
text-align: center;
background-color: #d0d0d0;
margin: 0;
border: solid 1px #afafaf;
}
.text:hover{background-color: #a6d9ff;}
.text:active{background-color: #ffbf75;}
.obiecte {
display: inline;
width:14%;
margin: .45%;
border: solid 1px #afafaf;
background-color: #f0f0f0;
}
.obiecte:hover{background-color: #a6d9ff;}
.obiecte:active{background-color: #ffbf75;}
#objectHolder {
position: absolute;
width: 100%;
top: 40%;
}
#textHolder {
position: absolute;
top: 10%;
width: 100%;
}
.text p {
line-height: 7;
font-weight: bolder;
color: #36618d;
}
img {
display:block;
}
canvas {
opacity: 50%;
background-color:pink;
border: 1px solid red;
}
// store our global state here
var clicked = [];
var hoverElement;
var statusDiv = document.getElementById('status');
function getCentreOfElement(el) {
var bounds = el.getBoundingClientRect();
return {x:bounds.left + bounds.width/2.0,
y:bounds.top + bounds.height/2.0};
}
function getNearestPointOutside(from, to, boxSize) {
// which side does it hit?
// get the angle of to from from.
// triangle centre, w/2, h/2, same as 0,w,h.
var theta = Math.atan2(boxSize.y, boxSize.x);
var phi = Math.atan2(to.y - from.y, to.x - from.x);
var nearestPoint = {};
if(Math.abs(phi) < theta) { // crosses +x
nearestPoint.x = from.x + boxSize.x/2.0;
nearestPoint.y = from.y + ((to.x === from.x) ? from.y :
((to.y - from.y)/(to.x - from.x) * boxSize.x/2.0));
} else if(Math.PI-Math.abs(phi) < theta) { // crosses -x
nearestPoint.x = from.x - boxSize.x/2.0;
nearestPoint.y = from.y + ((to.x === from.x) ? from.y :
(-(to.y - from.y)/(to.x - from.x) * boxSize.x/2.0));
} else if(to.y > from.y) { // crosses +y
nearestPoint.y = from.y + boxSize.y/2.0;
nearestPoint.x = from.x + ((to.y === from.y) ? 0 :
((to.x - from.x)/(to.y - from.y) * boxSize.y/2.0));
} else { // crosses -y
nearestPoint.y = from.y - boxSize.y/2.0;
nearestPoint.x = from.x - ((to.y === from.y) ? 0 :
((to.x - from.x)/(to.y - from.y) * boxSize.y/2.0));
}
return nearestPoint;
}
var lineElem;
function drawLineXY(fromXY, toXY) {
if(!lineElem) {
lineElem = document.createElement('canvas');
lineElem.style.position = "absolute";
lineElem.style.zIndex = -100;
document.body.appendChild(lineElem);
}
var leftpoint, rightpoint;
if(fromXY.x < toXY.x) {
leftpoint = fromXY;
rightpoint = toXY;
} else {
leftpoint = toXY;
rightpoint = fromXY;
}
var lineWidthPix = 4;
var gutterPix = 10;
var origin = {x:leftpoint.x-gutterPix,
y:Math.min(fromXY.y, toXY.y)-gutterPix};
lineElem.width = Math.max(rightpoint.x - leftpoint.x, lineWidthPix) +
2.0*gutterPix;
lineElem.height = Math.abs(fromXY.y - toXY.y) + 2.0*gutterPix;
lineElem.style.left = origin.x;
lineElem.style.top = origin.y;
var ctx = lineElem.getContext('2d');
// Use the identity matrix while clearing the canvas
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, lineElem.width, lineElem.height);
ctx.restore();
ctx.lineWidth = 4;
ctx.strokeStyle = '#09f';
ctx.beginPath();
ctx.moveTo(fromXY.x - origin.x, fromXY.y - origin.y);
ctx.lineTo(toXY.x - origin.x, toXY.y - origin.y);
ctx.stroke();
}
var movaDiv = document.getElementById('mova');
var movbDiv = document.getElementById('movb');
function moveHandler(evt) {
var startCentre, startBounds;
var movaBounds = movaDiv.getBoundingClientRect();
var targets = [];
if(clicked.length === 2) {
targets = clicked;
} else if(clicked.length === 1) {
targets.push(clicked[0]);
if(typeof hoverElement !== 'undefined') {
targets.push(hoverElement);
}
}
if(targets.length == 2) {
startCentre = getCentreOfElement(targets[0]);
startBounds = targets[0].getBoundingClientRect();
var endCentre = getCentreOfElement(targets[1]);
var endBounds = targets[1].getBoundingClientRect();
var start = getNearestPointOutside(startCentre, endCentre,
{x:startBounds.width,
y:startBounds.height});
var end = getNearestPointOutside(endCentre, startCentre,
{x:endBounds.width,
y:endBounds.height});
drawLineXY(start, end);
var movbBounds = movbDiv.getBoundingClientRect();
movaDiv.style.left = (start.x - movaBounds.width/2.0)+"px";
movaDiv.style.top = (start.y - movaBounds.height/2.0)+"px";
movbDiv.style.left = (end.x - movbBounds.width/2.0)+"px";
movbDiv.style.top = (end.y - movbBounds.height/2.0)+"px";
} else if(targets.length == 1) {
startCentre = getCentreOfElement(targets[0]);
startBounds = targets[0].getBoundingClientRect();
var startNearest = getNearestPointOutside(
startCentre, {x:evt.clientX, y:evt.clientY},
{x:startBounds.width, y:startBounds.height});
movaDiv.style.left = (startNearest.x - movaBounds.width/2.0)+"px";
movaDiv.style.top = (startNearest.y - movaBounds.height/2.0)+"px";
drawLineXY(startNearest, {x:evt.clientX, y:evt.clientY});
}
}
function clickHandler(evt) {
if(clicked.length == 2) {
clicked = [];
}
clicked.push(evt.target);
}
function hoverOverHandler(evt) {
hoverElement = evt.target;
}
function hoverOutHandler(evt) {
hoverElement = undefined;
}
var attachIds = ['text0', 'obj0'];
for(var ind = 0; ind < attachIds.length; ++ind) {
var el = document.getElementById(attachIds[ind]);
el.onclick = clickHandler;
el.onmouseover = hoverOverHandler;
el.onmouseout = hoverOutHandler;
}
window.onmousemove = moveHandler;
Output
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |