2017-11-23 4 views
1

원 (좌표 점)을 클릭하고 싶습니다. 마커를 원의 위치로 가져 와서 원의 위치에서 일시 중지 한 다음 경로를 따라 다시 시작하십시오.경로 세그먼트를 따라 D3 전환 및 좌표 값에서 일시 중지

또한 마커가 일시 중지되었을 때 원을 활성화하고 싶습니다. 클릭하면 (또는 보로 노이 셀을 클릭하면) 원이 활성화됩니다. 내 의도는 결국 원 좌표에 대한 href에 대한 클릭 기능을 갖게하는 것입니다.

나는 경로 변수의 인덱스를 시간 변수 대신 translateAlong 함수에 전달해야한다고 생각하지만이를 수행하는 방법을 찾을 수 없다.

Voronoi 세포가 필요한지 확실하지 않습니다. Voronoi 세포를 사용하여 전환을 일시 중지하고 내 서클을 활성화 할 수 있다고 생각했습니다. 어쨌든 나는 Voronoi 세포로 원을 활성화 할 수 없다.

I에 유래 d3 on click on circle pause and resume transition of marker along line 에 상당히 최근에 도움이되고 당신이 지점에서 일시 정지하려면 내가 전체 경로에서 하나의 전환을 실행하지 않을 다시

<!DOCTYPE html> 
<html lang="en"> 
    <head> 
<meta charset="utf-8"> 
<title>basic_animateBetweenCircles</title> 

<script src="https://d3js.org/d3.v4.min.js"></script> 
<style> 
path { 
    stroke: #848484; 
    fill: none; 
} 
circle { 
    fill: steelblue; 
    stroke: steelblue; 
    stroke-width: 3px; 
} 

.line { 
    fill: none; 
    stroke: #FE642E; 
    stroke-width: 4; 
    stroke-dasharray: 4px, 8px; 
} 
.point{ 
    fill:#DF013A; 
} 
</style> 
</head> 
<body> 

<script> 

var width = 960, 
    height = 500; 

var data = [ 
     [480, 200], 
     [580, 400], 
     [680, 100], 
     [780, 300], 
     [180, 300], 
     [280, 100], 
     [380, 400] 
    ]; 

    //check index of path data 
     for (var i = 0; i < data.length; i++) { 
      var coordindex = i + " " + data[i]; 
      console.log("Coordindex: " + coordindex); 
      //return coordindex; 
     }; 

var duration = 20000; 

var line = d3.line() 
    .x(function(d) {return (d)[0];}) 
    .y(function(d) {return (d)[1];}); 

var voronoi = d3.voronoi() 
    .extent([[0, 0], [width, height]]); 

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

//path to animate - marker transitions along this path 
var path = svg.append("path") 
    .data([data]) 
    .attr("d", line) 
    .attr('class', 'line') 
    .attr("d", function(d) { 
     return line(d) 
    }); 

//voronoi 
var voronoiPath = svg.append("g") 
    .selectAll("path") 
    .data(voronoi.polygons(data)) 
    .enter().append("path") 
    .attr("d", polygon) 
    .on("touchmove mousemove", function() { 
     d3.select(this) 
     .style("fill", "purple"); 
}); 

//Want to activate circles when marker paused on them/in voronoi cell - intention is to have on click to href 
svg.selectAll("circle") 
     .data(data) 
    .enter() 
     .append("circle") 
     .attr("class", "point") 
     .attr("r", 10) 
    .attr("transform", function(d) { return "translate(" + d + ")"; }) 
     .on('click', function(d, i) { 
     d3.select(this) 
      .style("fill", "green"); 
     if (d3.active(this)) { 
      marker.transition(); 
      setTimeout(function() { 
       pauseValues.lastTime = pauseValues.currentTime; 
       //console.log(pauseValues); 
      }, 100); 
     } else { 
      transition(); 
     } 
    }); 

var pauseValues = { 
    lastTime: 0, 
    currentTime: 0 
}; 

//marker to transition along path 
var marker = svg.append("circle") 
    .attr("r", 19) 
    .attr("transform", "translate(" + (data[0]) + ")") 
    .on('click', function(d, i) { 
     if (d3.active(this)) { 
      marker.transition(); 
      setTimeout(function() { 
       pauseValues.lastTime = pauseValues.currentTime; 
       //console.log(pauseValues); 
      }, 100); 
     } else { 
      transition(); 
     } 
    }); 

function transition() { 
    marker.transition() 
     .duration(duration - (duration * pauseValues.lastTime)) 
     .attrTween("transform", translateAlong(path.node())) 
     .on("end", function() { 
      pauseValues = { 
       lastTime: 0, 
       currentTime: 0 
      }; 
      transition() 
     }); 
} 

function translateAlong(path) { 
    var l = path.getTotalLength(); 
    return function(d, i, a) { 
     return function(t) { 
      t += pauseValues.lastTime; 
      var p = path.getPointAtLength(t * l); 
      pauseValues.currentTime = t; 
      return "translate(" + p.x + "," + p.y + ")"; 
     }; 
    }; 
} 

function polygon(d) { 
    return "M" + d.join("L") + "Z"; 
} 

</script> 
</body> 

답변

3

지원을 기대하고있다. 대신, 나는 그것을 지점에서 지점으로 이동하면서 N 개의 전환으로 분해 할 것입니다. 다음 구간에서 원을 시작하기 전에 잠시 멈출 수 있습니다. 이렇게하려면, 그냥 약간의 대수와 각 선분을 따라 전환 할 것 :

<!DOCTYPE html> 
 
<html lang="en"> 
 

 
<head> 
 
    <meta charset="utf-8"> 
 
    <title>basic_animateBetweenCircles</title> 
 

 
    <script src="https://d3js.org/d3.v4.min.js"></script> 
 
    <style> 
 
    path { 
 
     stroke: #848484; 
 
     fill: none; 
 
    } 
 
    
 
    circle { 
 
     fill: steelblue; 
 
     stroke: steelblue; 
 
     stroke-width: 3px; 
 
    } 
 
    
 
    .line { 
 
     fill: none; 
 
     stroke: #FE642E; 
 
     stroke-width: 4; 
 
     stroke-dasharray: 4px, 8px; 
 
    } 
 
    
 
    .point { 
 
     fill: #DF013A; 
 
    } 
 
    </style> 
 
</head> 
 

 
<body> 
 

 
    <script> 
 
    var width = 960, 
 
     height = 500; 
 

 
    var data = [ 
 
     [480, 200], 
 
     [580, 400], 
 
     [680, 100], 
 
     [780, 300], 
 
     [180, 300], 
 
     [280, 100], 
 
     [380, 400] 
 
    ]; 
 

 

 
    var duration = 20000/data.length, 
 
     pauseTime = 2000; 
 

 
    var line = d3.line() 
 
     .x(function(d) { 
 
     return (d)[0]; 
 
     }) 
 
     .y(function(d) { 
 
     return (d)[1]; 
 
     }); 
 

 
    var voronoi = d3.voronoi() 
 
     .extent([ 
 
     [0, 0], 
 
     [width, height] 
 
     ]); 
 

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

 
    //path to animate - marker transitions along this path 
 
    var path = svg.append("path") 
 
     .data([data]) 
 
     .attr("d", line) 
 
     .attr('class', 'line') 
 
     .attr("d", function(d) { 
 
     return line(d) 
 
     }); 
 

 
    //voronoi 
 
    var voronoiPath = svg.append("g") 
 
     .selectAll("path") 
 
     .data(voronoi.polygons(data)) 
 
     .enter().append("path") 
 
     .attr("d", polygon); 
 

 
    //Want to activate circles when marker paused on them/in voronoi cell - intention is to have on click to href 
 
    svg.selectAll("circle") 
 
     .data(data) 
 
     .enter() 
 
     .append("circle") 
 
     .attr("class", "point") 
 
     .attr("r", 10) 
 
     .attr("transform", function(d) { 
 
     return "translate(" + d + ")"; 
 
     }) 
 
     .on('click', function(d, i) { 
 
     d3.select(this) 
 
      .style("fill", "green"); 
 
     pausePoints.push(i); 
 
     if (pausePoints.length === 1) 
 
      transition();  
 
     }); 
 

 
    //marker to transition along path 
 
    var marker = svg.append("circle") 
 
     .attr("r", 19) 
 
     .attr("transform", "translate(" + (data[0]) + ")"); 
 

 
    var pausePoints = [], 
 
     iter = 0, 
 
     transData = data.slice(); 
 
    
 
    function transition() { 
 
     marker.transition() 
 
     .ease(d3.easeLinear) 
 
     .duration(duration) 
 
     .attrTween("transform", function(){ 
 
      var p0 = transData.shift(), 
 
       p1 = transData[0]; 
 
       m = (p0[1] - p1[1])/(p0[0] - p1[0]), 
 
       b = p0[1] - (m * p0[0]), 
 
       i = d3.interpolateNumber(p0[0], p1[0]); 
 
       
 
      return function(t){ 
 
       var x = i(t), 
 
        y = m*x + b; 
 
       return "translate(" + x + "," + y + ")"; 
 
      } 
 
     }) 
 
     .on("end", function(){ 
 
      if (transData.length <= 1) return; 
 
      iter++;   
 
      setTimeout(transition, pausePoints.indexOf(iter) !== -1 ? pauseTime : 0); 
 
     }); 
 
    } 
 

 
    function polygon(d) { 
 
     return "M" + d.join("L") + "Z"; 
 
    } 
 
    </script> 
 
</body>

: 코드를 실행

// copy our data 
transData = data.slice(); 

function transition() { 
    marker.transition() 
    .ease(d3.easeLinear) 
    .duration(duration) 
    .attrTween("transform", function(){ 

     // get our two points 
     // slope between them 
     // and intercetp 
     var p0 = transData.shift(), 
      p1 = transData[0]; 
      m = (p0[1] - p1[1])/(p0[0] - p1[0]), 
      b = p0[1] - (m * p0[0]), 
      i = d3.interpolateNumber(p0[0], p1[0]); 

     // move the point along the line 
     return function(t){ 
      var x = i(t), 
       y = m*x + b; 
      return "translate(" + x + "," + y + ")"; 
     } 
    }) 
    // one line segment is complete 
    .on("end", function(){ 
     // if no more movements, stop 
     if (transData.length <= 1) return; 
     iter++; 
     // determine if this is a "pause"   
     setTimeout(transition, pausePoints.indexOf(iter) !== -1 ? pauseTime : 0); 
    }); 

, 당신은 여러 지점을 일시 중지 할 수 있습니다 시작하는 점을 클릭

+0

정말 고마워요 - 당신은 훌륭합니다! 나는 이런 일을해야한다는 것을 알았지 만 그것을 성취 할 방법을 모르고있었습니다. 이 커뮤니티 덕분에 많은 것을 배우고 있습니다. – user3471259