2017-11-24 9 views
2

次の作業にd3を使用したい: ドーナツチャートを各国の中心に表示する回転球体を表示する。地球と対話することができるはずです(国の選択、ズーム、回転)。 d3はすべての部分を実装する簡単な方法を提供していますが、必要に応じてドーナツの一部を動作させることはできません。 globe with donut :それはのように、ドーナツは、地球の上に平面上に表示されているように、コードとによってD3球体/球体に投影されたドーナツチャート

var arc = d3.arc(); 
var data = [3, 23, 17, 35, 4]; 
var radius = 15/scale; 
var _arc = arc.innerRadius(radius - 7/scale) 
      .outerRadius(radius).context(donutsContext); 
var pieData = pie(data); 
for (var i = 0; i < pieData.length; i++) { 
    donutsContext.beginPath(); 
    donutsContext.fillStyle = color(i); 
    _arc(pieData[i]); 
} 

簡単な方法はd3.arcの助けを借りて、ドーナツグラフを描くがあります

私は彼らが世界中

の周りに「ラップ」することにしたい一方で、正しく世界に投影することができるd3.geoCircleの方法があります。私は2つの円の助けを借りて世界に正しく投影「リング」だ:

var circle = d3.geoCircle() 
    .center(centroid) 
    .radius(2); 
var outerCircle = circle(); 
var circle = d3.geoCircle() 
    .center(centroid) 
    .radius(1); 
var innerCircle = circle(); 

var interCircleCoordinates = []; 
for (var i = innerCircle.coordinates[0].length - 1; i >= 0; i--) { 
    interCircleCoordinates.push(innerCircle.coordinates[0][i]); 
} 
outerCircle.coordinates.push(interCircleCoordinates); 

globe with rings

を私は実際にドーナツを取得する必要があります。私が試した他の方法は、ドーナツから画像を取得し、ピクセル操作の助けを借りて、世界中のこのイメージをラッピングされ

var image = new Image; 
image.onload = onload; 
image.src = img; 

function onload() { 
    window.dx = image.width; 
    window.dy = image.height; 

    context.drawImage(image, 0, 0, dx, dy); 
    sourceData = context.getImageData(0, 0, dx, dy).data; 
      target = context.createImageData(width, height); 
      targetData = target.data; 

    for (var y = 0, i = -1; y < height; ++y) { 
     for (var x = 0; x < width; ++x) { 
      var p = projection.invert([x, y]), λ = p[0], φ = p[1]; 
       if (λ > 180 || λ < -180 || φ > 90 || φ < -90) { i += 4; continue; } 
       var q = ((90 - φ)/180 * dy | 0) * dx + ((180 + λ)/360 * dx | 0) << 2; 
       var r = sourceData[q]; 
       var g = sourceData[++q]; 
       var b = sourceData[++q]; 
       targetData[++i] = r; 
       targetData[++i] = g; 
       targetData[++i] = b; 
       targetData[++i] = 125;// 
     } 
    } 
    context.clearRect(0,0, width, height); 
    context.putImageData(target, 0, 0); 
}; 

私は世界のために、世界中で非常に遅く回転との相互作用を得るこの方法によって、私はだから私の質問は(1000px)

を必要とするサイズ:

  1. は球にd3.arcのヘルプ(世界、ORTで生成されたドーナツを投影するためのいくつかの方法がありますですホログラム投影)?
  2. geoCircleからドーナツを得る方法はありますか?
  3. たぶん私は
+0

'geoPath'を' context.arc() '(https://github.com/d3/d3-geo/blob/master/README.md#geoPath)で使用できますか? –

答えて

1

地球上のドーナツを表示するために頭に浮かぶ一つの方法がありますが表示されていない私の目標を達成するための他のいくつかの方法があります。重要な課題は、d3が3次元オブジェクトを非常にうまく投影しないことです。したがって、「簡単な」ソリューションは、円グラフを地理フィーチャに変換し、フィーチャの残りの部分とともに投影することです。これを行うには

以下を行う必要があります。あなたは、通常、Goはパイの形状を近似するポイントを得るために生成されたパスに沿って

  • 同じよう

    • パイ/ドーナツ・ジェネレータを使用してください。
    • 長い/緯度の点にポイント
    • は、地図上ににGeoJSON
    • プロジェクトそれらをにこれらのポイントを組み立て変換します。

    最初の点は簡単ですが、内側の半径の円グラフを作成するだけです。

    を使用して各パスを選択して周長に沿ってポイントを見つける必要があります。これはパスの長さに依存するため、path.getTotalLength()が便利です(コーナーが重要なので少し複雑にしたいあなたがそれらを得ることを保証するためにこれらのコーナーケースのために))。

    ポイントを取得したら、2番目の投影を使用する必要があります。方位角の等距離が最適です。円グラフがsvg座標空間で[0,0]の中央に配置されている場合は、中心座標がsvg空間の[0,0]に位置するように方位角を回転させます(中心にしないでください)。それらを配置するためにパイが、それはちょうど余分なステップを追加します)。各点をとり、projection.invert()に2番目の投影を使用して実行します。ドーナツチャートごとに異なる地理的重心を持つように、投影を更新する必要があります。

    緯度が長い場合は、既にgeojsonに変換し、正射投影で投影することは簡単です。


    このアプローチは、私のような何かを与えた:

    enter image description here

    注:データに応じて、それがにGeoJSONにデータを前処理する最も簡単なことや保存可能性があることにGeoJSONそれぞれの計算とは対照的に、ページの読み込み。

    、カスタムを使って、SVGや表示SVG要素を持っている必要はありませんあなたは、あなたはまだgetPointAtLengthのようなSVGの機能にアクセスできるようにする必要があり、実際にSVGを使用する必要はありませんがあなたは、キャンバスを使用している

    パスを複製要素:

    document.createElementNS(d3.namespaces.svg, 'path'); 
    

    ああ、及び第二の突起の変換が設定されていることを確認します - デフォルトは[480250]行方不明ならば、物事をオフにスローされますすべてのD3の予測のための(ほとんど?)。

  • +0

    ありがとう、アンドリュー!できます! (私はあなたの説明に従うカップル時間でこれを実装することもできます) – Katya

    +0

    ちょっとしたコメント - 少なくともChromeではgetPointAtDistanceの代わりにgetPointAtLengthを見つけました – Katya

    +0

    これは私の部分のタイプミスです - getPointAtLengthにする必要があります。 –