2015-09-01 13 views
5

Obiettivo: Spostare il rettangolo rosso all'interno del gruppo di rettangoli neri. I rettangoli neri formano una figura che è limitata a spostare il rettangolo rosso.Limita il movimento dell'elemento quando lo trasciniamo

window.onload=function(){ 

var inter = false; 

//Make an SVG Container 
var svgContainer = d3.select("body").append("svg") 
    .attr("width", 800) 
    .attr("height", 600); 

//draw some rects 
var r1 = svgContainer.append("rect") 
    .attr("class", "interactive") 
    .attr("x", 10) 
    .attr("y", 223) 
    .attr("width", 50) 
    .attr("height", 150); 

var r2 = svgContainer.append("rect") 
    .attr("class", "interactive") 
    .attr("x", 223) 
    .attr("y", 10) 
    .attr("width", 50) 
    .attr("height", 300) 
    .attr("transform", "rotate(45 220,10)"); 

//group of elements for limit red rect drag 
var interactive = d3.selectAll(".interactive") 
    .on("mouseover", function(d){ 
     inter = true; 
    }) 
    .on("mouseleave", function(d){ 
     inter = false; 
    }); 

// dragging function 
var drag = d3.behavior.drag() 
    .on("drag", function(d,i) { 
     if(inter){ 
      d.x += d3.event.dx; 
      d.y += d3.event.dy; 
      d3.select(this).attr("transform", function(d,i){ 
       return "translate(" + [ d.x,d.y ] + ")" 
      }); 
     } 
    }) 
    .on("dragstart", function() { 
     d3.select(this).style("pointer-events", "none") 
    }) 
    .on("dragend", function() { 
     d3.select(this).style("pointer-events", "auto") 
    }); 

// red rectangle for draging 
var r = svgContainer.append("rect") 
    .attr("x", 150) 
    .attr("y", 100) 
    .attr("width", 20) 
    .attr("height", 20) 
    .attr("fill", "red") 
    .data([ {"x":0, "y":0} ]) 
    .call(drag); 

} 

http://codepen.io/anon/pen/pjorBb

Ecco il mio esempio di un soggetto. Ma non funziona correttamente. Forse qualcuno ha un esempio simile di un corretto o dare indizi su come farlo correttamente.

risposta

1

Questa non è una soluzione perfetta. Ma potresti avere l'idea di come implementare la funzionalità da questa demo.

//Make an SVG Container 
 
var svgContainer = d3.select("body").append("svg") 
 
\t .attr("width", 800) 
 
\t .attr("height", 600); 
 

 
//draw some rects 
 
var r1 = svgContainer.append("rect") 
 
\t .attr("class", "interactive") 
 
\t .attr("x", 10) 
 
\t .attr("y", 223) 
 
\t .attr("width", 50) 
 
\t .attr("height", 150); 
 

 
var r2 = svgContainer.append("rect") 
 
\t .attr("class", "interactive") 
 
\t .attr("x",223) 
 
\t .attr("y", 10) 
 
\t .attr("width", 50) 
 
\t .attr("height", 300) 
 
\t .attr("transform", "rotate(45 220,10)"); 
 

 
function pointRectangleIntersection(p, r) { 
 
    return p.x >= r.x1 && p.x <= r.x2 && p.y >= r.y1 && p.y <= r.y2; 
 
} 
 
// dragging function 
 
var drag = d3.behavior.drag()   
 
\t .on("drag", function(d,i) {   
 
      var pt1 = d3.mouse(r1.node()); 
 
      var point1 = {x: pt1[0], y: pt1[1]}; 
 
      var bbox1 = r1.node().getBBox(); 
 
      var rect1 = { x1: bbox1.x, x2: bbox1.x+bbox1.width, y1: bbox1.y, y2: bbox1.y+bbox1.height }; 
 
      var pt2 = d3.mouse(r2.node()); 
 
      var point2 = {x: pt2[0], y: pt2[1]}; 
 
      var bbox2 = r2.node().getBBox(); 
 
      var rect2 = { x1: bbox2.x, x2: bbox2.x+bbox2.width, y1: bbox2.y, y2: bbox2.y+bbox2.height }; 
 
      
 
      if(pointRectangleIntersection(point1, rect1) || pointRectangleIntersection(point2, rect2)){ 
 
       if(pointRectangleIntersection(point1, rect1)){ 
 
        d.x = Math.max(0, Math.min(rect1.x2 - 20, d3.event.x)); 
 
        d.y = Math.max(0, Math.min(rect1.y2 - 20, d3.event.y)); 
 
       } else{ 
 
        d.x = Math.max(0, Math.min(rect2.x2 - 20, d3.event.x)); 
 
        d.y = Math.max(0, Math.min(rect2.y2 - 20, d3.event.y)); 
 
       }    
 
       d3.select(this).attr("x", d.x); 
 
       d3.select(this).attr("y", d.y); 
 
       d3.event.sourceEvent.stopPropagation();    
 
      } 
 
\t \t 
 
\t }); \t 
 
\t 
 
// red rectangle for draging 
 
var r = svgContainer.append("rect") 
 
\t .attr("x", 150) 
 
\t .attr("y", 100) 
 
\t .attr("width", 20) 
 
\t .attr("height", 20) 
 
\t .attr("fill", "red") 
 
\t .datum({"x":0, "y":0}) 
 
\t .call(drag);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

