2016-07-11 12 views
5

Ich versuche, eine schöne Drag & Drop auf einer Leinwand, die 3 Festplatten darstellt.Nice Drag and drop auf einer Leinwand HTML5

Ich möchte mit der Maus die Position jeder Masse ändern. Mein Hauptproblem ist, dass ich durch die Länge der Axt für jede dieser 3 Kugeln eingeschränkt bin.

Im Moment habe ich die folgende Funktion implementiert, wenn die Maus innerhalb der Leinwand bewegt (Wert von indexMass zeigt an, welche Masse bewegt wird: 1, 2 or 3 und t1, t2, t3 für jeweils the angle of mass 1, 2, 3):

// Happens when the mouse is moving inside the canvas 
function myMove(event) { 

    if (isDrag) { 
    var x = event.offsetX; 
    var y = event.offsetY; 

    if (indexMass == 1) 
     { // Update theta1 value 
     t1 = t1 + 0.1*Math.atan(y/x); 
     } 
    else if (indexMass == 2) 
     { // Update theta2 value 
     t2 = t2 + 0.1*Math.atan(y/x); 
     } 
    else if (indexMass == 3) 
     { // Update theta3 value 
     t3 = t3 + 0.1*Math.atan(y/x); 
     } 

    // Update drawing 
    DrawPend(canvas); 

    }  

} 

Wie Sie sehen können ich für jeden Winkel tat:

t = t + 0.1*Math.atan(y/x); 

mit:

var x = event.offsetX; 
var y = event.offsetY; 

Aber dieser Effekt ist nicht sehr nett. Sobald die Kugel mit der Maus ausgewählt wurde (per Mausklick), möchte ich, dass der Cursor mit dieser Kugel oder der Kugel verbunden wird, um den "delta" der Mauskoordinaten zu folgen, wenn ich nicht mehr auf der Kugel bin.

Zusammengefasst, ich weiß nicht, wie man eine feine und benutzerfreundliche Drag & Drop erstellen, wenn jemand mir helfen oder mir einige Ratschläge geben könnte, wäre das großartig.

Dank

UPDATE 1

@ Blindman67: Danke für Ihre Hilfe, ist Ihr Code-Snippet ziemlich komplex für mich, ich das alles nicht verstehen. Aber ich bin auf dem richtigen Weg.

Ich beginne mit dem ersten Problem: Machen Sie die ausgewählte Festplatte mit der Maus drehen sehr geschlossen zu bleiben oder darüber, beim Ziehen.

Im Moment habe ich meine Funktion geändert myMove (die, wenn ich nach unten geklickt haben genannt wird und die Maus zum Ziehen bewegen) wie:

// Happens when the mouse is moving inside the canvas 
function myMove(event) { 

    // If dragging 
    if (isDrag) { 

    // Compute dx and dy before calling DrawPend 
    var lastX = parseInt(event.offsetX - mx); 
    var lastY = parseInt(event.offsetY - my); 

    var dx = lastX - window['x'+indexMass]; 
    var dy = lastY - window['y'+indexMass]; 

    // Change angle when dragging 
    window['t'+indexMass] = Math.atan2(dy, dx); 

    // Update drawing 
    DrawPend(canvas); 

    // Highlight dragging disk 
    fillDisk(indexMass, 'pink'); 

    }      

} 

wo indexMass ist der Index der geschleppt Platte und window['x'+indexMass], window['y'+indexMass] sind die aktuellen Koordinaten des ausgewählten Datenträgerzentrums.

Nach berechne ich die dx, dy jeweils von Koordinaten Maus geklickt, wenn drag Starten (mx, my durch getMousePos function zurückgegeben) und Maus-Koordinaten mit bewegt.

Schließlich ändere ich den Winkel der Platte durch Satz, für globalen Variable (Theta von ausgewählter Platte), das heißt window['t'+indexMass]:

// Change angle when dragging 
window['t'+indexMass] = Math.atan2(dy, dx); 

Ich habe Ihren Teil des Codes nahm mit Math.atan2.

Aber das Ergebnis dieser Funktion macht keine gute Animation mit Maus ziehen, ich würde gerne wissen, wo das herkommen könnte.

Im Moment möchte ich nur das Ziehen implementieren, ohne die Länge der Achse zu ändern, ich werde später mehr für diese Funktionalität sehen.

