【D3.js】stereographicプロジェクションを使って全天球表示
アメリカ地質調査所(USGS)が公開している過去7日間の地震データを地図上に表示しています。
単純に表示するのもなんだったので、d3.geo.stereographicを利用して全天球表示というのをやってみました。グリグリ動いて楽しいのですが……見やすくは無いですね。
サンプル
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
d3.json('../../_geodata/conuntries.geojson', function(data) { d3.json('http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson', function(earthquakes){ main(data, earthquakes); }); }); function main(mapdata, earthquakes){ var div = d3.select('body').append('div').attr('id', 'stereographic'); var width = parseInt(div.style('width'), 10); var height = parseInt(div.style('height'), 10); var svg = div.append('svg') .attr('width', width) .attr('height', height); // プロジェクションの回転角を収納 var rotate = {x: 0, y: 45}; // プロジェクション設定(全天球表示) var projection = d3.geo.stereographic() .scale(4.5 * height / Math.PI) .translate([width / 2, height / 2]) .clipAngle(120) .rotate([rotate.x, -rotate.y]) // パスジェネレーター生成 var path = d3.geo.path().projection(projection); /********************************************************** * アウトライン(外周)を追加 **********************************************************/ svg.append('path').datum({type: 'Sphere'}) .attr({ 'class': 'cellestial-globe', 'd': path }); /********************************************************** * グリッドラインを追加 **********************************************************/ var graticule = d3.geo.graticule(); var lines = svg.selectAll('path.graticule').data([graticule()]) .enter().append('path') .attr({ 'class': 'graticule', 'd': path, 'stroke': 'gray' }); /********************************************************** * 地形を追加 **********************************************************/ var map = svg.selectAll('path.map').data(mapdata.features) .enter().append('path') .attr({ 'class': 'map', 'd':path, 'stroke': 'lime', 'fill':'green', 'fill-opacity':0.6 }) /********************************************************** * 震度サークルを追加 **********************************************************/ //震度スケール設定 var earthquakesScale = d3.scale.sqrt().domain([0, 10]).rangeRound([0, 10]) //地震サークル追加 var eqCircle = svg.selectAll('circle.earthquake').data(earthquakes.features) .enter().append('circle') .attr({ 'class': 'earthquake', 'r':function(d){return earthquakesScale(d.properties.mag) }, 'fill': 'none', 'stroke': 'red', 'stroke-width':2, 'stroke-opacity': 0.8 }); //緯度経度→xy座標変換 earthquakes.features.forEach(function(d){ d.xy = projection(d.geometry.coordinates) }); eqCircle.attr({ 'cx': function(d){ return d.xy[0] }, 'cy': function(d){ return d.xy[1] } }); /********************************************************** * ドラッグイベント処理 **********************************************************/ //ドラッグ時ビヘイビア 設定 var dragBehavior = d3.behavior.drag() .origin(Object) .on('drag', drag); //マウスドラッグイベントキャッチ用オーバーレイを追加 var overlay = svg.selectAll('rect').data([rotate]) .enter().append('rect'); overlay .attr('width', width) .attr('height', height) .attr('fill-opacity', 0); overlay.call(dragBehavior); //ドラッグ時処理 function drag(d) { projection.rotate([(d.x = d3.event.x) / 2, -(d.y = d3.event.y) / 2]); lines.attr('d', path); map.attr('d', path); earthquakes.features.forEach(function(d){ d.xy = projection(d.geometry.coordinates) }); eqCircle.attr({ 'cx': function(d){ return d.xy[0] }, 'cy': function(d){ return d.xy[1] } }); } } |