|
var width = 300, |
|
height = 300 |
|
|
|
var scale = 1500 |
|
var translate = [-100, 1500] |
|
var labelPadding = 3 |
|
|
|
var firs |
|
|
|
var svg = d3.select('#viz') |
|
.append('svg') |
|
.attr('width', width) |
|
.attr('height', height) |
|
|
|
// find proper scale and translation from bounds of europe polygon |
|
var projection = d3.geo.azimuthalEqualArea() |
|
.scale(scale) |
|
.translate(translate) |
|
var path = d3.geo.path().projection(projection) |
|
|
|
var selected = d3.set(['EYVLFIR', 'EPWWFIR']) |
|
// var selected = d3.set(['EYVLFIR']) |
|
// var selected = d3.set(['EPWWFIR']) |
|
// var selected = d3.set([ |
|
// 'LGGGFIR', |
|
// 'LIBBFIR', 'LIMMFIR', 'LIRRFIR', |
|
// 'LMMMFIR', |
|
// 'LCCCFIR' |
|
// ]) |
|
|
|
// ca. BBox for Poland and Lituania |
|
var geojObj = { |
|
'type': 'FeatureCollection', |
|
'features': [{ |
|
'type': 'Feature', |
|
'geometry': { |
|
'type': 'Polygon', |
|
'coordinates': [ |
|
[ |
|
[14.0, 48.7], |
|
[14.0, 56.6], |
|
[27.4, 56.6], |
|
[27.4, 48.7], |
|
[14.0, 48.7] |
|
] |
|
] |
|
}, |
|
'properties': { |
|
'name': 'A' |
|
} |
|
}] |
|
} |
|
|
|
var tooltip = d3.select('#tooltip').classed('hidden', true), |
|
tooltiptext = d3.select('#tooltiptext') |
|
|
|
var background = svg.selectAll('rect.background') |
|
.data([{}]).enter() |
|
.append('rect') |
|
.classed('background', true) |
|
var g = svg.selectAll('g.all') |
|
.data([{}]).enter() |
|
.append('g') |
|
.classed('all', true) |
|
var active = d3.select(null) |
|
|
|
var zoom = d3.behavior.zoom() |
|
.scaleExtent([1, 8000]) |
|
.on('zoom', zoomed) |
|
|
|
function zoomed () { |
|
g.style('stroke-width', 1.5 / d3.event.scale + 'px') |
|
g.attr('transform', 'translate(' + d3.event.translate + ')scale(' + d3.event.scale + ')') |
|
} |
|
|
|
// If the drag behavior prevents the default click, |
|
// also stop propagation so we don’t click-to-zoom. |
|
function stopped () { |
|
if (d3.event.defaultPrevented) d3.event.stopPropagation() |
|
} |
|
|
|
function reset () { |
|
active.classed('active', false) |
|
active = d3.select(null) |
|
svg.transition() |
|
.duration(750) |
|
.call(zoom.translate([0, 0]).scale(1).event) |
|
} |
|
|
|
function clicked (d) { |
|
if (active.node() === this) { |
|
console.log('this node is active') |
|
return reset() |
|
} |
|
active.classed('active', false) |
|
active = d3.select(this).classed('active', true) |
|
|
|
var bounds = path.bounds(d), |
|
dx = bounds[1][0] - bounds[0][0], |
|
dy = bounds[1][1] - bounds[0][1], |
|
x = (bounds[0][0] + bounds[1][0]) / 2, |
|
y = (bounds[0][1] + bounds[1][1]) / 2, |
|
scale = .95 / Math.max(dx / width, dy / height), |
|
translate = [width / 2 - scale * x, height / 2 - scale * y] |
|
svg.transition() |
|
.duration(750) |
|
.call(zoom.translate(translate).scale(scale).event) |
|
} |
|
|
|
// prj is the projection |
|
// pth is the path |
|
// gObj is the geojson object |
|
function scaleAndTranslate (prj, pth, gObj) { |
|
prj |
|
.scale(1) |
|
.translate([0, 0]) |
|
|
|
var b = pth.bounds(gObj), |
|
dx = (b[1][0] - b[0][0]), |
|
dy = (b[1][1] - b[0][1]), |
|
x = (b[1][0] + b[0][0]), |
|
y = (b[1][1] + b[0][1]), |
|
s = .95 / Math.max(dx / width, |
|
dy / height), |
|
t = [(width - s * x) / 2, |
|
(height - s * y) / 2] |
|
|
|
// return the scale and translate to be used to update the projection. |
|
// Such as |
|
// projection.scale(s).translate(t) |
|
return {'scale': s, 'translate': t} |
|
} |
|
|
|
svg.on('click', stopped, true) |
|
background.on('click', reset) |
|
g.style('stroke-width', '0.5px') |
|
|
|
svg |
|
.call(zoom) // delete this line to disable free zooming |
|
.call(zoom.event) |
|
|
|
svg.on('mousemove', function () { |
|
// update tooltip position |
|
tooltip.style('top', (event.pageY + 16) + 'px').style('left', (event.pageX + 10) + 'px') |
|
return true |
|
}) |
|
|
|
d3.json('FIRs_NM.json', function (error, fir) { |
|
if (error) throw error |
|
firs = topojson.feature(fir, fir.objects.FIRs_NM) |
|
|
|
var graticule = d3.geo.graticule() |
|
|
|
var myfirs = firs.features.filter(function (d) { |
|
return selected.has(d.id) |
|
}) |
|
|
|
// var sAndT = scaleAndTranslate(projection, path, firs) |
|
// projection.scale(sAndT.scale).translate(sAndT.translate) |
|
|
|
var gFIR = g.selectAll('.fir') |
|
.data(myfirs) |
|
.enter() |
|
.append('g') |
|
.attr('class', 'fir') |
|
|
|
var fff = gFIR |
|
.append('path') |
|
.attr('class', function (d) { |
|
return 'fir ' + d.id |
|
}) |
|
.attr('d', path) |
|
|
|
gFIR.selectAll('.point') |
|
.data(function (d, i) { |
|
return d.geometry.coordinates[0] |
|
}) |
|
.enter().append('circle') |
|
.attr('class', 'point') |
|
.attr('cx', function (d) { |
|
return projection([d[0], d[1]])[0] |
|
}) |
|
.attr('cy', function (d) { |
|
return projection([d[0], d[1]])[1] |
|
}) |
|
.attr('r', 1) |
|
.attr('fill', 'red') |
|
.attr('opacity', 0.3) |
|
|
|
var label = gFIR.selectAll('.label') |
|
.data(function (d) { |
|
return (d.geometry.coordinates[0]).filter(function (d, i) { |
|
// if (i%3 === 0) return true |
|
return true |
|
}) |
|
}) |
|
.enter().append('g') |
|
.attr('class', 'label') |
|
.attr('transform', function (d, i) { |
|
return 'translate(' + |
|
projection([d[0], d[1]])[0] + ',' + |
|
projection([d[0], d[1]])[1] + ')' |
|
}) |
|
label.append('text') |
|
// .attr("dy", ".35em") |
|
.text(function (d, i) { |
|
return i |
|
}) |
|
|
|
// from http://stackoverflow.com/a/16093597/963575 |
|
var mmm = topojson.merge( |
|
fir, |
|
fir.objects.FIRs_NM.geometries.filter(function (d) { |
|
return selected.has(d.id) |
|
})) |
|
|
|
g.append('path') |
|
.datum(mmm) |
|
.attr('class', 'merged') |
|
.attr('transform', 'translate(20, 30)') |
|
.attr('d', path) |
|
|
|
}) |