2015-03-03 148 views
0

感謝您的閱讀。D3.js在布面和svg中放大縮小行爲

目標

我想比較工作SVG點擊到變焦麥克·博斯托克的塊到基於畫布的系統。我將工作的SVG放在頂部,底部放置一個畫布。當用戶點擊上SVG中的狀態時,我希望較低的畫布元素「跟隨」或模仿縮放和平移。例如,單擊上SVG中的明尼蘇達也會導致較低的畫布放大並平移到明尼蘇達。

的問題

我的畫布元素繪製加載topojson後罰款,但它並沒有動畫。我希望它有動畫。我相信這是因爲我不完全瞭解縮放行爲和基於路徑的投影。

http://jsfiddle.net/30w8nv4t/2/

function zoomed(d) { 
    g.style("stroke-width", 1.5/d3.event.scale + "px"); 
    g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); 

    // the zTranslate and zScale variables appear to be ok, 
    // but `d` is null. I'm not sure how to redraw. 
    var zTranslate = zoom.translate(); 
    var zScale = zoom.scale(); 
    console.log(zTranslate, zScale, d); 
    context.clearRect(0, 0, width, height); 
    context.beginPath(); 
    canvasPath(d); 
    context.stroke(); 
} 

在這種情況下,d顯然是空的,我不能重繪什麼。我假設我的問題可能在zoomed方法或clicked函數中。

我用這並排側的方法,因爲我想學習路徑,投影和縮放行爲如何一起工作的原因。我很欣賞canvas對SVG的表現如何,但缺乏交互性令人望而生畏。幸運的是,能夠縮放和平移到任意幾何圖形將我的問題減半。

謝謝您的閱讀。 JSFiddle的鏈接位於這篇文章的頂部。

回答

1

canvas繪圖函數使用經/緯度座標的預測值,但你不更新你的zoom處理projectionscaletranslate。吃出你後的行爲,

一種方法是從transformsvgzoom處理程序切換,一個transformprojection

我已經在這個更新的小提琴做到了這一點:http://jsfiddle.net/30w8nv4t/7/

的區別是:

  1. 更新zoom行爲,以便使用projectiontranslatescale作爲默認值,並設置scaleExtent值也基於projection

    var zoom = d3.behavior.zoom() 
        .translate(projection.translate()) 
        .scale(projection.scale()) 
        .scaleExtent([projection.scale()/5, projection.scale()*5]) 
        .on("zoom", zoomed); 
    
  2. 更新您的zoomed功能translatescaleprojection然後重繪svg基於路徑。

    function zoomed(d) { 
        //g.style("stroke-width", 1.5/d3.event.scale + "px"); 
        //g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); 
        projection.translate(d3.event.translate).scale(d3.event.scale); 
        g.selectAll("path").attr("d", path); 
    
        var zTranslate = zoom.translate(); 
        var zScale = zoom.scale(); 
        console.log(zTranslate, zScale, d); 
        context.clearRect(0, 0, width, height); 
        context.beginPath(); 
        canvasPath(states); 
        context.stroke(); 
    } 
    
  3. 相應地更新您的clicked函數。

    function clicked(d) { 
        if (active.node() === this) { 
         zoom.scale(500).translate([width/2, height/2]); 
         active.classed("active", false); 
         active = d3.select(null); 
        } else { 
         var centroid = path.centroid(d), 
          translate = zoom.translate(), 
          bounds = path.bounds(d), 
          dx = bounds[1][0] - bounds[0][0], 
          dy = bounds[1][1] - bounds[0][1], 
          scale = .9/ Math.max(dx/width, dy/height); 
    
         zoom.scale(scale * zoom.scale()) 
            .translate([ 
             translate[0] - centroid[0] * scale + width * scale/2, 
             translate[1] - centroid[1] * scale + height * scale/2]); 
    
    
         active.classed("active", false); 
         active = d3.select(this).classed("active", true); 
        } 
    
        zoom.event(svg); 
    } 
    

    這可能是變化的主要成分之一,爲scaletranslate應用於zoom行爲,當他們,他們必須由當前zoomscale進行縮放。 clicked函數然後觸發zoomed函數重繪svgcanvas元素。

正如你所看到的,你的canvas繪圖代碼是正確的。只是使用projection的繪圖代碼根據zoom處理程序未更新的projection來確定繪製點的xy位置。

也可以爲canvas設置單獨的projection,並在調用canvas重繪函數之前更新zoom處理程序中的處理程序。我將把它作爲讀者的練習!

+0

好,這讓我朝更好的方向發展。但是,當我們將鼠標縮放與點擊相結合時,它看起來有點小錯誤。例如,單擊加利福尼亞州。請注意,地圖會放大加利福尼亞州。現在將地圖向東拖動並點擊一個狀態。觀察到狀態不居中。話雖如此,這促使我瞭解縮放行爲和預測的作用。我的繪圖功能是正確的! :) – standers 2015-03-03 04:53:10