2014-02-15 42 views
0

現狀:重新定位SVG:使用d3.js創建矩形元素(使用D3或jQuery的)

我是一個谷歌地圖與D3覆蓋上工作。這主要基於Mike Bostock的這個例子:http://bl.ocks.org/mbostock/899711

我正在運行它從一個Rails 4應用程序,並從CDN加載到d3.js庫。因此,有權訪問d3.js和jQuery庫,並希望避免添加更多的庫。

任務:

的數據點(由svg:rect元素表示)有時模糊谷歌地圖上的地名。我需要它,以便用戶可以將光標移到這些數據點上,並且它們會瞬間彈出。

我應該注意我想要隨機重定位點,所以不能真正走懸停的CSS路線。

所以......

  • 將事件偵聽器的SVG(取決於哪些因素或矩形實際上應該被操縱)

  • 寫一個回調函數,重新定位(偏移?動畫?轉換?)觸發事件的元素

  • 等待setTimeout(或使用d3 .each("end",function())),然後將元素返回到其之前的位置

簡單吧?

嘗試:

因此,試圖用D3,然後用jQuery的嘗試。因爲它似乎無法處理SVG(儘管如果d3.js沒有通過商品,我可能不得不使用jQuery-SVG庫)

隨着d3的嘗試,事件處理程序分配很好。我已經將處理程序分配給svg父元素,而不是rect子元素。

.on('mouseover', scatter) 

這會產生事件觸發的預期行爲,並在鼠標懸停時調用scatter函數。

但是,我一直無法得到我期待的行爲的任何明智的表達。

我試過改變x,y值。我試着改變頂部和左側的值。這些值似乎在物體上發生變化,但沒有任何變化。我已經嘗試過直線d3風格選擇和d3風格轉換。

我試過rect子元素上的相同更改。這會移動rect元素,但不會將SVG與其一起使用,因此不會顯示。

相關的代碼:

追加SVGs到每一個數據點,設定爲SVG正確的x和y以及將事件偵聽器向每個。

var marker = layer.selectAll("svg") 
     .data(data) 
     .each(transformMarker) 
     .enter().append("svg:svg") 
     .each(transformMarker) 
     .on('mouseover', scatter); 

另外,我的風格SVG父元素包含一個矩形子元素,風格rects,所以實際的東西在屏幕上顯示。

transformMarker函數,您可能需要了解標記的位置。

function transformMarker(d) { 
     d = new google.maps.LatLng(J.lat(d), J.lon(d)); 
     d = projection.fromLatLngToDivPixel(d); 
     return d3.select(this) 
      .style("left", (d.x) + "px") 
      .style("top", (d.y) + "px"); 

的散射函數(console.logs的一大堆,所以你可以看到發生了什麼)

function scatter(d){ 
     console.log("the event has fired") 
     d = new google.maps.LatLng(J.lat(d), J.lon(d)); 
     d = projection.fromLatLngToDivPixel(d); 
     console.log(d.x) 
     console.log((d.x + 15) + "px") 
     console.log(this) 
     d3.select(this) 
     .attr("x", (d.x + 15)) 
     .attr("y", (d.y + 15)) 
     console.log(this) 

而且console.logs泵出什麼

the event has fired 
602.0032221842557 
617.0032221842557px 

<svg style=​"left:​ 602.0032221842557px;​ top:​ 230.00228557549417px;​" 
    x="617.0032221842557" y=​"245.00228557549417">​ 
    <rect height=​"7" width=​"7" fill=​"#138770" stroke=​"#0f0f02" stroke-width=​"0.5">​</rect>​ 
</svg>​ 

<svg style=​"left:​ 602.0032221842557px;​ top:​ 230.00228557549417px;​" 
    x="617.0032221842557" y=​"245.00228557549417">​ 
    <rect height=​"7" width=​"7" fill=​"#138770" stroke=​"#0f0f02" stroke-width=​"0.5">​</rect>​ 
</svg>​ 

而CSS的SVG,因爲這可能是投擲扳手

.overlay, .overlay svg { 
    position: absolute; 
} 

.wrapper, .overlay svg { 
    /*border: 1px solid black;*/ 
    width: 7px; 
    height: 7px; 

    transform: translateZ(0px); 
    -webkit-transform: translateZ(0px); 
    -moz-transform: translateZ(0px); 
} 

我離文明還有幾天的距離,所以希望能把這個問題擺在那裏,然後回來一個新的方法,以及Stack Overflow和d3谷歌組織的一些建議。

如果您有任何其他問題或需要更多信息,請讓我知道。

回答

0

總括:

每個數據點是矩形其自己的單獨<svg>元件內。使用絕對定位(lefttop樣式)在transformMarker事件中定位每個svg元素。

顯然,如果您想要移動與數據點關聯的svg圖形,您將需要更改<svg>元素的位置。您試圖通過xy屬性來實現,但這並不是SVG如何擺在首位。這些屬性僅在<svg>元素嵌入另一個SVG時才相關。你的是絕對定位在頁面上的獨立元素。所以,你需要更改絕對定位樣式值:

function scatter(d){ 
     d = new google.maps.LatLng(J.lat(d), J.lon(d)); 
     d = projection.fromLatLngToDivPixel(d); 
     d3.select(this) 
     .style("left", (d.x + 15) + "px") 
     .style("top", (d.y + 15) + "px") 
} 

而且,我不知道爲什麼你在你的初始化調用transformMarker兩次;你只需要一次,但是一定要保持的版本是經過創建的元素稱爲之一:

var marker = layer.selectAll("svg") 
     .data(data) 
     .enter().append("svg:svg") 
     .each(transformMarker) 
     .on('mouseover', scatter); 
+0

感謝您花時間幫助我解決Amelia問題。 –

+1

我已經取消了不必要的'transformMarker'。關於一致定位的觀點最終是關鍵。我想我以前嘗試過使用'left'和'top',但是使用'.attr',而不是'.style'來分配它們。 我已經在最基本的層面上工作了,所以現在看看我是否可以隨機做出動作,動畫(通過轉換)並在一段時間後重置!乾杯。 –

+0

是的,第二個'transformMarker'需要在地圖移動時重繪元素。 –

0

我想看看這個漂亮的random function for Sass

module Sass::Script::Functions 
    def random(max = Sass::Script::Number.new(100)) 
    Sass::Script::Number.new(rand(max.value), max.numerator_units, max.denominator_units) 
    end 
end 

添加將隨機函數放入你的sass中,檢出this guide。如果你想讓你的物品在mousever上隨機地重新定位,我只需要一個隨機位置的類,使用隨機函數並將這個類移除/添加到元素中。當然,在我提供的鏈接中有一些使用隨機函數的例子。

當然這很簡單,只需將上面的代碼添加到sass.rb中的config/initializers中。這裏是使用它的example rails app

它的一個問題是,如果你在一個類中設置它,它只會產生一次隨機數。刷新並重新加載後,它不會爲其生成的css生成新的隨機頂部/左側等。我不確定是否有解決辦法,或者這實際上有幫助。但它很有趣,所以我想我會發布它。