2013-01-22 52 views
12

我正在使用Google API v3製作熱圖。我會舉一個例子。讓我們考慮地震的大小。我給每個點分配權重以指定它們的大小。但谷歌考慮縮小時點的密度。在一個地方得分越多,得分越高。例如,如果兩個地球之間發生彼此數英里的距離,一個3級,另一個8級,第一個應該是綠色/藍色,第二個應該是紅色。但是,一旦縮小,地圖上的兩點越來越近,谷歌地圖就會考慮點的數量而不是重量,因此它會顯示爲已讀。我希望它是平均數,即(3 + 8)/2=5.5 ......代表任何顏色。這可能嗎?基於平均權重而非數據點數量的熱圖

回答

2

定義熱圖考慮點密度以及分配給每個點的權重。據我所知,至少Google的熱圖以這種方式工作。 所以你實際需要的不是一個熱圖,而是一個點的圖,它們將根據一個值進行着色。

我還需要更改Google熱度貼圖考慮的比例密度/重量,以便爲地圖着色,但我沒有找到任何方法。 目前熱圖的主要因素是密度,重量的變化對顏色影響很小。

2

作爲一個部分解決方案,我從以下項目中修改heatmap.js: https://github.com/pa7/heatmap.js

要在一個長/緯度點得到的平均我已經修改了_organiseData功能存儲PointCount和每個x,y位置的PointSum;和這些值,我得到的平均點:

store [x] [y] = storePointSum [x] [y]/storePointCount [x] [y];

我仍然在研究如何在多個x,y座標系以不同的地圖分辨率堆疊時修改「混合」......如果我知道我會發布它。

歡呼

〜亞倫

+1

*** ***更新看來好像使用的「添加劑alpha混合」定義(和控制)由HTML規範,這就是從根本上決定在這個特定的熱繪製的顏色地圖 - 可能大多數是由於其高性能特性。不幸的是,我一直無法找到一種方法來做「平均漸變阿爾法混合」。環境設置globalCompositeOperation看起來很有希望,但它似乎只支持傳統的混合。如果有人希望進一步探究,觀察者的兩個關鍵功能是_drawAlpha和_getPointTemplate。 –

3

有一個體面的有些解決方法,如果你像我一樣,不具備處理時間或電源產生的疊加,你不能修改任何現有的庫你喜歡。

我使用谷歌地圖heatmap庫並設置maxIntensity並消散爲false。將maxIntensity設置爲您選擇的值將解決您的熱點圖相對於彼此變色而不是0或設置值的問題。將散逸設置爲false將禁用在更改縮放級別時發生的自動半徑設置。

接下來,我爲每次縮放級別發生變化都做了一個事件,在這種情況下,我將半徑設置爲一個似乎代表我的數據的值,以最準確的方式表示縮放級別。

現在爲了擺脫地圖上的數據點混合在一起並將其添加到一個大紅色blob中的問題,我決定在我的地圖上爲每個要使用的縮放級別創建一個單獨的網格。我對所有在同一個網格點內框住的值進行平均,並確保網格足夠大以保持熱圖點重疊,但小到不會看起來像一堆圓圈。 (我發現網格應該是地圖上熱點半徑大小的0.4倍,以獲得平滑的外觀)。

熱圖點的半徑由google設置,以像素爲單位。我不知道如何將像素轉換爲緯度/經度,所以我只是通過繪製具有一定半徑的圓形畫線來測量它,然後測量這些線條之間的距離。如果您不打算繪製比一個小國家更多的地圖,那麼這種轉換方法將非常有效。

表現明智,這並不像我想象的那麼糟糕。我加載了大約2300個點,並且地圖加載速度與我爲每個縮放級別創建網格之前所做的速度一樣快,而且當您更改縮放級別時,實際上並未看到數據點正在刷新。

這裏有一些代碼段爲所有上述:

地圖設置:

map.heatmap.set('maxIntensity', 12000); 
map.heatmap.set('dissipating', false); 

更改網格和半徑每縮放級別:

map._on({ 
    obj: map.gMap, 
    event: "zoom_changed", 
    callback: function(){ 
     var zoomLevel = map.zoom(); 
     switch(zoomLevel){ 
      case 7: 
       map.heatmap.setData(gridData[zoomLevel]); 
       map.heatmap.set('radius', 0.04); 
       break; 
      case 8: 
       map.heatmap.setData(gridData[zoomLevel]); 
       map.heatmap.set('radius', 0.03); 
       break; 
      case 9: 
       map.heatmap.setData(gridData[zoomLevel]); 
       map.heatmap.set('radius', 0.02); 
       break; 
      case 10: 
       map.heatmap.setData(gridData[zoomLevel]); 
       map.heatmap.set('radius', 0.01); 
       break; 
      case 11: 
       map.heatmap.setData(gridData[zoomLevel]); 
       map.heatmap.set('radius', 0.005); 
       break; 
      case 12: 
       map.heatmap.setData(gridData[zoomLevel]); 
       map.heatmap.set('radius', 0.0025); 
       break; 
      case 13: 
       map.heatmap.setData(gridData[zoomLevel]); 
       map.heatmap.set('radius', 0.00225); 
       break; 
      default: 
       map.heatmap.setData(gridData[zoomLevel]); 
       map.heatmap.set('radius', 0.000625); 
     } 
    } 
}); 

我的網格中產生PHP對於每個人來說可能看起來都不一樣,但只是一個例子,下面是我使用的函數:

function getHeatGrid($gridSize){ 
$mapGrid = false; 
$mapData = false; 
$radius = $gridSize * 2.8 * 0.3; //grid size is multiplied by 2.8 to convert from the heat map radius to lat/long values(works for my lat/long, maybe not yours). * 0.3 is arbitrary to avoid seeing the grid on the map. 
$string = file_get_contents("mapData.json"); 
$json_a = json_decode($string, true); 

forEach($json_a as $key => $value){ 
    $row = intval(round(($value['center_longitude']/$radius))); 
    $column = intval(round(($value['center_latitude']/$radius)/68*111)); //around 52.0;5.0 latitude needs to be scaled to make a square grid with the used longitude grid size 
    if(isset($mapGrid[$row][$column])){ 
     $mapGrid[$row][$column] = round(($value['solarValue'] + $mapGrid[$row][$column])/2); 
    } else { 
     $mapGrid[$row][$column] = $value['solarValue']; 
    } 
} 

forEach($mapGrid as $long => $array){ 
    forEach($array as $lat => $weight){ 
     $mapData[] = array(
      "center_longitude" => $long * $radius, 
      "center_latitude" => ($lat * $radius)/111*68, 
      "solarValue" => $weight 
     ); 
    } 
} 
return $mapData; 
} 

不幸的是,我現在無法顯示地圖,因爲它目前對於我工作的公司的客戶保持私密,但如果它公開發布,我會添加一個鏈接,以便您瞭解此方法的工作情況。

希望這可以幫助別人。

盧卡斯