Move divs with mouseclick between div container - javascript

I would like to drag and drop divs within a container-div. Only up and down the list, using the mouse. How can I create this?
Searching the internet and stackoverflow didn't give me a good answer, since I would like to have it in vanilla Javascript and everything is nowadays in jQuery. :S
This is wat I have:
<div class="chapcontainer" data-chaporder="1000">
<div class="chapter">Big fire</div>
<div class="subchapter" data-chapid="1">Forest burning</div>
<div class="subchapter" data-chapid="2">Balu hoses</div>
<div class="subchapter" data-chapid="3">Forest animals die</div>
<div class="subchapter" data-chapid="4">Lovely fire</div>
</div>
</div>
The chapter-div is the container. Within this div I want to be able to move the subchapter-div with a click of the mousebutton up and down the list of subchapter-divs.
For example I move the subchapter-div with data-chapid 4 to the top, then it should be moved to the top and the data-chapid changed to 1. Is something like this possible in vanilla javascript?
I've read about AppendChild, but I don't know how I can trigger this with the mouse.

You could do it with jQuery:
$(".subchapter[data-chapid='1']").on("click", function() {
$(this).css('margin-left', '20px') // add margin/padding/etc here
})
Fiddle

Doing drag and drop yourself is complicated, but here are some of the basic steps. One advantage of rolling your own is you can do more advanced things than your standard jquery ui drag and drop can, like smooth scrolling the container, auto-opening nested tree items if the user hovers over them, or doing animations while moving items.
Steps:
Listen for mousedown events on your items in your container. When the user presses down on an item, store the mouse's offset relative to the top of container (this includes the scroll of the container). Also store the mouse's offset relative to the item being dragged.
Clone the element that's being dragged and absolute position it under the mouse, using the relative offset you stored in step 1.
Make the original element invisible.
Listen for mousemove events on your container. Reposition the dragged item appropriately.
As the mouse moves, you'll need to update the mouse's new offset from the top (including scroll) and figure out which item you're over. You can do this by getting the height of each item in your list. So if your mouse is 710 pixels from the top, and each item is 100 pixels high, you're over index 8. You can use this info to change the style of the item you're over to show that it's a drop target. One thing to watch out for is if you do any styling changes that change the heights of items, you'll need to recalculate your heights.
On mouseup, you already know which item you're over, so now you need to update your data array to move the dragged item, probably using array.splice. Delete the absolutely positioned dragged element, and rerender your list to reflect your changes. I'm assuming you're using some sort of templating library to render your stuff, or at least a render function that clears what's there and replaces it with the current state.

Related

Vue draggable with elements that change height upon being dragged

I have a Vue3 app with vue-draggable and I have a list of sortable cards which possibly contain long text inside. To make dragging easier, I want to hide the text contained in the cards and only show their title when one is being dragged. This makes it easier to drop the card into the right position.
In order to achieve this, the elements which I want to hide inside of the cards while one is being dragged are given a CSS class hidden-while-dragging and the whole collection receives a class dragging while an item is being dragged. This is achieved by setting a boolean variable to the correct value upon receiving the events start and end and conditionally setting the class on the whole <draggable> element. Then I have this CSS rule:
.dragging .hidden-while-dragging {
display: none;
}
This works fine except for one case: if I drag an element and, upon dragging, the height of the parent container changes (due to the disappearing of the content inside of the cards), I am not able to drag the item: it instantly gets dropped in place, and no end event is emitted, so for example the collection keeps the class dragging.
Afterwards, I am able to drop the element once again: the issue doesn't occur this time, because no change in height occurs, and after I drop the element, everything goes back to "normal".
I made this repo in order to have a reproducible example: https://github.com/samul-1/vue-draggable-bug-demo
Here's a codepen as well: https://codepen.io/samul-11/pen/mdjKvZa try and drag the first or last element and you'll see the issue.
You can observe the height of the #app element changing when dragging an element. An interesting thing is that this only happens if dragging the first or third item in my example, not the second. So apparenly the issue is with elements at the edge of the parent.
Is this a bug with the library or is there a way around it?

Drag and Drop Element into a Container fails with too many elements

