I've started to build an drag and drop editor with html and Javascript. All in All it works fine.
You can drag images from a toolbar and drop them into the dropzone.
If you drop an image you actually create a copy of the original. thus you can drop them multiple times. The images get a left and top value to set their position. The value is relative (in %). Thats because it's possible to zoom in and out.
Now if I drop an image on another one it gets removed. Unfortunately I've got no idea how to prevent this.
I think The main issue is, that the dropped image becomes a child of the already dropped one and not of the dropzone. But preventing event capturing didn't helped.
It would be great if someone could help me out.
Here you see the main js drag and drop functions. I think thats the location where the problem can be solved. If you need any other code just let me know.
function allowDrop(ev) {
ev.preventDefault();
}
function DragStart(ev) {
ev.dataTransfer.setData("application/json", JSON.stringify([ev.target.id,(ev.offsetX || ev.clientX - $(ev.target).offset().left),(ev.offsetY || ev.clientY - $(ev.target).offset().top)]));
}
function DropIt(ev) {
ev.preventDefault();
var data = JSON.parse(ev.dataTransfer.getData("application/json"));
var width = document.getElementById("dropzone").clientWidth;
var height = document.getElementById("dropzone").clientHeight;
var copyimg = document.createElement("img");
var original = document.getElementById(data[0]);
copyimg.src = original.src;
ev.target.appendChild(copyimg);
copyimg.style.left =(ev.clientX - (screen.width - width) * 0.5 - data[1]) / width *100 + '%';
copyimg.style.top = (ev.clientY - screen.height * 0.2 - data[2]) / height *100 + '%';
return false;
}
}
You have to check the target element, if the element is an IMG type get the dropzone parent element:
supposing the dropzone is a <div> element
if(ev.target.tagName!="DIV")
ev.target=$(ev.target).closest('div')[0];
Related
I'm looking for a template for a responsive, dragable (horizontal resizeable) sidebar.
Optional based on bootstrap (I use bootstrap 4.6, but other version are fine), may make use of jQuery.
This for example fits my needs:
https://bootsnipp.com/snippets/BDWlD
But's it not dragable!
I've try to use some code for dragable divs, but they do not work because of the use of negative margins and some more to toogle sidebar in template above (and the most other respontive sidebar templates) (most all use negative margins to support css-animations).
One example, which didn't work: https://jsfiddle.net/RainStudios/mw786v1w/, but I'd try a lot more
var element = document.getElementById('element');
var resizer = document.createElement('div');
resizer.className = 'resizer';
resizer.style.width = '10px';
resizer.style.height = '10px';
resizer.style.background = 'red';
resizer.style.position = 'absolute';
resizer.style.right = 0;
resizer.style.bottom = 0;
resizer.style.cursor = 'se-resize';
element.appendChild(resizer);
resizer.addEventListener('mousedown', initResize, false);
function initResize(e) {
window.addEventListener('mousemove', Resize, false);
window.addEventListener('mouseup', stopResize, false);
}
function Resize(e) {
element.style.width = (e.clientX - element.offsetLeft) + 'px';
element.style.height = (e.clientY - element.offsetTop) + 'px';
}
function stopResize(e) {
window.removeEventListener('mousemove', Resize, false);
window.removeEventListener('mouseup', stopResize, false);
}
So I look for a joined code from both or a other template for a dragable responsive sidebar.
(If possible without big libaraies, because I still have to further develop the code.)
I've google a lot but did not find a well solutions.
A more detailed description of the problem:
The width of the sidebar (e.g. 250px) and a negative margin (-250px) with the same value is set in one class (in the example of the link from above #sidebar-wrapper). In a second class, the padding is set to 250px. If the second class is active, the sidebar is shown, otherwise it is hidden.
To modify that dynamicly is tricky.
To adjust this dynamically, I would have to adjust all three classes dynamically, which is possible but very cumbersome and ugly.
Alternatively I would have to write the sidebar handling completely new in JS without classes (directly assigned values) incl. the responsive variants (from media queries). Also not nice. May there is a way to dynamicly compute the values in css??
Any idea?
Some links are suffient, I do the rest.
Or an idea to handle that CSS-stuff (must not be complete code)
(At the end should end up in a help page with a table of contents in the sidebar, a search with instant search via ajax and a load of the help content also via ajax in the main div. But I'm not worried about this part, I've built something like that before - but if I find something ready-made, I won't say no ;-) )
Finaly I managed by myself:
Changes to above:
var wrapperElement = document.getElementById('wrapper');
...
function Resize(e) {
element.style.width = (e.clientX - element.offsetLeft) + 'px';
wrapperElement.style.paddingLeft = (e.clientX - element.offsetLeft) + 'px'; /new
}
Changes to script from Sidebar-Example:
$("#menu-toggle").click(function(e) {
e.preventDefault();
$("#wrapper").toggleClass("toggled");
element.style.width = ""; //new
wrapperElement.style.paddingLeft = ""; // new
});
Full code: https://codepen.io/MichaelBootstrap/pen/BapJzYz
This works fine.
Disadvantages:
After fading in and out, the sidebar has the old width again.
There are still problems when the sidebar becomes too small
Draging is not so smooth
If some one have a besser solution, then I would be very pleased.
I am trying to make an image get attached to the mouse and it isn't showing up correctly when I hover over the image. I need to make it so that the image preview that is trailing the mouse and is larger on the mouse preview.Could you please help me?
Here is the fiddle:
https://jsfiddle.net/pgyt1qpg/1/
here is the code:
document.querySelector('.container').addEventListener('mouseover', function(e) {
e.preventDefault();
if (e.target.tagName === 'IMG') {
//create the div tag for preview
var myElement = document.createElement('div');
myElement.className = 'preview';
e.target.parentNode.appendChild(myElement);
//Create the image element for preview
var myImg = document.createElement('img');
var imgLoc = e.target.src;
myImg.src = imgLoc;
myElement.style.left = e.offsetX + 15 + 'px';
myElement.style.top = e.offsetY + 15 + 'px';
myImg.style.width = "500px";
myImg.style.height = "500px";
myElement.style.zIndex = "-1";
myElement.appendChild(myImg);
//When mouse goes out of the image delete the preview
e.target.addEventListener('mouseout', function handler(d) {
var myNode = d.target.parentNode.querySelector('div.preview');
myNode.parentNode.removeChild(myNode);
e.target.removeEventListener('mouseout', handler, false);
}, false);
//place the image 15 inches to the bottom, right of the mouse
e.target.addEventListener('mousemove', function(f) {
myElement.style.left = f.offsetX + 15 + 'px';
myElement.style.top = f.offsetY + 15 + 'px';
});
}
}, false);
UPDATE:
I have updated the fiddle (many thanks to peter) and the image is on the right side now. I just need to make it closer to the mouse. How do I go about doing that?
Problem 1: Getting the hover preview to follow the mouse.
Solution: Add relative or absolute positioning.
myElement.style.position = 'absolute';
Problem 2: Getting the hover preview to appear above the thumbnails.
Solution (creates new problem though): Raise z-index to 2.
This will create the problem of the hover preview interrupting the hover event over the thumbnail when it appears. You can solve this by checking the mouse coordinates in the mouseout event and seeing if they are actually outside the bounds of the selected triggered thumbnail. If they are not, you cancel the preview close because it's just the interruption. There are other ways to do it but you seem comfortable with the coordinates so that's what came to mind.
Also, you need to adjust the mouse tracking coordinates to make it line up with the actual cursor better. That should get you moving, feel free to update the Fiddle and ask if there's more problems.
I can't comment.. But to answer your last question in the answer's comments I believe you are going to have to do something like this.
You will have to reload the image to get the original size.
How do I move the background position of the image so it stays between 2 elements as the page resizes?
I managed to get it working for the first one with some Javascript but that same function doesn't work for the second one.
This is what I'm getting. Here's the link.
The bottom leaf moves too much and I need it to stay between the cat and text
This is the Javascript I've got for the first leaf.
function bgPos(){
var w = $(window).width() - $('.container').width();
w = w*2;
$('.class2').css('background-position', w+'px 0')
}
$(window).on('resize', bgPos).trigger('resize');
Any ideas?
Your bgPos function fort .class2 should look very similar to bgPos function which you use for class1, but with with a horizontal delta (I've used value 500)
var w = $(window).width() - $('.container').width();
w = w/2-500;
$('.class2').css('background-position', w+'px 0')
This delta is a distance that should be kept between these "green" leaps on resize. You could find better value to keep it sharply perfect
Is it possible to slow down the speed of a draggable element?
I have build a simple slider with jQuery drag and drop. When the slider element (the draggable element) moves to certain positions a picture fades in. So if you move the draggable element not too fast it looks like you can handle a "picture animation" with the slider. Now, I want to slow down the draggable element. So the user never can drag the element too fast.
This is an example of my code.
$('.slider').mousemove(function(){
if($(this).position().left >= 0 && $(this).position().left <= 2 ) {
$('.slider_1').fadeIn();
$('.slider_2').fadeOut();
}
...
I hope someone can help me :)
Ah! finally an interesting jQuery question.
This can definitely be achieved. Below I've explained how. If you want to go straight to the demo, click here.
Let's assume your HTML is setup as follows:
<div id="slider">
<div id="bar"></div>
</div>
Where the bar is the actual thing you click and drag.
Now what you need to do is the following:
get the $('#bar').offset().left
explicitly specify the position of #bar when the draggable is dragged, using some extra variable SPEED
For example:
ui.position.left += (ui.offset.left - ui.originalPosition.left - leftOffset)*SPEED;
Then, you can use the $('#bar').offset().left in jQuery's .fadeTo() (or other) function to change the opacity of the image you are talking about.
This all seems rather trivial, but it's not. There are some problems when trying to implement this. For example:
When the slider reaches the maximum sliding distance, it should stop animating or be reset. You can do this in multiple ways but I think the easiest solution is to write a .mousedown / .mouseup listener which updates a variable dragging, that keeps track whether the user is still trying to drag #bar. If it's not, reset #bar. If it is, keep the slider at the maximum distance until .mouseup is fired.
Also, you must be careful with predefined borders.
The code I propose is the following:
// Specify your variables here
var SPEED = -0.6;
var border = 1; // specify border width that is used in CSS
var fadeSpeed = 0; // specify the fading speed when moving the slider
var fadeSpeedBack = 500; // specify the fading speed when the slider reverts back to the left
// Some pre-calculations
var dragging = false;
var slider = $('#slider');
var leftOffset = slider.offset().left + border;
var adjustedSliderWidth = 0.5*slider.width();
// the draggable function
$('#bar').draggable({
axis: "x",
revert : function(event, ui) {
$(this).data("draggable").originalPosition = {
top : 0,
left : 0
};
$('#image').fadeTo(fadeSpeedBack, 0);
return !event;
},
drag: function (event, ui) {
var barOffset = $('#bar').offset().left - leftOffset;
if (barOffset >= 0) {
if (barOffset < adjustedSliderWidth) {
ui.position.left += (ui.offset.left - ui.originalPosition.left - leftOffset)*SPEED;
} else {
if (!dragging) { return false; }
else { ui.position.left = adjustedSliderWidth; }
}
}
// fading while moving:
$('#image').fadeTo(fadeSpeed, (ui.position.left/adjustedSliderWidth));
// remove this if you don't want the information to show up:
$('#image').html(ui.position.left/adjustedSliderWidth
+"<br \><br \>"
+ui.position.left);
}
});
// the mouse listener
$("#bar").mousedown(function(){ dragging = true; });
$("#bar").mouseup(function(){ dragging = false; });
I've also implemented the revert option on draggable so the slider nicely returns to zero when the user releases #bar. Of course you can delete this if you want.
Now the variable that your whole question is about is the variable: SPEED.
You can specify the speed of dragging by specifying a number for this variable.
E.g.:
var SPEED = 0.0; // the normal dragging speed
var SPEED = 0.5; // the dragging speed is 1.5 times faster than normal
var SPEED = -0.5; // the dragging speed is 0.5 times faster than normal
So negative values give a slower dragging speed and positive values give a faster dragging speed.
Unfortunately (or actually: fortunately), it is not possible to change the speed of the mouse pointer. This because only the OS has control over the mouse coordinates and speed. Browsers cannot influence this. Personally I think it doesn't matter: moving the slider slower than normal is what you're trying to achieve, so you can ignore the mouse pointer.
To see all this in action, I've prepared a working jsFiddle for you:
DEMO
I hope this helps you out :)
Simple, I just would like to have it so when a user is dragging an item and they reach the very bottom or top of the viewport (10px or so), the page (about 3000px long) gently scrolls down or up, until they move their cursor (and thus the item being dragged) out of the region.
An item is an li tag which uses jquery to make the list items draggable. To be specific:
../jquery-ui-1.8.14.custom.min.js
http://code.jquery.com/jquery-1.6.2.min.js
I currently use window.scrollBy(x=0,y=3) to scroll the page and have the variables of:
e.pageY ... provides absolute Y-coordinates of cursor on page (not relative to screen)
$.scrollTop() ... provides offset from top of page (when scroll bar is all the way up, it is 0)
$.height()... provides the height of viewable area in the user's browser/viewport
body.offsetHeight ... height of the entire page
How can I achieve this and which event best accommodates this (currently its in mouseover)?
My ideas:
use a an if/else to check if it is in top region or bottom, scroll up if e.pageY is showing it is in the top, down if e.page& is in bottom, and then calling the $('li').mouseover() event to iterate through...
Use a do while loop... this has worked moderately well actually, but is hard to stop from scrolling to far. But I am not sure how to control the iterations....
My latest attempt:
('li').mouseover(function(e) {
totalHeight = document.body.offsetHeight;
cursor.y = e.pageY;
var papaWindow = window;
var $pxFromTop = $(papaWindow).scrollTop();
var $userScreenHeight = $(papaWindow).height();
var iterate = 0;
do {
papaWindow.scrollBy(0, 2);
iterate++;
console.log(cursor.y, $pxFromTop, $userScreenHeight);
}
while (iterate < 20);
});
Works pretty well now, user just needs to "jiggle" the mouse when dragging items sometimes to keep scrolling, but for scrolling just with mouse position its pretty solid. Here is what I finally ended up using:
$("li").mouseover(function(e) {
e = e || window.event; var cursor = { y: 0 }; cursor.y = e.pageY; //Cursor YPos
var papaWindow = parent.window;
var $pxFromTop = $(papaWindow).scrollTop();
var $userScreenHeight = $(papaWindow).height();
if (cursor.y > (($userScreenHeight + $pxFromTop) / 1.25)) {
if ($pxFromTop < ($userScreenHeight * 3.2)) {
papaWindow.scrollBy(0, ($userScreenHeight / 30));
}
}
else if (cursor.y < (($userScreenHeight + $pxFromTop) * .75)) {
papaWindow.scrollBy(0, -($userScreenHeight / 30));
}
}); //End mouseover()
This won't work as the event only fires while you're mouse is over the li.
('li').mouseover(function(e) { });
You need to be able to tell the position of the mouse relative to the viewport when an item is being dragged. When the users starts to drag an item attach an 'mousemove' event to the body and then in that check the mouse position and scroll when necessary.
$("body").on("mousemove", function(event) {
// Check mouse position - scroll if near bottom or top
});
Dont forget to remove your event when the user stops dragging.
$("body").off("mousemove", function(event) {
// Check mouse position - scroll if near bottom or top
});
This may not be exactly what you want, but it might help. It will auto-scroll when the mouse is over the 'border of the screen' (a user defined region). Say you have a 40px wide bar on the right of the screen, if the mouse reaches the first 1px, it will start scrolling. Each px you move into it, the speed will increase. It even has a nice easing animation.
http://www.smoothdivscroll.com/v1-2.htm
I get a weekly newsletter (email) from CodeProject, and it had some stuff that certainly looks like it will solve my problem... hopefully this can help others:
http://johnpolacek.github.com/scrollorama/ -- JQuery based and animates the scroll
https://github.com/IanLunn/jQuery-Parallax -- JQuery based, similar to above
http:// remysharp. com/2009/01/26/element-in-view-event-plugin/ -- JQuery, detects whether an element is currently in view of the user (super helpful for this issue!)
Also the site in #2 had some interesting code:
var windowHeight = $window.height();
var navHeight = $('#nav').height() / 2;
var windowCenter = (windowHeight / 2);
var newtop = windowCenter - navHeight;
//ToDo: Find a way to use these vars and my original ones to determine scroll regions