Draggable object animation in VueJS allows for smooth movement of

I'm currently working on developing draggable objects in Vue.js from scratch, but I've encountered two issues.

  1. After dragging, the object quickly snaps to the target coordinates without any transition effect.
  2. I attempted to eliminate the 'Ghosting image' by changing the opacity to 0% while dragging, but it doesn't seem to be effective.

Below is the code snippet I am currently implementing: https://jsfiddle.net/wmsk1npb/

<div id="app">
  {{x}}/{{y}} ....... {{coordinates}}
        <div class="bubbleMenuContainer" :style="coordinates" draggable="true" @drag="move" @dragend="set">
            Test
        </div>
</div>
new Vue({
  el: '#app',
  data: {
    x:0,
    y:0,
    coordinates:{
         top: "100px",
         left: "100px",
         opacity: "100%",
     }
    },
   methods:{
        move(event){
            this.x =  event.clientX;
            this.y =  event.clientY;
            this.coordinates.left = event.clientX + "px";
            this.coordinates.top = event.clientY + "px";
            this.coordinates.opacity = "0%;"
        },
        set(event){
            this.coordinates.left = event.clientX + "px";
            this.coordinates.top = event.clientY + "px";
            this.coordinates.opacity = "100%;"
        }
    }
})
.bubbleMenuContainer{
    position: absolute;
    border-radius: 100px;
    background-color: lightcoral;
    width: 30px;
    height: 30px;
    padding: 10px;
}

Answer №1

My approach to achieving draggable functionality differs from using draggable="true". Instead, I prefer utilizing mouse events such as up, down, and move (along with touch equivalents for touch-enabled devices).

This method provides greater control and eliminates the issue of overlapping items being displayed.

The concept behind this technique involves:

  • Tracking data like position, start drag position (x,y), and whether the item is currently being dragged
  • Setting isDragging to true and storing the initial drag position coordinates on mouse down event
  • Updating the position based on the difference between start drag and current clientXY if isDragging === true on mouse move
  • Resetting isDragging to false on mouse up event

For enhanced functionality, you can dynamically add and remove mousemove and mouseup listeners. Placing the mouse move listener on the document rather than the element itself is a more effective approach.

I recently wrote about implementing this process using the new Vue3 Composition API at https://dev.to/dasdaniel/vue3-compisition-api-craeting-a-draggable-element-fo6

Although it's specifically for Vue3 and not directly copy-paste friendly, the crucial logic is outlined below:

  const onMouseDown = e => {
    let { clientX, clientY } = e;
    position.dragStartX = clientX - position.x;
    position.dragStartY = clientY - position.y;

    position.isDragging = true;

    document.addEventListener("mouseup", onMouseUp);
    document.addEventListener("mousemove", onMouseMove);
  };

  const onMouseMove = e => {
    let { clientX, clientY } = e;
    position.x = clientX - position.dragStartX;
    position.y = clientY - position.dragStartY;
  };

  const onMouseUp = e => {
    let { clientX, clientY } = e;
    position.isDragging = false;
    position.dragStartX = null;
    position.dragStartY = null;
    document.removeEventListener("mouseup", onMouseUp);
    document.removeEventListener("mousemove", onMouseMove);
  };

Answer №2

The attribute "draggable" in HTML is used to determine if an element can be dragged. This behavior is native to browsers, and you can find more information about it here. The reason you see a "ghost image" when trying to drag the bubble is due to this browser behavior.

A simpler method for making an element draggable can be seen in this sample on JSFiddle here.

<div id="app" @mouseup="up" @mousemove="move">
  {{x}}/{{y}} ....... {{coordinates}}
  <div class="bubbleMenuContainer" :style="coordinates" @mousedown="down">
     Test
  </div>
</div>

down(e) {
  this.bubbleMenuClickState = true;
  this.offset = [
    e.target.offsetLeft - e.clientX,
    e.target.offsetTop - e.clientY
  ];
},
up(e) {
  this.bubbleMenuClickState = false;
},
move(e) {
  if (this.bubbleMenuClickState) {
     this.coordinates.left = (e.clientX + this.offset[0]) + "px";
     this.coordinates.top = (e.clientY + this.offset[1]) + "px";
  }
}

Here are the steps:

  1. Add a "mousedown" listener to calculate the offset of the bubble relative to its parent. Without this step, the initial click on the bubble may set its position unexpectedly since no mouse move event has occurred yet.
  2. Include a "mouseup" listener on the bubble's parent (such as #app) to detect when the user releases the click, preventing further movement caused by mouse events.
  3. Implement a "mousemove" listener to update the bubble's position while the user holds and drags it.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Keep the sub-menu in a kendo context menu from closing until the user either hovers over another menu item or clicks outside of the current item

Please take a look at this example: Due to the small size of sub-items, the sub-menu closes quickly when hovering over the menu and losing focus. My goal is to keep an opened sub-menu from closing until the user hovers over another menu item or clicks on ...

Generating a USA map with DataMaps in d3jsonData