+0

Questa è una buona opzione! Ma non funziona correttamente con un oggetto che ruota. –

1

Mi è venuta in mente una situazione simile in passato. Ecco come ho superato il problema.

Quando trascino il piccolo elemento, utilizzo una funzione getXY() per determinare la x, y dell'elemento trascinato.

getXY() avrà le coordinate del mouse (d3.mouse(this)) e x, y , width, height degli & oggetti esterni interni. Quindi determinerà se restituire le coordinate del mouse o meno (in questo caso coordinate del bordo dell'oggetto esterno).

Spero che tu possa avere l'idea. Penso che tu possa usarlo per risolvere il tuo problema.

Questo è il mio post originale. d3js transforming nested group images

0

per esempio. Ho cambiato l'attività per le mie esigenze. E ha scritto una decisione che potrebbe essere utile a qualcuno. Il prossimo è il codice in cui un rettangolo può essere spostato solo lungo la linea. Le linee possono essere nascoste con un colore trasparente (.attr ("fill", "rgba (0, 0, 0, 0)");) e puoi disegnare qualsiasi altra cosa per l'utente.

http://codepen.io/anon/pen/pjoGOr

var deltaMax = 15; // max distance to line 
var svgx = 0; 
var svgy = 0; 
var limiters = []; //array of lines for align 

var svgContainer = d3.select("body").append("svg") 
    .attr("width", 700) 
    .attr("height", 700); 

var line1 = svgContainer.append("line") 
    .style("stroke", "black") 
    .attr("x1", 100) 
    .attr("y1", 50) 
    .attr("x2", 100) 
    .attr("y2", 200); 

var line2 = svgContainer.append("line") 
    .style("stroke", "blue") 
    .attr("x1", 100) 
    .attr("y1", 50) 
    .attr("x2", 300) 
    .attr("y2", 50); 

var line3 = svgContainer.append("line") 
    .style("stroke", "green") 
    .attr("x1", 100) 
    .attr("y1", 50) 
    .attr("x2", 300) 
    .attr("y2", 200); 

limiters.push(line1); 
limiters.push(line2); 
limiters.push(line3); 

function distance2points(x1,y1,x2,y2){ //distance between 2 points 
    return Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); 
} 

//find nearest intersection point 
function stick(x1,y1,x2,y2,x3,y3) { 

    //intersection point 
    var ipoint = { x:0, y:0 }; 
    var onSegment = false; 

    if((x2 - x1) == 0){ 
     ipoint.x = x1; 
     ipoint.y = y3; 
    }else if((y2-y1) == 0){ 
     ipoint.x = x3; 
     ipoint.y = y1; 
    }else{ 
     var k = (y2-y1)/(x2-x1); 
     var b = y2-k*x2; 

     var kp = -1/k; 
     var bp = y3-kp*x3; 

     ipoint.x = (bp-b)/(k-kp); 
     ipoint.y = ipoint.x*k+b; 

    } 
    //xxx helper 
    point.attr("cx",ipoint.x); 
    point.attr("cy",ipoint.y); 

    if(distance2points(x3,y3,ipoint.x,ipoint.y) > deltaMax){ 
     return false; 
    } 
    //intersectionn point on segment? 
    if(((x1 >= ipoint.x) && (x2 <= ipoint.x) || (x1 <= ipoint.x) && (x2 >= ipoint.x)) && 
     ((y1 >= ipoint.y) && (y2 <= ipoint.y) || (y1 <= ipoint.y) && (y2 >= ipoint.y))){ 
     onSegment = true; 
    }else if(distance2points(x1,y1,ipoint.x,ipoint.y) < deltaMax){ 
     ipoint.x = x1; 
     ipoint.y = y1; 
     onSegment = true; 
    }else if(distance2points(x2,y2,ipoint.x,ipoint.y) < deltaMax){ 
     ipoint.x = x2; 
     ipoint.y = y2; 
     onSegment = true; 
    }else{ 
     onSegment = false; 
    } 

    if(onSegment){ 
     point.attr("fill","blue"); 
     return ipoint; 
    }else{ 
     point.attr("fill","red"); 
     return false; 
    } 
} 

//mouse position 
svgContainer.on('mousemove', function() { 
    svgx = d3.mouse(this)[0]; 
    svgy = d3.mouse(this)[1]; 
}); 

// dragging function 
var drag = d3.behavior.drag() 
    .on("drag", function(d,i) { 
     for (i = 0; i < limiters.length; i++) { 
      var obj = limiters[i]; 
      var p = stick(
       obj.attr("x1"), 
       obj.attr("y1"), 
       obj.attr("x2"), 
       obj.attr("y2"), 
       svgx,//mouse position 
       svgy 
      ); 
      if(p !== false){ 
       d3.select(this).attr("transform", function(d,i){ 
        return "translate(" + [ p.x,p.y ] + ")" 
       }); 
       break; 
      } 
     } 

    }); 

var r = svgContainer.append("rect") 
    .attr("x", 0) 
    .attr("y", 0) 
    .attr("width", 20) 
    .attr("height", 20) 
    .attr("fill", "red") 
    .data([ {"x":0, "y":0} ]) 
    .call(drag); 

//xxx helper - nearest intersection point 
var point = svgContainer.append("circle") 
    .attr("cx", 10) 
    .attr("cy", 30) 
    .attr("r", 5) 
    .attr("fill", "green");