I am using the interact.js library for drag/drop functionality. I'm using raw images instead of divs as my draggable objects and this seems to work fine:
<img id="drag4" src="images/SVG/ksTire.svg" class="draggable js-drag" style="width:85px">
I cannot figure out how to return an image back to its original starting point before the drag began. I need to store the original coords in a js variable, and depending on certain events, return the image back to its exact original starting location. I experimented with various x/y coordinates on the event, and tried getElementById also, with no luck. Whenever I try to return the image back to its original location, some approaches will bring it back the first time, but then when I begin to drag it again, it's way off in a strange place, not under the mouse pointer anymore.
Could someone please provide a bit of sample code showing how to constantly snap a draggable object back to its initial location? I already figured out the places in code where to call this, all I need is how to get images back to the right place, and then to continue to behave properly after that occurs.
Note: interact.js isn't built on jquery, so I'd prefer a non-jquery solution in this particular case.
Here is the full contents of my dropzone.js, which is where most of the pertinent stuff happens related to this issue:
(function(interact) {
'use strict';
var transformProp;
var startPos = null;
var startX = 0;
var startY = 0;
var validDrop = false;
interact.maxInteractions(Infinity);
// setup draggable elements.
/* block below was copied from https://github.com/taye/interact.js/issues/79 -- try to get this working */
// setup drop areas.
setupDropzone('#drop1', '#drag1, #drag2, #drag4');
setupDropzone('#drop2', '#drag4');
setupDropzone('#drop4', '#drag4');
setupDropzone('#drop5', '#drag1, #drag2, #drag4');
setupDropzone('#drop6', '#drag3');
setupDropzone('#drop7', '#drag1');
/* SNAP code was copied from http://kundprojekt.soonce.com/lintex/zonbuilder/ and https://github.com/taye/interact.js/issues/79 -- try to get this working */
// dropzone #1 accepts draggable #1
//setupDropzone('#drop1', '#drag1');
// dropzone #2 accepts draggable #1 and #2
//setupDropzone('#drop2', '#drag1, #drag2');
// every dropzone accepts draggable #3
//setupDropzone('.js-drop', '#drag3');
/**
* Setup a given element as a dropzone.
*
* #param {HTMLElement|String} el
* #param {String} accept
*/
function setupDropzone(el, accept) {
interact(el)
.dropzone({
accept: accept,
ondropactivate: function(event) {
addClass(event.relatedTarget, '-drop-possible');
},
ondropdeactivate: function(event) {
removeClass(event.relatedTarget, '-drop-possible');
}
})
.snap({
mode: 'anchor',
anchors: [],
range: Infinity,
elementOrigin: {
x: 0.5,
y: 0.5
},
endOnly: true
})
.on('dropactivate', function(event) {
var active = event.target.getAttribute('active') | 0;
// change style if it was previously not active
if (active === 0) {
addClass(event.target, '-drop-possible');
//event.target.textContent = 'Drop me here!';
}
event.target.setAttribute('active', active + 1);
})
.on('dropdeactivate', function(event) { // this fires after each drop, whether a drop into a valid drop zone occurs or not
var active = event.target.getAttribute('active') | 0;
// change style if it was previously active
// but will no longer be active
if (active === 1) {
removeClass(event.target, '-drop-possible');
//event.target.textContent = 'Dropzone';
}
event.target.setAttribute('active', active - 1);
if (!validDrop) {
//document.getElementById("drag4").style.position = 'absolute';
//document.getElementById("drag4").style.left = startX + "px";
//document.getElementById("drag4").style.top = startY + "px";
}
})
.on('dragstart', function(event) {
// snap to the start position
if (!startPos) {
var rect = interact.getElementRect(event.target);
// record center point when starting the very first a drag
startPos = {
x: rect.left + rect.width / 2,
y: rect.top + rect.height / 2
}
}
event.interactable.snap({
anchors: [startPos]
});
})
.on('dragenter', function(event) {
addClass(event.target, '-drop-over');
var dropRect = interact.getElementRect(event.target),
dropCenter = {
x: dropRect.left + dropRect.width / 2,
y: dropRect.top + dropRect.height / 2
};
event.draggable.snap({
anchors: [dropCenter]
});
//event.relatedTarget.textContent = 'I\'m in';
})
.on('dragleave', function(event) {
removeClass(event.target, '-drop-over');
event.draggable.snap(false);
// when leaving a dropzone, snap to the start position
event.draggable.snap({
anchors: [startPos]
});
var svgFilename = getSVGFilename(event.relatedTarget.src);
if (document.getElementById("message").innerHTML) {
document.getElementById("message").innerHTML = document.getElementById("message").innerHTML.replace(svgFilename + "<br>", "");
}
//event.relatedTarget.textContent = 'Drag me…';
})
.on('drop', function(event) { // this only fires when an object is dropped into a valid drop zone for that object
validDrop = true;
removeClass(event.target, '-drop-over');
var svgFilename = getSVGFilename(event.relatedTarget.src);
document.getElementById("message").innerHTML += svgFilename + "<br>";
//event.relatedTarget.textContent = 'Dropped';
});
}
function getAbsolutePosition(el) {
var el2 = el;
var curtop = 0;
var curleft = 0;
if (document.getElementById || document.all) {
do {
curleft += el.offsetLeft - el.scrollLeft;
curtop += el.offsetTop - el.scrollTop;
el = el.offsetParent;
el2 = el2.parentNode;
while (el2 != el) {
curleft -= el2.scrollLeft;
curtop -= el2.scrollTop;
el2 = el2.parentNode;
}
} while (el.offsetParent);
} else if (document.layers) {
curtop += el.y;
curleft += el.x;
}
return [curleft, curtop];
};
function getSVGFilename(url) {
if (url.indexOf("/") > -1)
return url.substr(url.lastIndexOf('/') + 1);
else
return "";
}
function addClass(element, className) {
if (element.classList) {
return element.classList.add(className);
} else {
element.className += ' ' + className;
}
}
function removeClass(element, className) {
if (element.classList) {
return element.classList.remove(className);
} else {
element.className = element.className.replace(new RegExp(className + ' *', 'g'), '');
}
}
interact('.js-drag')
.draggable({
max: Infinity
})
.on('dragstart', function(event) {
validDrop = false;
event.interaction.x = parseInt(event.target.getAttribute('data-x'), 10) || 0;
event.interaction.y = parseInt(event.target.getAttribute('data-y'), 10) || 0;
var absolutePosition = getAbsolutePosition(event.target);
startX = absolutePosition[0];
startY = absolutePosition[1];
})
.on('dragmove', function(event) {
event.interaction.x += event.dx;
event.interaction.y += event.dy;
if (transformProp) {
event.target.style[transformProp] =
'translate(' + event.interaction.x + 'px, ' + event.interaction.y + 'px)';
} else {
event.target.style.left = event.interaction.x + 'px';
event.target.style.top = event.interaction.y + 'px';
}
})
.on('dragend', function(event) {
event.target.setAttribute('data-x', event.interaction.x);
event.target.setAttribute('data-y', event.interaction.y);
});
interact(document).on('ready', function() {
transformProp = 'transform' in document.body.style ? 'transform' : 'webkitTransform' in document.body.style ? 'webkitTransform' : 'mozTransform' in document.body.style ? 'mozTransform' : 'oTransform' in document.body.style ? 'oTransform' : 'msTransform' in document.body.style ? 'msTransform' : null;
});
}(window.interact));
And here is my base html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>WorkScreen Prototype #1</title>
<script src="js/interact.js"></script>
<script src="js/dropzones.js"></script>
<link rel="stylesheet" href="css/dropzones.css">
</head>
<body style="background-color: #CCC; height: 852px">
View All SVGs
<div style="margin-top:55px">
<div style="float: left; vertical-align: top">
<img id="drag1" src="images/SVG/ksBatteryBox.svg" class="draggable js-drag" style="width:80px"><br />
<img id="drag2" src="images/SVG/ksBumper6308700.svg" class="draggable js-drag" style="width:85px"><br />
<img id="drag3" src="images/SVG/ksHood8090130.svg" class="draggable js-drag" style="width:165px"><br />
<img id="drag4" src="images/SVG/ksTire.svg" class="draggable js-drag" style="width:85px"><br />
</div>
<div style="float: left;vertical-align:top;margin-left:-72px">
<div style ="margin-left:100px;">
<div id="drop1" class="dropzone js-drop" style="margin-left:186px;"></div>
<div id="drop2" class="dropzone js-drop" style="margin-left:90px"></div>
<div style="">
<div id="drop6" class="dropzone js-drop" style="clear: both; margin-left: 0px; margin-top: 37px"></div>
<div style="float:left"><img src="images/BaseTruck.png" /></div>
<div id="drop7" class="dropzone js-drop" style="float: left; margin-left: 251px; margin-top: 153px; position: absolute;"></div>
<div id="drop3" class="dropzone js-drop" style="float:left; margin-left:10px;margin-top:37px"></div>
</div>
<div id="drop5" class="dropzone js-drop" style="clear: both; margin-left: 186px;"></div>
<div id="drop4" class="dropzone js-drop" style="margin-left: 90px;"></div>
<br /><br />
<div id="message" style="clear: both; margin-left: 0px; margin-top: 44px; width: 245px; display: inherit; border: 2px solid gray; padding: 7px;"></div>
</div>
</div>
</div>
</body>
</html>
Here's the solution in case it helps others. No need to figure out exact location relative to window in order to return elements to their load-time position. Just do this:
function resetCoords(evt) {
evt.relatedTarget.style.left = "0px";
evt.relatedTarget.style.top = "0px";
evt.interaction.x = 0;
evt.interaction.y = 0;
}
And call resetCoords like this:
.on('dropdeactivate', function(event) { // this fires after each drop, whether a drop into a valid drop zone occurs or not
var active = event.target.getAttribute('active') | 0;
// change style if it was previously active
// but will no longer be active
if (active === 1) {
removeClass(event.target, '-drop-possible');
//event.target.textContent = 'Dropzone';
}
event.target.setAttribute('active', active - 1);
if (!validDrop) {
resetCoords(event);
}
})
In the .on('drop...) event you set validDrop to true, else it will be false.
Related
I've tried adding the top and left changes, and margin (with different positioning changes too) changes to each element if one approaches another but only the margin change works once. Is there a way to make them work more consistently?
This is where I've used a function to add the event listeners:
var three = document.getElementById('three');
var test = document.getElementById('test');
var two = document.getElementById('two');
var obj = null;
function testmovea(object, event) {
obj = document.getElementById(object.id);
document.addEventListener("mousemove", move);
}
function move(event) {
obj.innerText = event.clientX + ' ' + event.clientY;
obj.style.position = 'absolute';
obj.style.left = event.clientX + "px";
obj.style.top = event.clientY + "px";
three.addEventListener('mouseover', borders);
three.addEventListener('mouseleave', bordersOff);
two.addEventListener('mouseenter', bTwo);
test.addEventListener('mouseenter', bTest);
two.addEventListener('mouseleave', bTwoReset);
test.addEventListener('mouseleave', bTestReset);
document.addEventListener("mouseup", stopMove);
}
function bTwo() {
two.style.margin = "10%";
}
function bTwoReset() {
two.style.margin = "0%";
}
function bTest() {
test.style.margin = "10%";
}
function bTestReset() {
test.style.margin = "0%"
}
This is the mouse stop event I use:
function stopMove() {
document.removeEventListener('mousemove', move);
test.removeEventListener('mouseover', bTest);
two.removeEventListener('mouseover', bTwo);
test.removeEventListener('mouseleave', bTestReset);
two.removeEventListener('mouseleave', bTwoReset);
}
the testmovea function relies on a onmousedown property defined for a DOM element of the page
Update:
I've managed to get it to partially work:
function collide(el1, el2) {
if(twoBoundX >= threeBoundY || threeBoundY >= twoBoundX) {
two.style.margin = + event.clientX + "px";
two.style.margin = + event.clientY + "px";
}
}
where twoBoundX and threeBoundY are getBoundingClientRect() of the respective elements
Here's the full code snippet:
<html>
<head>
<style type="text/css">
#two {
border: 1px solid black;
padding: 1%;
margin: 1%;
margin-top: 10%;
width: 10%;
}
#three {
border: 1px solid black;
padding: 1%;
margin-top: 2%;
}
</style>
</head>
<body>
<div id="two" onmousedown="testmovea(this, event)" onclick="currentTwoPos()">
stop movement
</div>
<div id="three" onmousedown="testmovea(this)">Expand div</div>
<div style="height: 30%" id="two" contenteditable="true">
some contenteditable</div>
</body>
<script>
var three = document.getElementById('three');
var two = document.getElementById('two');
const twoBound = two.getBoundingClientRect();
const threeBound = three.getBoundingClientRect();
var threeBoundX = threeBound.x;
var threeBoundY = threeBound.y;
var twoBoundX = twoBound.x;
var twoBoundY = twoBound.y;
var twoBoundBottom = null;
var twoBoundTop = null;
var obj = null;
function collide(el1, el2) {
if(twoBoundX >= threeBoundY || threeBoundY >= twoBoundX) {
two.style.left = event.clientX + "px";
two.style.top = event.clientY + "px";
three.style.left = event.clientX + "px";
three.style.top = event.clientY + "px";
}
}
function testmovea(object, event) {
obj = document.getElementById(object.id);
document.addEventListener("mousemove", move);
}
function move(event) {
obj.innerText = event.clientX + ' ' + event.clientY;
obj.style.position = 'absolute';
obj.style.left = event.clientX + "px";
obj.style.top = event.clientY + "px";
two.addEventListener('mouseover', collide);
three.addEventListener('mouseover', collide);
document.addEventListener("mouseup", stopMove);
}
function stopMove() {
mousemove = false;
document.removeEventListener('mousemove', move);
three.removeEventListener('mouseover', collide);
two.removeEventListener('mouseover', collide);
}
</script>
</html>
collision detection
You need to define a function that checks whether two of your shapes collide. If you only have rectangles whose vertex are parallel with the OX and OY vertexes, it would look like this:
function areColliding(r1, r2) {
return !(
(r1.x > r2.x + r2.w) ||
(r1.x + r1.w < r2.x) ||
(r1.y > r2.y + r2.h) ||
(r1.y + r1.h < r2.y)
);
}
Of course, if some rotation or even other shapes are involved into your problem, then you need to extend/adjust the collision detector accordingly.
a shared function
You need to create a function that would receive the current status of the elements and the move that happens. It would look like this:
function handleMove(currentPositions, proposedPositions) {
while (!validPositions(proposedPositions)) {
proposedPositions = generateNewPositions(currentPositions, handleCollisions(proposedPositions));
}
refreshUI(proposedPositions);
}
currentPositions is the set of positions your elements currently have
proposedPositions is the set of positions your elements are going to have if there are no collisions
validPositions checks for any pair of shapes that would collide and returns true if none of those pair collide and false if at least one such pair collides
proposedPositions is being refreshed while there are still collisions
generateNewPositions is your handler for collision-based changes
handleCollisions effectuates changes to avoid collision
refreshUI refreshes the UI
event handling
your mouse events should handle change updates by loading all the positions of your elements and calling this shared functionality.
Note: If you have further problems, then you might need to create a reproducible example so we could see your exact structure, styling and code as well.
<html>
<head>
<style type="text/css">
#two {
border: 1px solid black;
width: 10%;
padding: 1%;
margin: 1%;
margin-top: 10%;
}
#three {
border: 1px solid black;
padding: 1%;
margin-top: 2%;
}
</style>
</head>
<body>
<div id="two" onmousedown="testmovea(this, event)" style="position: relative;">
stop movement
</div>
<div id="three" onmousedown="testmovea(this)" style="position: relative;">Expand div</div>
<!--<div style="height: 30%; position: relative;" id="two" contenteditable="true">
some contenteditable</div>-->
</body>
<script>
var three = document.getElementById('three');
var two = document.getElementById('two');
let moveStarted = false;
function collide() {
const first = two.getBoundingClientRect();
const second = three.getBoundingClientRect();
if (!(
(first.x + first.width < second.x) ||
(second.x + second.width < first.x) ||
(first.y + first.height < second.y) ||
(second.y + second.height < first.y)
)) {
two.style.left = event.clientX + "px";
two.style.top = event.clientY + "px";
three.style.left = event.clientX + "px";
three.style.top = event.clientY + "px";
}
}
function testmovea(object, event) {
obj = document.getElementById(object.id);
if (!moveStarted) {
document.addEventListener("mousemove", move);
moveStarted = true;
}
}
function move(event) {
//obj.innerText = event.clientX + ' ' + event.clientY;
obj.style.left = event.clientX + "px";
obj.style.top = event.clientY + "px";
if (!obj.classList.contains("dragged")) obj.classList.add("dragged");
collide(obj);
}
function stopMove() {
mousemove = false;
if (moveStarted) {
document.removeEventListener('mousemove', move);
moveStarted = false;
}
}
document.addEventListener("mouseup", stopMove);
</script>
</html>
OK so I've tried one thing from a different question and it worked, but not the way I wanted it to. it didn't work the way I wanted it to! You literally had to click when two objects were touching so it would alert you, if somebody can figure out a way to detect if two elements are touching without having to click that would be a life saver! So I hope you people who read this request please respond if you know how. this is the code below. so one object is moving and i want it to make it stop when the object hits the player (i am making a game) the movement is by px.... i want it to keep testing if one object hits the player, and if it does i want it to stop everything.
var boxes = document.querySelectorAll('.box');
boxes.forEach(function (el) {
if (el.addEventListener) {
el.addEventListener('click', clickHandler);
} else {
el.attachEvent('onclick', clickHandler);
}
})
var detectOverlap = (function () {
function getPositions(elem) {
var pos = elem.getBoundingClientRect();
return [[pos.left, pos.right], [pos.top, pos.bottom]];
}
function comparePositions(p1, p2) {
var r1, r2;
if (p1[0] < p2[0]) {
r1 = p1;
r2 = p2;
} else {
r1 = p2;
r2 = p1;
}
return r1[1] > r2[0] || r1[0] === r2[0];
}
return function (a, b) {
var pos1 = getPositions(a),
pos2 = getPositions(b);
return comparePositions(pos1[0], pos2[0]) && comparePositions(pos1[1], pos2[1]);
};
})();
function clickHandler(e) {
var elem = e.target,
elems = document.querySelectorAll('.box'),
elemList = Array.prototype.slice.call(elems),
within = elemList.indexOf(elem),
touching = [];
if (within !== -1) {
elemList.splice(within, 1);
}
for (var i = 0; i < elemList.length; i++) {
if (detectOverlap(elem, elemList[i])) {
touching.push(elemList[i].id);
}
}
if (touching.length) {
console.log(elem.id + ' touches ' + touching.join(' and ') + '.');
alert(elem.id + ' touches ' + touching.join(' and ') + '.');
} else {
console.log(elem.id + ' touches nothing.');
alert(elem.id + ' touches nothing.');
}
}
this is my video game right now (please do not copy)
<!DOCTYPE html>
/
<html>
<form id="player" class="box">
</form>
<button type="button" class="up" onclick="moveup()">^</button>
<button type="button" class="down" onclick="movedown()">v
</button>
<style src="style.css">
#player {
width: 300px;
height: 100px;
background-color: blue;
display: inline-block;
position: relative;
bottom: -250px;
left: 200px;
}
.up {
position: relative;
bottom: -400px;
}
.down {
position: relative;
bottom: -420px;
}
body {
background-color: black;
}
#car {
width: 300px;
height: 100px;
background-color: red;
display: inline-block;
position: relative;
bottom: -250px;
left: 600px;
}
</style>
<form id="car" class="box"></form>
<script>
imgObj = document.getElementById('player');
imgObj.style.position= 'relative';
imgObj.style.bottom = '-250px';
function moveup() {
imgObj.style.position= 'relative';
imgObj.style.bottom = '-250px';
imgObj.style.bottom = parseInt(imgObj.style.bottom) + 70 + 'px';
}
function movedown() {
imgObj.style.position= 'relative';
imgObj.style.bottom = '-250px';
imgObj.style.bottom = parseInt(imgObj.style.bottom) + -120 + 'px';
}
myMove();
function myMove() {
var elem = document.getElementById("car");
var pos = 0;
var id = setInterval(frame, 5);
function frame() {
if (pos == 1000) {
clearInterval(id);
myMove();
} else {
pos++;
elem.style.left = pos + "px";
elem.style.left = pos + "px";
}
}
}
/* please do not copy; this is it so far i want the red box when it hits the player(blue box) to stop everything that is happening */
/* made by Jsscripter; car game */
</script>
</html>
Intersection observer. API was largely developed because of news feeds and infinite scrolling. Goal was to solve when something comes into view, load content. Also is a great fit for a game.
The Intersection Observer API lets code register a callback function
that is executed whenever an element they wish to monitor enters or
exits another element (or the viewport), or when the amount by which
the two intersect changes by a requested amount. This way, sites no
longer need to do anything on the main thread to watch for this kind
of element intersection, and the browser is free to optimize the
management of intersections as it sees fit.
https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
All major browsers except safari support the API. For backwards compatibility and Safari support can use the polyfill from W3C found here. Check out this example from MDN:
var callback = function(entries, observer) {
entries.forEach(entry => {
// Each entry describes an intersection change for one observed
// target element:
// entry.boundingClientRect
// entry.intersectionRatio
// entry.intersectionRect
// entry.isIntersecting
// entry.rootBounds
// entry.target
// entry.time
});
};
var options = {
root: document.querySelector('#scrollArea'),
rootMargin: '0px',
threshold: 1.0
}
var observer = new IntersectionObserver(callback, options);
var target = document.querySelector('#listItem');
observer.observe(target);
See this in action here: https://codepen.io/anon/pen/OqpeMV
I need to modify a pasted image inside a contenteditable div: resize it proportionately, add borders, etc... Perhaps this can be achieved by adding a className that will alter the necessary CSS properties.
The problem is that I don't know how to reference the focused, i.e. the active, the clicked-upon image or any element for that matter.
This is the HTML that I am trying to use
<!DOCTYPE html>
<html>
<body>
<div contenteditable="true">This is a div. It is editable. Try to change this text.</div>
</body>
</html>
Using css, html and javascript
Your editable content should be inside a parent div with an id or class name, you can even have different divs for images and such.
Then it is as simple as having css like so:
#editableContentDiv img {
imgProperty: value;
}
Then you can have javascript like so:
function insertImage(){
var $img = document.querySelector("#editableContentDiv img");
$img.setAttribute('class','resize-drag');
}
Eventually if you have more than one img inside the same div you can use querySelectorAll instead of querySelector and then iterate through the img tags inside same div.
I beleive that should at least give you an idea of where to start with what you want.
Similar example
I found this gist that seems to have similar things to want you want but a bit more complicated.
function resizeMoveListener(event) {
var target = event.target,
x = (parseFloat(target.dataset.x) || 0),
y = (parseFloat(target.dataset.y) || 0);
// update the element's style
target.style.width = event.rect.width + 'px';
target.style.height = event.rect.height + 'px';
// translate when resizing from top or left edges
x += event.deltaRect.left;
y += event.deltaRect.top;
updateTranslate(target, x, y);
}
function dragMoveListener(event) {
var target = event.target,
// keep the dragged position in the data-x/data-y attributes
x = (parseFloat(target.dataset.x) || 0) + event.dx,
y = (parseFloat(target.dataset.y) || 0) + event.dy;
updateTranslate(target, x, y);
}
function updateTranslate(target, x, y) {
// translate the element
target.style.webkitTransform =
target.style.transform =
'translate(' + x + 'px, ' + y + 'px)';
// update the position attributes
target.dataset.x = x;
target.dataset.y = y;
}
function insertImage() {
var $img = document.createElement('img');
$img.setAttribute('src', 'https://vignette.wikia.nocookie.net/googology/images/f/f3/Test.jpeg/revision/latest?cb=20180121032443');
$img.setAttribute('class', 'resize-drag');
document.querySelector(".container-wrap").appendChild($img);
var rect = document.querySelector(".container-wrap").getBoundingClientRect();
$img.style.left = rect.left;
$img.style.top = rect.top;
}
function dataTransfer() {
//cleanup
var $out = document.querySelector(".out-container-wrap");
while ($out.hasChildNodes()) {
$out.removeChild($out.lastChild);
}
//get source
var source = document.querySelector('.container-wrap')
//get data
var data = getSource(source);
//add data to target
setSource($out, data);
}
/**
* Get data from source div
*/
function getSource(source) {
var images = source.querySelectorAll('img');
var text = source.querySelector('div').textContent;
//build the js object and return it.
var data = {};
data.text = text;
data.image = [];
for (var i = 0; i < images.length; i++) {
var img = {}
img.url = images[i].src
img.x = images[i].dataset.x;
img.y = images[i].dataset.y;
img.h = images[i].height;
img.w = images[i].width;
data.image.push(img)
}
return data;
}
function setSource(target, data) {
//set the images.
for (var i = 0; i < data.image.length; i++) {
var d = data.image[i];
//build a new image
var $img = document.createElement('img');
$img.src = d.url;
$img.setAttribute('class', 'resize-drag');
$img.width = d.w;
$img.height = d.h;
$img.dataset.x = d.x;
$img.dataset.y = d.y;
var rect = target.getBoundingClientRect();
$img.style.left = parseInt(rect.left);
$img.style.top = parseInt(rect.top);
//transform: translate(82px, 52px)
$img.style.webkitTransform = $img.style.transform = 'translate(' + $img.dataset.x + 'px,' + $img.dataset.y + 'px)';
//$img.style.setProperty('-webkit-transform', 'translate('+$img.dataset.x+'px,'+$img.dataset.y+'px)');
target.appendChild($img);
}
//make a fresh div with text content
var $outContent = document.createElement('div')
$outContent.setAttribute('class', 'out-container-content');
$outContent.setAttribute('contenteditable', 'true');
$outContent.textContent = data.text;
target.appendChild($outContent);
}
interact('.resize-drag')
.draggable({
onmove: dragMoveListener,
inertia: true,
restrict: {
restriction: "parent",
endOnly: true,
elementRect: {
top: 0,
left: 0,
bottom: 1,
right: 1
}
}
})
.resizable({
edges: {
left: true,
right: true,
bottom: true,
top: true
},
onmove: resizeMoveListener
})
.resize-drag {
z-index: 200;
position: absolute;
border: 2px dashed #ccc;
}
.out-container-content,
.container-content {
background-color: #fafcaa;
height: 340px;
}
#btnInsertImage {
margin-bottom: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="http://code.interactjs.io/interact-1.2.4.min.js"></script>
</head>
<body>
<button id="btnInsertImage" onclick="insertImage()">Insert Image</button>
<div class="container-wrap">
<div class="container-content" contenteditable="true">This is the content of the container. The content is provided along with the image. The image will be moved around and resized as required. The image can move within the boundary of the container.</div>
</div>
<button id="btnSubmit" onclick="dataTransfer()">Submit</button>
<div class="out-container-wrap">
</div>
</body>
</html>
Source
This is what I tried and it seems to be working - at least on my system, the snippet I made does not work unfortunately.
function getSelImg(){
var curObj;
window.document.execCommand('CreateLink',false, 'http://imageselectionhack/');
allLinks = window.document.getElementsByTagName('A');
for(i = 0; i < allLinks.length; i++)
{
if (allLinks[i].href == 'http://imageselectionhack/')
{
curObj = allLinks[i].firstChild;
window.document.execCommand('Undo'); // undo link
break;
}
}
if ((curObj) && (curObj.tagName=='IMG'))
{
//do what you want to...
curObj.style.border = "thick solid #0000FF";
}
}
<!DOCTYPE html>
<html>
<body>
<input type="button" onclick="getSelImg()" value="set img border">
<div contenteditable="true">This is a div.<br>
It is editable.<br>
Try to paste an image here:<br>
###########################<br>
<br>
<br>
<br>
###########################
</div>
</body>
</html>
I want to use the 'mouse's drag' to drag a background's position around, inside a box.
The CSS:
.filmmakers #map {
width : 920px;
height : 500px;
margin-top : 50px;
margin-left : 38px;
border : 1px solid rgb(0, 0, 0);
cursor : move;
overflow : hidden;
background-image : url('WorldMap.png');
background-repeat : no-repeat;
}
The html:
<div id = "map" src = "WorldMap.png" onmousedown = "MouseMove(this)"> </div>
The Javascript:
function MouseMove (e) {
var x = e.clientX;
var y = e.clientY;
e.style.backgroundPositionX = x + 'px';
e.style.backgroundPositionY = y + 'px';
e.style.cursor = "move";
}
Nothing happens, no errors, no warnings, nothing... I have tried lots of things: an absolutely positioned image inside a div (you can guess why that didn't work), A draggable div inside a div with a background image, a table with drag and drop, and finally I tried this:
function MouseMove () {
e.style.backgroundPositionX = 10 + 'px';
e.style.backgroundPositionY = 10 + 'px';
e.style.cursor = "move";
}
This works, but its not relative to the mouse's position, pageX and pageY don't work either.
A live demo: http://jsfiddle.net/VRvUB/224/
P.S: whatever your idea is, please don't write it in JQuery
From your question I understood you needed help implementing the actual "dragging" behavior. I guess not. Anyway, here's the results of my efforts: http://jsfiddle.net/joplomacedo/VRvUB/236/
The drag only happens when the mouse button, and.. well, it behaves as I think you might want it to. Just see the fiddle if you haven't =)
Here's the code for those who want to see it here:
var AttachDragTo = (function () {
var _AttachDragTo = function (el) {
this.el = el;
this.mouse_is_down = false;
this.init();
};
_AttachDragTo.prototype = {
onMousemove: function (e) {
if ( !this.mouse_is_down ) return;
var tg = e.target,
x = e.clientX,
y = e.clientY;
tg.style.backgroundPositionX = x - this.origin_x + this.origin_bg_pos_x + 'px';
tg.style.backgroundPositionY = y - this.origin_y + this.origin_bg_pos_y + 'px';
},
onMousedown: function(e) {
this.mouse_is_down = true;
this.origin_x = e.clientX;
this.origin_y = e.clientY;
},
onMouseup: function(e) {
var tg = e.target,
styles = getComputedStyle(tg);
this.mouse_is_down = false;
this.origin_bg_pos_x = parseInt(styles.getPropertyValue('background-position-x'), 10);
this.origin_bg_pos_y = parseInt(styles.getPropertyValue('background-position-y'), 10);
},
init: function () {
var styles = getComputedStyle(this.el);
this.origin_bg_pos_x = parseInt(styles.getPropertyValue('background-position-x'), 10);
this.origin_bg_pos_y = parseInt(styles.getPropertyValue('background-position-y'), 10);
//attach events
this.el.addEventListener('mousedown', this.onMousedown.bind(this), false);
this.el.addEventListener('mouseup', this.onMouseup.bind(this), false);
this.el.addEventListener('mousemove', this.onMousemove.bind(this), false);
}
};
return function ( el ) {
new _AttachDragTo(el);
};
})();
/*** IMPLEMENTATION ***/
//1. Get your element.
var map = document.getElementById('map');
//2. Attach the drag.
AttachDragTo(map);
This isn't working because you are passing the element "map" to your MouseMove function, and using it as both an event object and an element. You can fix this painlessly by using JavaScript to assign your event handler rather than HTML attributes:
<div id="map"></div>
And in your JavaScript:
document.getElementById('map').onmousemove = function (e) {
// the first parameter (e) is automatically assigned an event object
var x = e.clientX;
var y = e.clientY;
// The context of this is the "map" element
this.style.backgroundPositionX = x + 'px';
this.style.backgroundPositionY = y + 'px';
}
http://jsfiddle.net/VRvUB/229/
The downside of this approach is that the backgroundPositionX and backgroundPositionY style properties are not supported in all browsers.
You mention "an absolutely positioned image inside a div" which is probably the more compatible solution for this. To make this setup work, you need to set the position of the outer element to relative, which makes absolute child elements use its bounds as zero.
<div id="map">
<img src="" alt="">
</div>
CSS:
#map {
position:relative;
overflow:hidden;
}
#map img {
position:absolute;
left:0;
top:0;
}
Here it is applied to your code: http://jsfiddle.net/VRvUB/232/
This works 100%
Vanilla Javascript
document.getElementById('image').onmousemove = function (e) {
var x = e.clientX;
var y = e.clientY;
this.style.backgroundPositionX = -x + 'px';
this.style.backgroundPositionY = -y + 'px';
this.style.backgroundImage = 'url(https://i.ibb.co/vhL5kH2/image-14.png)';
}
document.getElementById('image').onmouseleave = function (e) {
this.style.backgroundPositionX = 0 + 'px';
this.style.backgroundPositionY = 0 + 'px';
this.style.backgroundImage = 'url(https://i.ibb.co/Ph9MCB2/template.png)';
}
.container {
max-width: 670px;
height: 377px;
}
#image {
max-width: 670px;
height: 377px;
cursor: crosshair;
overflow: hidden;
background-image: url('https://i.ibb.co/Ph9MCB2/template.png');
background-repeat: no-repeat;
}
<div class="container">
<div id="image">
</div>
</div>
I have a small problem with loading and position one of my images. The smallest one. I'm using spacegallery script (http://www.eyecon.ro/spacegallery/).
It's loading good, but i want it to position it in the corner of bigger image, and when i load my page for the first time, it's not positioned, when i reload it - it's all fine, but the first loading is wrong.
Here are the screens:
It's the first load without refreshing the site:
first load http://derivativeofln.com/withoutload.png
Second and next loads:
second load http://derivativeofln.com/withload.png
My HTML:
<div id="myGallery" class="spacegallery">
<img class="imaz" src=http://derivativeofln.com/magnifier.jpg />
<img class="aaa" src=images/bw1.jpg alt="" atr1="bw1" />
<img class="aaa" src=images/bw2.jpg alt="" atr1="bw2" />
<img class="aaa" src=images/bw3.jpg alt="" atr1="bw3" />
</div>
MY CSS:
#myGallery0 {
width: 100%;
height: 300px;
}
#myGallery0 img {
border: 2px solid #52697E;
}
a.loading {
background: #fff url(../images/ajax_small.gif) no-repeat center;
}
.imaz {
z-index: 10000;
}
.imaz img{
position: absolute;
left:10px;
top:10px;
z-index: 10000;
width: 35px;
height: 35px;
}
My Jquery main script file: (the first positioning instructions are on the bottom, so feel free to scroll down : ))
(function($){
EYE.extend({
spacegallery: {
animated: false,
//position images
positionImages: function(el) {
var top = 0;
EYE.spacegallery.animated = false;
$(el)
.find('a')
.removeClass(el.spacegalleryCfg.loadingClass)
.end()
.find('img.aaa')
.removeAttr('height')
.each(function(nr){
var newWidth = this.spacegallery.origWidth - (this.spacegallery.origWidth - this.spacegallery.origWidth * el.spacegalleryCfg.minScale) * el.spacegalleryCfg.asins[nr];
$(this)
.css({
top: el.spacegalleryCfg.tops[nr] + 'px',
marginLeft: - parseInt((newWidth + el.spacegalleryCfg.border)/2, 10) + 'px',
opacity: 1 - el.spacegalleryCfg.asins[nr]
})
.attr('width', parseInt(newWidth));
this.spacegallery.next = el.spacegalleryCfg.asins[nr+1];
this.spacegallery.nextTop = el.spacegalleryCfg.tops[nr+1] - el.spacegalleryCfg.tops[nr];
this.spacegallery.origTop = el.spacegalleryCfg.tops[nr];
this.spacegallery.opacity = 1 - el.spacegalleryCfg.asins[nr];
this.spacegallery.increment = el.spacegalleryCfg.asins[nr] - this.spacegallery.next;
this.spacegallery.current = el.spacegalleryCfg.asins[nr];
this.spacegallery.width = newWidth;
})
},
//constructor
init: function(opt) {
opt = $.extend({}, EYE.spacegallery.defaults, opt||{});
return this.each(function(){
var el = this;
if ($(el).is('.spacegallery')) {
$('')
.appendTo(this)
.addClass(opt.loadingClass)
.bind('click', EYE.spacegallery.next);
el.spacegalleryCfg = opt;
var listunia, images2 = [], index;
listunia = el.getElementsByTagName("img");
for (index = 1; index < listunia.length; ++index) {
images2.push(listunia[index]);
}
el.spacegalleryCfg.images = images2.length;
el.spacegalleryCfg.loaded = 0;
el.spacegalleryCfg.asin = Math.asin(1);
el.spacegalleryCfg.asins = {};
el.spacegalleryCfg.tops = {};
el.spacegalleryCfg.increment = parseInt(el.spacegalleryCfg.perspective/el.spacegalleryCfg.images, 10);
var top = 0;
$('img.aaa', el)
.each(function(nr){
var imgEl = new Image();
var elImg = this;
el.spacegalleryCfg.asins[nr] = 1 - Math.asin((nr+1)/el.spacegalleryCfg.images)/el.spacegalleryCfg.asin;
top += el.spacegalleryCfg.increment - el.spacegalleryCfg.increment * el.spacegalleryCfg.asins[nr];
el.spacegalleryCfg.tops[nr] = top;
elImg.spacegallery = {};
imgEl.src = this.src;
if (imgEl.complete) {
el.spacegalleryCfg.loaded ++;
elImg.spacegallery.origWidth = imgEl.width;
elImg.spacegallery.origHeight = imgEl.height
} else {
imgEl.onload = function() {
el.spacegalleryCfg.loaded ++;
elImg.spacegallery.origWidth = imgEl.width;
elImg.spacegallery.origHeight = imgEl.height
if (el.spacegalleryCfg.loaded == el.spacegalleryCfg.images) {
EYE.spacegallery.positionImages(el);
}
};
}
});
el.spacegalleryCfg.asins[el.spacegalleryCfg.images] = el.spacegalleryCfg.asins[el.spacegalleryCfg.images - 1] * 1.3;
el.spacegalleryCfg.tops[el.spacegalleryCfg.images] = el.spacegalleryCfg.tops[el.spacegalleryCfg.images - 1] * 1.3;
if (el.spacegalleryCfg.loaded == el.spacegalleryCfg.images) {
if(el.spacegalleryCfg.images == 3){
$('img.imaz', this).css('top', '27px'); // HERE IS POSITIONING OF MY IMAGES, WHEN SCRIPT LOADS FOR THE FIRST TIME!
$('img.imaz', this).css('left', (($(el).find('img.aaa:last').width())/2 + 77) + 'px' );
}
else if(el.spacegalleryCfg.images==2){
$('img.imaz', this).css('top', '33px');
$('img.imaz', this).css('left', (($(el).find('img.aaa:last').width())/2 + 77) + 'px' ); // HERE IT ENDS:)
}
EYE.spacegallery.positionImages(el);
}
}
});
}
}
});
})(jQuery);
this seems to be a cache thing
try to specify image dimensions (width and height) on your html, because on first load (images not in cache) the browser only knows dimensions after the load and the positioning might not be correct.
in alternative you can run your positioning code when the document is loaded
$(document).ready(«your poisitioning function here»)
see http://api.jquery.com/ready/ for that jquery ready function