I'm trying to create a basic US map using the DataMaps package and d3 library. Here's what I have attempted so far: <!DOCTYPE html> <html> <head> <title> TEST </title> <script src="https://d3js.org/d3.v5.js"> ...

Is there a way to trigger a modal to open in VueJS with Bootstrap?

I have been attempting to trigger a modal in my Vue Template using bootstrap. However, I am encountering an issue where the modal does not appear when I use jQuery on it. Below is the code snippet: <template> <div id="app_religion"> ...

Why do attributes of a directive fail to function within a different directive in AngularJS?

Trying to set attributes of the angularJS directive named ng-FitText within another angularJS directive called scroll-cards. Here's the approach I'm taking: In the code snippet below, the attribute data-fittest is being assigned from ng-FitText ...

How can I position text below a ticked checkbox?

Having an issue with my HTML and jQuery code. Everything is working fine, but when I click on a checkbox, the text "FINISHED" appears below all checkboxes instead of just the one I clicked on. This is my html code: $('.label__checkbox').cli ...

I need help with a process to extract information from a database and convert it into an object specifically for my situation

Currently, I am utilizing the postgres row_to_json function to retrieve data that has been stored using JSON.stringify(). However, upon retrieval and attempting to parse it with JSON.parse(), an error message stating "unexpected token ," is returned. The ...

Validating forms using TypeScript in a Vue.js application with the Vuetify

Currently, I am attempting to utilize Vue.js in conjunction with TypeScript. My goal is to create a basic form with some validation but I keep encountering errors within Visual Studio Code. The initial errors stem from my validate function: validate(): v ...

Insert a new class within the container div

I am looking to insert a 'disabled' class within a parent div named 'anchorxx' The disabled class div can be located anywhere within the anchorXX divs Is it achievable using jquery? I am unsure how to approach this task. Appreciate y ...

Experiencing difficulties when integrating the pdf-viewer-reactjs module within Next.js framework

I recently integrated the pdf-viewer-reactjs library into my Next.js project and encountered the following error: error - ./node_modules/pdfjs-dist/build/pdf.js 2094:26 Module parse failed: Unexpected token (2094:26) You may need an appropriate loader to h ...

Why won't the button's color change when I try clicking on it?

I am currently learning vue and facing some challenges. The code I have is supposed to change the button color when clicked, but it's not working as expected. Any advice on how to fix this issue would be greatly appreciated. Thank you! let app = ...

Exploring Selenium: Clicking on Auto-Complete Suggestions using Python

Attempting to interact with an auto-complete search bar on the site in order to search for results. Wanting to click on the drop-down element that appears after entering a city name to perform a full city name search and obtain results. Below is the cod ...

In terms of function efficiency, what yields better results: using conditional execution or employing conditional exit?

Feedback is welcomed on the efficiency of the following JavaScript/TypeScript solutions: function whatever(param) { if (param === x) { doStuff(); } } or function whatever(param) { if (param !== x) { return false; } doStuff(); } The se ...

What is the process for sending an image as input to a Django view using an Angular frontend?

I currently have a django web api with an angular frontend that allows users to upload and view images. My goal now is to expand this functionality: when the user clicks the "segment" button (see image), it should send the corresponding image to my python ...

Display an icon button when a user edits the text in a text field, and make it disappear once clicked on

Figuring out how to incorporate a v-text-area with an added button (icon) that only appears when the text within the text area is edited, and disappears once it is clicked on, has proven to be quite challenging. Below is a simplified version of my code to ...

When using the `mongoose find()` method, the returned _id may not match the one stored in

Just had a bizarre experience while working with MongoDB recently. It appears that when I make a query in a collection for a document, instead of returning the _id stored in the database, it generates a new _id for the queried document. For instance: In ...

Developing Your Own Local Variable in Angular with Custom Structural Directive ngForIn

I am hoping for a clear understanding of this situation. To address the issue, I developed a custom ngForIn directive to extract the keys from an object. It functions correctly with the code provided below: import {Directive, Input, OnChanges, SimpleChan ...

Uploading files to AWS-S3 using Angular $http PUT method: A step-by-step guide

When attempting to upload a file to AWS-S3 using $http.put(url, file) in my Angular application, I encounter an issue. The HTTP-403 Forbidden error message indicates that the signature calculated by S3 differs from the one I provided. However, if I use c ...

Eliminate any additional spacing within the pre/code tags

I am currently utilizing prism.js for code highlighting. I have encountered an issue where there are unnecessary white spaces at the top and bottom of my output. You can view a live example here. <pre> <code class="language-css"> &lt ...

Error encountered: MongoDB cast exception - nested subdocument

Check out this schema design: var messageSchema = new Schema({ receivers: [User], message: String, owner: { type: Schema.Types.ObjectId, ref: 'User' } }); var userSchema = new Schema({ name: String, photo: String }); var in ...

Tally of number series in an array

If my array looks like [0, 2, 4, 10, 10, 10, 10, 2, 5, 3, 2, 10, 10, 5, 7, 4, 10, 10, 10, 10] How do I determine the number of times a sequence of 10's occurs with at least 3 repetitions. In this example, the output would be 2 because there are 2 s ...