Last active
August 29, 2015 14:14
-
-
Save hitsujixgit/1562c11d53bcfc2bc92f to your computer and use it in GitHub Desktop.
横浜市の地図を、人口に応じて色分け表示する
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict' | |
### | |
* 色を変換する関数を定義する | |
### | |
hex2rgb = (hexcode) -> | |
# rgbに変換する | |
result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hexcode); | |
if result is null | |
console.log "error!" | |
return | |
[r,g,b] = [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] | |
return [r,g,b] | |
rgb2hsv = (r,g,b) -> | |
# rgb to hsv | |
r = r / 255 | |
g = g / 255 | |
b = b / 255 | |
max_v = Math.max(Math.max(r,g), b) | |
min_v = Math.min(Math.min(r,g), b) | |
v = max_v | |
s = max_v - min_v | |
if min_v == max_v | |
h = 0 | |
else if min_v == b | |
h = 60 * (g-r)/s + 60 | |
else if min_v == r | |
h = 60 * (b-g)/s + 180 | |
else | |
h = 60 * (r-b)/s + 300 | |
return [h,s,v] | |
hsv2rgb = (h,s,v) -> | |
console.log [h,s,v] | |
if h is null | |
r = 0 | |
g = 0 | |
b = 0 | |
else | |
h_dash = h / 60 | |
x = s * (1 - Math.abs(h_dash % 2 - 1)) | |
if h_dash < 1 | |
[r,g,b] = [s,x,0] | |
else if h_dash < 2 | |
[r,g,b] = [x,s,0] | |
else if h_dash < 3 | |
[r,g,b] = [0,s,x] | |
else if h_dash < 4 | |
[r,g,b] = [0,x,s] | |
else if h_dash < 5 | |
[r,g,b] = [x,0,s] | |
else if h_dash < 6 | |
[r,g,b] = [s,0,x] | |
else | |
console.log '変換エラー' | |
return | |
r += (v-s) | |
g += (v-s) | |
b += (v-s) | |
r *= 255 | |
g *= 255 | |
b *= 255 | |
return [Math.round(r),Math.round(g),Math.round(b)] | |
readTopoFileDone = false | |
readAttrFileDone = false | |
# fileから読み込んだdataの格納変数 | |
topo_data = null | |
attr_data = null | |
map_width = 500 | |
map_height = 650 | |
svg = null | |
### | |
* JSONファイルを読み込み、地図描画関数mainを呼び出す | |
### | |
readTopoFile = (json) -> | |
topo_data = json | |
readTopoFileDone = true | |
readAttrFile = (json) -> | |
attr_data = json | |
readAttrFileDone = true | |
d3.json("yokohama_topo_out.json", (error, json) -> | |
if error | |
return console.warn error | |
readTopoFile(json) | |
if readTopoFileDone and readAttrFileDone | |
main(topo_data, attr_data)) | |
d3.json("yokohama_codes_and_stat.json", (error, json) -> | |
if error | |
return console.warn(error) | |
readAttrFile(json) | |
if readTopoFileDone and readAttrFileDone | |
main(topo_data, attr_data)) | |
### | |
* 地図を描画する | |
### | |
main = (topo, attr) -> | |
labelLineHeight = 16 | |
# 属性情報を入れ直すためのHash Table | |
attrHash = [] | |
# attr情報を、IDをkeyとするhash-tableに変換する | |
# idをKeyとしたhashテーブル&property毎のhashテーブルを作成する | |
for e in attr | |
attrHash[e.cityid]=e | |
# 人口の最大値と最小値を求めておく | |
# --全年齢人口データのみを入れた配列を作成する | |
elements = [] | |
target_key = "ttl" | |
for e in attr | |
elements.push(e[target_key]) | |
# -- maxとminをとる | |
target_max = Math.max.apply(null, elements) | |
target_min = Math.min.apply(null, elements) | |
# svgを追加 | |
svg = d3.select("body #map").append("svg").attr("width", map_width).attr("height", map_height) | |
# 横浜市のmapを描画する | |
yokohama = topojson.object(topo, topo.objects.yokohama) | |
# 横浜市を中心に指定したメルカトル図法で10万分の1で描画する | |
projection = d3.geo.mercator().center([139.59,35.45]).scale(100000).translate([map_width / 2, map_height / 2]) | |
# pathを作成する | |
path = d3.geo.path().projection(projection) | |
svg.append("path").datum(yokohama).attr("d", path) | |
# classを指定する | |
svg.selectAll(".yokohama").data(yokohama.geometries).enter().append("path").attr("class", (d) -> | |
return "yokohama " + d.properties.name).attr("d", path) | |
# 色を塗る | |
hexcode_max = "#ee0000" | |
hexcode_min = "#00ee00" | |
# 念のためあらかじめ塗っておく | |
svg.selectAll("path").attr("fill", "#bee59e") | |
# HEXカラーコードからRGBに変換 | |
[r_min,g_min,b_min] = hex2rgb(hexcode_min) | |
[r_max,g_max,b_max] = hex2rgb(hexcode_max) | |
# RGB(0-255)からHSVに変換 | |
[h_min,s_min,v_min] = rgb2hsv(r_min,g_min,b_min) | |
[h_max,s_max,v_max] = rgb2hsv(r_max,g_max,b_max) | |
areaGrad = d3.scale.linear().domain([target_min, target_max]).range([[h_min,s_min,v_min], [h_max,s_max,v_max]]) | |
for k, v of attrHash | |
[h,s,v] = areaGrad(attrHash[k][target_key]) | |
[r,g,b] = hsv2rgb(h,s,v) | |
svg.selectAll("."+k).attr("fill", "rgba(#{r},#{g},#{b},1)") | |
# 内部境界に線を引く | |
svg.append("path") | |
.datum(topojson.mesh(topo, topo.objects.yokohama, (a, b) -> | |
return a isnt b)) | |
.attr("d", path) | |
.attr("class", "subunit-boundary") | |
# 区コードのラベル貼り | |
city_labels = new Array() | |
svg.selectAll(".cityname-label") | |
.data(yokohama.geometries) | |
.enter() | |
.append("text") | |
.attr("class", (d) -> | |
if not (city_labels.indexOf(d.properties.name) > -1) | |
city_labels.push(d.properties.name) | |
return "cityname-label "+d.properties.name) | |
.attr("transform", (d) -> | |
# 文字をpath中央から、文字高さ1/2分高い位置に貼る | |
pos = path.centroid(d) | |
pos[1] -= labelLineHeight / 2 | |
return "translate(" + pos + ")") | |
.attr("dy", ".35em") | |
.text((d) -> | |
return attrHash[d.properties.name].name) | |
# 値ラベル貼り | |
svg.selectAll(".stat-label") | |
.data(yokohama.geometries) | |
.enter() | |
.append("text") | |
.attr("class", (d) -> | |
if not (city_labels.indexOf(d.properties.name) > -1) | |
city_labels.push(d.properties.name) | |
return "stat-label "+d.properties.name) | |
.attr("transform", (d) -> | |
# 文字をpath中央から、文字高さ1/2分高い位置に貼る | |
pos = path.centroid(d) | |
pos[1] += labelLineHeight / 2 | |
return "translate(" + pos + ")") | |
.attr("dy", ".35em") | |
.text((d) -> | |
return attrHash[d.properties.name][target_key]) | |
# 各最初のエリアのみラベルを表示する | |
for id in city_labels | |
svg.select(".cityname-label."+id).style("display", "block") | |
svg.select(".stat-label."+id).style("display", "block") | |
return true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment