2016-12-06 6 views
1

所有其他示例都帶有svg.append()的鼠標事件....我不知道在哪裏「輸入」以獲取畫布渲染器中的弧,並在v4樣式中添加.on('click', function(){})。我想點擊以獲得d的值。在這個例子中,我在哪裏添加處理程序?我理解這個例子下面的老方法。如何添加鼠標事件以強制使用d3畫布渲染器的有向圖?

可能是這樣的工作? d3.select(canvas).call(d3.mouse()).on("click", ...)

鏈接working example

var links = d3.range(nodes.length - 1).map(function(i) { 
    return { 
    source: Math.floor(Math.sqrt(i)), 
    target: i + 1 
    }; 
}); 

var simulation = d3.forceSimulation(nodes) 
    .force("charge", d3.forceManyBody()) 
    .force("link", d3.forceLink(links).distance(20).strength(1)) 
    .force("x", d3.forceX()) 
    .force("y", d3.forceY()) 
    .on("tick", ticked); 

var canvas = document.querySelector("canvas"), 
    context = canvas.getContext("2d"), 
    width = canvas.width, 
    height = canvas.height; 

d3.select(canvas) 
    .call(d3.drag() 
     .container(canvas) 
     .subject(dragsubject) 
     .on("start", dragstarted) 
     .on("drag", dragged) 
     .on("end", dragended)); 

function ticked() { 
    context.clearRect(0, 0, width, height); 
    context.save(); 
    context.translate(width/2, height/2); 

    context.beginPath(); 
    links.forEach(drawLink); 
    context.strokeStyle = "#aaa"; 
    context.stroke(); 

    context.beginPath(); 
    nodes.forEach(drawNode); 
    context.fill(); 
    context.strokeStyle = "#fff"; 
    context.stroke(); 

    context.restore(); 
} 

function dragsubject() { 
    return simulation.find(d3.event.x - width/2, d3.event.y - height/2); 
} 

function dragstarted() { 
    if (!d3.event.active) simulation.alphaTarget(0.3).restart(); 
    d3.event.subject.fx = d3.event.subject.x; 
    d3.event.subject.fy = d3.event.subject.y; 
} 

function dragged() { 
    d3.event.subject.fx = d3.event.x; 
    d3.event.subject.fy = d3.event.y; 
} 

function dragended() { 
    if (!d3.event.active) simulation.alphaTarget(0); 
    d3.event.subject.fx = null; 
    d3.event.subject.fy = null; 
} 

function drawLink(d) { 
    context.moveTo(d.source.x, d.source.y); 
    context.lineTo(d.target.x, d.target.y); 
} 

function drawNode(d) { 
    context.moveTo(d.x + 3, d.y); 
    context.arc(d.x, d.y, 3, 0, 2 * Math.PI); 
} 

老辦法

var node = svg.append("g") 
.attr("class", "nodes") 
.selectAll("circle") 
.data(graph.nodes) 
.enter().append("circle") 
    .attr("r", 8) 
    .attr("fill", function(d) { return color(d.group); }) 
    .on("click", togglenode) 
    .call(d3.drag() 
     .on("start", dragstarted) 
     .on("drag", dragged) 
     .on("end", dragended)); 

回答

2

在D3 4.x版,添加一個click事件幾乎你3.x版做同樣的方式:

selection.on("click", function(d){ 
    //do whatever you want with the datum 
}); 

您的任務中的問題離子不是v3與v4,這不是你分享的代碼中的問題。該代碼的問題在於它使用HTML canvas而不是SVG來呈現dataviz。

與SVG不同,canvas沒有元素的節點樹。你不能「選擇某些東西」並向它添加一個事件處理程序。

將畫布視爲光柵圖像,如BMP或JPEG。您可以找到單擊的x和y位置,甚至可以找到該像素的顏色,但無法選擇給定的節點元素,因爲畫布沒有。

例如,請檢查tutorial from Nadieh Bremer以瞭解在使用HTML畫布時用戶點擊的圓圈的複雜程度。

+0

肯定有帆布正確的方式做d3.mouse()或東西嗎?我最終使用了從畫布上的d3.drag()模塊開始拖動。我會想象它只是將全局鼠標座標轉換爲畫布的座標空間。 – FlavorScape

1

因爲我使用了畫布渲染器,所以我只是在示例中欺騙並使用了d3 dragstart事件。可能有辦法像這樣我想知道。

 d3.select(canvas) 
     .call(d3.drag() 
      .container(canvas) 
      .subject(dragsubject) 
      .on("start", dragstarted) 
      .on("drag", dragged) 
      .on("end", dragended)); 

function dragstarted(d) { 
      if (!d3.event.active) simulation.alphaTarget(0.3).restart(); 
      d3.event.subject.fx = d3.event.subject.x; 
      d3.event.subject.fy = d3.event.subject.y; 
      //broadcast the selection to parent 
      emitter.emit(d3.event.subject); 
     } 
0

擴展FlavorScape與雙擊黑客

 d3.select(canvas) 
     .call(d3.drag() 
      .container(canvas) 
      .subject(dragsubject) 
      .on("start", dragstarted) 
      .on("drag", dragged) 
      .on("end", dragended)); 
     var clickDate = new Date(); 
     var difference_ms; 
     function dragstarted(d) { 
      if (!d3.event.active) simulation.alphaTarget(0.3).restart(); 
      d3.event.subject.fx = d3.event.subject.x; 
      d3.event.subject.fy = d3.event.subject.y; 
      difference_ms = (new Date()).getTime() - clickDate.getTime(); 
      clickDate = new Date(); 
      //if clicks less than 200ms apart (double click) 
      if(difference_ms < 200) 
       console.log(d3.event.subject); 
     }