I'm trying to use Drag and Drop to move <li> elements from one <ul> to another <ul>. I've got it working up to a point. My problem is I can't "drop" a <li> element when it's over another <li> element in my <ul> container. So when I fill up the visible portion of my container I can no longer drag and drop.
This CodePen demonstrates my problem.
not sure exactly what you are trying to achieve, if you want the drop target
to enlarge to accomodate, then be sure you set the CSS style on the target
with a text size using px definitions instead of pt specs.
then each time a drop occurs add to your drop routine to increase the size
of the drop target by the pixel height of 1 line of text. so it grows by 1 on
every drop, or the height is equal to lineHeight x (numElements + 1)
always leaving you room for 1 more drop
if you are trying to maintain a fixed size of the drop target, ie, you dont want
to move other elements down the page, take the above mentioned drop target
and put it inside a fixed size div with scrollable properties.
that way you have a drop element that can grow as described above,
but the fixed div constrains the screen real estate so the drop target doesnt
take up more space than you want
I solved my issue. I had to comment out an if statement in my handleDragOver function that was checking if the event.target was the dropzone element. I also changed my handleDrop function to use event.currentTarget instead of event.target

Transfer drag event - Jquery / UI

Ive got a problem here.
I want to make elements transfer their dragged event.
This means, I want to start dragging one element - and if this element reaches a point ( for example, left: 300 ) I want to hide the first element. Then I want to add a second element to the same drag event, for example an other div. So the drag will look like a single drag for the user but change its elements.
This should happen in one drag.
Anyone knows how I can make this?
An approach would be to use the drag event documented here:
http://jqueryui.com/draggable/#events
in the drag event check the left and top values and change the HTML of your helper element based on the left and top values of your drag event.
HTH

selecting an element on mouse click overlapped by another transparent div

I am working on a dashboard where user can drag and drop elements to create html pages.Now,he can have multiple images using an image component.We have managed to calculate the z-index of the images and they can be adjusted using up-down keys.
Issue:
The issue we are facing is when we select a image component we attach a dotted layer above it for helping the user to easily drag and resize it.If the user places the images as shown in the image below
we are not able to select the inner image again because the z-index of the selection div(the one with the blue dots) is(has to be) the highest(highest bcoz we have to use it for all components).So if I try to select the inner image now it cannot be selected.How can I handle the situation? For reference it works on this site as expected.
I believe we have get the element under the parent when it is clicked.But not sure how!We are using javascript,jquery to handle the events.
You can use JavaScript or jQuery to get the position of the inner image, and when the user clicks on the outer image, check to see whether the mouse position lies within the range of the smaller image. The range can be calculated with the position, width, and height of the inner element.
To get the element's position: use jQuery .offset() or .position() (The former is relative to the document, the latter to the parent).
To get the mouse position: http://docs.jquery.com/Tutorials:Mouse_Position
You could consider hiding the masking element quickly in order to gather the coordinate for your underlying element, when done, you could re enable visibility for the masking element. Use document.elementFromPoint() in order to get the DOM item from mouse coordinate.
An example:
http://jsfiddle.net/s94cnckm/14/
Alternatively you can use The CSS property pointer-events: none; on the masking element.
Related:
https://developer.mozilla.org/de/docs/Web/CSS/pointer-events
How to detecting a click under an overlapping element?

animating div elements left to right and back

I have a menu system made up of divs and i want to animate the left property to slide each time the user mouses over a menu item but i need the outer div(which is black) element to expand as the menu items move left to right also I want the div element(.container) to slide back and contract the outer div element(this black div which is 0 width) I have a basic example done in jsFiddle it olny moves the elements to the left
Having a little trouble fully understanding, but is this sort of what you mean?
http://jsfiddle.net/V3RHr/2/
If I could rewrite your html a bit, I would put make each .menu-item into an unordered list.
When you mouseenter the unordered list, you expand the second container. Inside that mouseenter function, I would have a second event when you mouseenter a list item, you populate the second container and stopPropogation.
You could probably still do it with a mouseenter on the first container, and another mouseenter on the div.menu-item, but your first container has extra height and width.
You should be able to fix the left is null issue by having the code not execute on the last .content, like this:
$('.container').not(':last').find('.menu-item').mouseenter(function () {
This will not apply to the menu-items within the green box.
For the re-show issue, I would change the way you are showing. Instead of sliding the box out from behind the other, you can position it where you want it to end up and hide it, then you can use:
.animate({width: 'show'})
Which will give a similar sliding effect.
That, or do it similar to my response to your other question, only without the collapsing I had previously:
http://jsfiddle.net/V3RHr/3/

Categories

Resources