UPDATE 2

Ich komme immer auf eine Lösung über das Ziehen einer ausgewählten Masse mit der Maus zu finden.

Für den Versuch einer Synthese von dem, was ich zuvor getan habe, glaube ich, die folgende Methode ist gut, aber diese Methode zum Ziehen funktioniert nicht sehr gut: die ausgewählte Festplatte folgt nicht korrekt die Maus und ich weiß es nicht Warum.

In myMove function (Funktion wird aufgerufen, wenn I Ziehen Start), entschied ich:

  1. Berechne die dx, dy zwischen den Mauskoordinaten und den ausgewählten Plattenkoordinaten, das heißt:

var dx = parseInt (event.offsetX - Fenster ['x' + indexMass]);

var dy = parseInt (event.offsetY - fenster ['y' + indexMass]);

indexMass repräsentiert den Index der ausgewählten Festplatte.

  1. Inkrementieren der Position der ausgewählten Platte durch dx, dy (in temporären Variablen tmpX, tmpY gespeichert).

  2. Berechne der neue Winkel theta (identifiziert in Code durch globale Variable window['t'+indexMass]

  3. Berechne die neuen Positionen der ausgewählten Platte mit diesem neuen Wert von theta, also beispielsweise mit disk1 (indexMass=1 und Theta = t1):

    x1= x0 +l1 * sin(t1) 
    y1= y0 +l1 * sin(t1) 
    

ich muss Sie feststellen, dass ich mit der Maus wollen ziehen nicht die Längen zu ändern Achsen mit der Maus, das ist eine Einschränkung.

Hier ist das gesamte myMove function (aufgerufen, wenn Drag beginnt):

// Happens when the mouse is moving inside the canvas 
function myMove(event) { 

    // If dragging 
    if (isDrag) { 

    console.log('offsetX', event.offsetX); 
    console.log('offsetY', event.offsetY); 
    var dx = parseInt(event.offsetX - window['x'+indexMass]); 
    var dy = parseInt(event.offsetY - window['y'+indexMass]); 
    console.log('dx', dx); 
    console.log('dy', dy); 

     // Temp variables 
     var tmpX = window['x'+indexMass]; 
     var tmpY = window['y'+indexMass]; 

     // Increment temp positions 
     tmpX += dx; 
     tmpY += dy; 
     // Compute new angle for indexMass 
     window['t'+indexMass] = Math.atan2(tmpX, tmpY); 
     console.log('printf', window['t'+indexMass]); 

     // Compute new positions of disks 
     dragComputePositions(); 

     // Update drawing 
     DrawPend(canvas); 

     // Highlight dragging disk 
     fillDisk(indexMass, 'pink'); 

    } 
} 

UPDATE 4 - Bounty:

Problem gelöst! Ich habe vergessen, die Position von "indexMass-1" Disk zu berücksichtigen, um den neuen Winkel mit Math.atan2 Funktion zu berechnen.

Antwort

5

Sie können die Betriebssystemmausposition nicht verschieben. Sie können die Maus verstecken canvas.style.cursor = "none"; und dann zeichnen Sie eine Maus auf der Leinwand selbst, aber es wird hinter einem Frame zurückbleiben, weil, wenn Sie die Maus Koordinaten erhalten das Betriebssystem hat bereits die Maus an dieser Position platziert, und wenn Sie requestAnimationFrame (RAF) Die nächste Präsentation der Zeichenfläche wird beim nächsten Aktualisierungsintervall für die Anzeige angezeigt. Wenn Sie RAF nicht verwenden, können Sie die Zeichenfläche bei der aktuellen Bildschirmaktualisierung zwar anzeigen oder nicht, aber gelegentlich werden Sie flackern und scheren.

Um das Problem zu lösen (was subjektiv ist) zeichne eine Linie vom Drehpunkt durch den Ball zur Mausposition, dies gibt dem Benutzer zumindest ein Feedback, was passiert.

Ich würde auch einige Griffe zu den Kugeln hinzufügen, so dass Sie die Masse (Volumen der Kugel * Dichte) und die Länge der Achse ändern können. Die Größenänderungscursor sind ein Problem, da die Richtung der erforderlichen Bewegung nicht übereinstimmen wird Die Winkel haben Veränderungen. Sie müssen einen finden, der dem richtigen Winkel am nächsten ist, oder einen Cursor auf eine Leinwand rendern und diesen verwenden.

Beispielcode zeigt was ich meine. (Schließt nicht sim) Bewegen Sie die Maus über Kugeln zu bewegen, wenn sie über Sie auch zwei Kreise sehen erscheint Abstand zu ändern und Radius (Masse)

/*------------------------------------------------------------------------------------- 
 
answer code 
 
---------------------------------------------------------------------------------------*/ 
 

 

 

 

 

 

 
var balls = []; 
 
var startX,startY; 
 
var mouseOverBallIndex = -1; 
 
var mouseOverDist = false; 
 
var mouseOverMass = false; 
 
const DRAG_CURSOR = "move"; 
 
const MASS_CURSOR = "ew-resize"; 
 
const DIST_CURSOR = "ns-resize"; 
 
var dragging = false; 
 
var dragStartX = 0; 
 
var dragStartY = 0; 
 
function addBall(dist,radius){ 
 
    balls.push({ 
 
     dist : dist, 
 
     radius : Math.max(10,radius), 
 
     angle : -Math.PI/2, 
 
     x : 0, 
 
     y : 0, 
 
     mass : (4/3) * radius * radius * radius * Math.PI, 
 
    }); 
 
} 
 
function drawBalls(){ 
 
    var i = 0; 
 
    var len = balls.length; 
 
    var x,y,dist,b,minDist,index,cursor; 
 
    ctx.lineWidth = 2; 
 
    ctx.strokeStyle = "black"; 
 
    ctx.fillStyle = "blue" 
 
    ctx.beginPath(); 
 
    x = startX; 
 
    y = startY; 
 
    ctx.moveTo(x, y) 
 
    for(; i < len; i += 1){ 
 
     b = balls[i]; 
 
     x += Math.cos(b.angle) * b.dist; 
 
     y += Math.sin(b.angle) * b.dist; 
 
     ctx.lineTo(x, y); 
 
     b.x = x; 
 
     b.y = y; 
 
    } 
 
    ctx.stroke(); 
 
    minDist = Infinity; 
 
    index = -1; 
 
    for(i = 0; i < len; i += 1){ 
 
     b = balls[i]; 
 
     ctx.beginPath(); 
 
     ctx.arc(b.x, b.y, b.radius, 0, Math.PI * 2); 
 
     ctx.fill(); 
 
     if(!dragging){ 
 
      x = b.x - mouse.x; 
 
      y = b.y - mouse.y; 
 
      dist = Math.sqrt(x * x + y * y); 
 
      if(dist < b.radius + 5 && dist < minDist){ 
 
       minDist = dist; 
 
       index = i; 
 
      } 
 
     } 
 
    } 
 
    if(!dragging){ 
 
     mouseOverBallIndex = index; 
 
     if(index !== -1){ 
 
      cursor = DRAG_CURSOR; 
 
      b = balls[index]; 
 
      ctx.fillStyle = "Red" 
 
      ctx.beginPath(); 
 
      ctx.arc(b.x, b.y, b.radius, 0, Math.PI * 2); 
 
      ctx.fill(); 
 
      dx = b.x - Math.cos(b.angle) * b.radius; 
 
      dy = b.y - Math.sin(b.angle) * b.radius; 
 
      x = dx - mouse.x; 
 
      y = dy - mouse.y; 
 
      dist = Math.sqrt(x * x + y * y); 
 
      ctx.beginPath(); 
 
      if(dist < 6){ 
 
       ctx.strokeStyle = "Yellow" 
 
       mouseOverDist = true; 
 
       ctx.arc(dx, dy, 12, 0, Math.PI * 2); 
 
       cursor = DIST_CURSOR; 
 
      }else{ 
 
       ctx.strokeStyle = "black" 
 
       mouseOverDist = false; 
 
       ctx.arc(dx, dy, 5, 0, Math.PI * 2); 
 

 
      } 
 
      ctx.stroke();MASS_CURSOR 
 
      dx = b.x - Math.cos(b.angle + Math.PI/2) * b.radius; 
 
      dy = b.y - Math.sin(b.angle + Math.PI/2) * b.radius; 
 
      x = dx - mouse.x; 
 
      y = dy - mouse.y; 
 
      dist = Math.sqrt(x * x + y * y); 
 
      ctx.beginPath(); 
 
      if(dist < 6){ 
 
       ctx.strokeStyle = "Yellow" 
 
       mouseOverMass = true; 
 
       ctx.arc(dx, dy, 12, 0, Math.PI * 2); 
 
       cursor = MASS_CURSOR; 
 
      }else{ 
 
       ctx.strokeStyle = "black" 
 
       mouseOverMass = false; 
 
       ctx.arc(dx, dy, 5, 0, Math.PI * 2); 
 

 
      } 
 
      ctx.stroke(); 
 
      canvas.style.cursor = cursor; 
 
     }else{ 
 
      canvas.style.cursor = "default"; 
 
     } 
 
    }else{ 
 
     b = balls[mouseOverBallIndex]; 
 
     ctx.fillStyle = "Yellow" 
 
     ctx.beginPath(); 
 
     ctx.arc(b.x, b.y, b.radius, 0, Math.PI * 2); 
 
     ctx.fill();   
 
     
 
    } 
 

 
} 
 
function display(){ // put code in here 
 
    var x,y,b 
 
    
 
    if(balls.length === 0){ 
 
     startX = canvas.width/2; 
 
     startY = canvas.height/2; 
 
     addBall((startY * 0.8) * (1/4), startY * 0.04); 
 
     addBall((startY * 0.8) * (1/3), startY * 0.04); 
 
     addBall((startY * 0.8) * (1/2), startY * 0.04); 
 
     
 
    } 
 
    ctx.setTransform(1,0,0,1,0,0); // reset transform 
 
    ctx.globalAlpha = 1;   // reset alpha 
 
    ctx.clearRect(0,0,w,h); 
 
    if((mouse.buttonRaw & 1) && mouseOverBallIndex > -1){ 
 
     b = balls[mouseOverBallIndex]; 
 
     if(dragging === false){ 
 
      dragging = true; 
 
      dragStartX = balls[mouseOverBallIndex].x; 
 
      dragStartY = balls[mouseOverBallIndex].y; 
 
     }else{ 
 
      b = balls[mouseOverBallIndex]; 
 
      if(mouseOverBallIndex === 0){ 
 
       x = startX; 
 
       y = startY; 
 
      }else{ 
 
       x = balls[mouseOverBallIndex-1].x 
 
       y = balls[mouseOverBallIndex-1].y 
 
      } 
 
      if(mouseOverDist){ 
 
       var dist = Math.sqrt(Math.pow(x-mouse.x,2)+Math.pow(y-mouse.y,2)); 
 
       b.dist = dist + b.radius; 
 
       
 
      }else  
 
      if(mouseOverMass){ 
 
       var dist = Math.sqrt(Math.pow(dragStartX-mouse.x,2)+Math.pow(dragStartY-mouse.y,2)); 
 
       b.radius = Math.max(10,dist); 
 
       b.mass = dist * dist * dist * (4/3) * Math.PI; 
 
      }else{ 
 
       b.angle = Math.atan2(mouse.y - y, mouse.x - x); 
 
       ctx.beginPath(); 
 
       ctx.lineWidth = 1; 
 
       ctx.strokeStyle = "grey"; 
 
       ctx.moveTo(x,y); 
 
       ctx.lineTo(mouse.x, mouse.y); 
 
       ctx.stroke(); 
 
      } 
 
     } 
 
     
 
    }else if(dragging){ 
 
     dragging = false; 
 
    } 
 

 
    drawBalls(); 
 
} 
 

 
/*------------------------------------------------------------------------------------- 
 
answer code END 
 
---------------------------------------------------------------------------------------*/ 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 
/** SimpleFullCanvasMouse.js begin **/ 
 
const CANVAS_ELEMENT_ID = "canv"; 
 
const U = undefined; 
 
var w, h, cw, ch; // short cut vars 
 
var canvas, ctx, mouse; 
 
var globalTime = 0; 
 
var createCanvas, resizeCanvas, setGlobals; 
 
var L = typeof log === "function" ? log : function(d){ console.log(d); } 
 
createCanvas = function() { 
 
    var c,cs; 
 
    cs = (c = document.createElement("canvas")).style; 
 
    c.id = CANVAS_ELEMENT_ID;  
 
    cs.position = "absolute"; 
 
    cs.top = cs.left = "0px"; 
 
    cs.zIndex = 1000; 
 
    document.body.appendChild(c); 
 
    return c; 
 
} 
 
resizeCanvas = function() { 
 
    if (canvas === U) { canvas = createCanvas(); } 
 
    canvas.width = window.innerWidth; 
 
    canvas.height = window.innerHeight; 
 
    ctx = canvas.getContext("2d"); 
 
    if (typeof setGlobals === "function") { setGlobals(); } 
 
} 
 
setGlobals = function(){ cw = (w = canvas.width)/2; ch = (h = canvas.height)/2; balls.length = 0; } 
 
mouse = (function(){ 
 
    function preventDefault(e) { e.preventDefault(); } 
 
    var mouse = { 
 
     x : 0, y : 0, w : 0, alt : false, shift : false, ctrl : false, buttonRaw : 0, 
 
     over : false, // mouse is over the element 
 
     bm : [1, 2, 4, 6, 5, 3], // masks for setting and clearing button raw bits; 
 
     mouseEvents : "mousemove,mousedown,mouseup,mouseout,mouseover,mousewheel,DOMMouseScroll".split(",") 
 
    }; 
 
    var m = mouse; 
 
    function mouseMove(e) { 
 
     var t = e.type; 
 
     m.x = e.offsetX; m.y = e.offsetY; 
 
     if (m.x === U) { m.x = e.clientX; m.y = e.clientY; } 
 
     m.alt = e.altKey; m.shift = e.shiftKey; m.ctrl = e.ctrlKey; 
 
     if (t === "mousedown") { m.buttonRaw |= m.bm[e.which-1]; } 
 
     else if (t === "mouseup") { m.buttonRaw &= m.bm[e.which + 2]; } 
 
     else if (t === "mouseout") { m.buttonRaw = 0; m.over = false; } 
 
     else if (t === "mouseover") { m.over = true; } 
 
     else if (t === "mousewheel") { m.w = e.wheelDelta; } 
 
     else if (t === "DOMMouseScroll") { m.w = -e.detail; } 
 
     if (m.callbacks) { m.callbacks.forEach(c => c(e)); } 
 
     e.preventDefault(); 
 
    } 
 
    m.addCallback = function (callback) { 
 
     if (typeof callback === "function") { 
 
      if (m.callbacks === U) { m.callbacks = [callback]; } 
 
      else { m.callbacks.push(callback); } 
 
     } else { throw new TypeError("mouse.addCallback argument must be a function"); } 
 
    } 
 
    m.start = function (element, blockContextMenu) { 
 
     if (m.element !== U) { m.removeMouse(); }   
 
     m.element = element === U ? document : element; 
 
     m.blockContextMenu = blockContextMenu === U ? false : blockContextMenu; 
 
     m.mouseEvents.forEach(n => { m.element.addEventListener(n, mouseMove); }); 
 
     if (m.blockContextMenu === true) { m.element.addEventListener("contextmenu", preventDefault, false); } 
 
    } 
 
    m.remove = function() { 
 
     if (m.element !== U) { 
 
      m.mouseEvents.forEach(n => { m.element.removeEventListener(n, mouseMove); }); 
 
      if (m.contextMenuBlocked === true) { m.element.removeEventListener("contextmenu", preventDefault);} 
 
      m.element = m.callbacks = m.contextMenuBlocked = U; 
 
     } 
 
    } 
 
    return mouse; 
 
})(); 
 
var done = function(){ 
 
    window.removeEventListener("resize",resizeCanvas) 
 
    mouse.remove(); 
 
    document.body.removeChild(canvas);  
 
    canvas = ctx = mouse = U; 
 
    L("All done!") 
 
} 
 

 
resizeCanvas(); // create and size canvas 
 
mouse.start(canvas,true); // start mouse on canvas and block context menu 
 
window.addEventListener("resize",resizeCanvas); // add resize event 
 

 
function update(timer){ // Main update loop 
 
    globalTime = timer; 
 
    display(); // call demo code 
 
    // continue until mouse right down 
 
    if (!(mouse.buttonRaw & 2)) { requestAnimationFrame(update); } else { done(); } 
 
} 
 
requestAnimationFrame(update); 
 

 
/** SimpleFullCanvasMouse.js end **/