|
<!DOCTYPE html> |
|
<head> |
|
<meta charset="utf-8"> |
|
<script src="https://d3js.org/d3.v4.min.js"></script> |
|
<script src="//d3js.org/topojson.v1.min.js"></script> |
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/awesomplete/1.1.2/awesomplete.min.js"></script> |
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/awesomplete/1.1.2/awesomplete.min.css"> |
|
<style> |
|
body { |
|
background: #222; |
|
} |
|
.kommun { |
|
stroke: #303030; |
|
fill: #383838; |
|
} |
|
|
|
circle { |
|
fill: #c27575; |
|
fill-opacity: 0.8; |
|
mix-blend-mode: screen; |
|
pointer-events:none; |
|
} |
|
|
|
.search { |
|
display: flex; |
|
width: 300px; |
|
margin-bottom: 8px; |
|
} |
|
|
|
.btn { |
|
background: white; |
|
} |
|
|
|
.search { |
|
width: 300px; |
|
} |
|
|
|
.dropdown-input { |
|
width: 100%; |
|
font-size: 16px; |
|
padding: 4px 8px; |
|
|
|
} |
|
|
|
.numbers { |
|
position: absolute; |
|
color: white; |
|
top: 100px; |
|
font-size: 32px |
|
} |
|
</style> |
|
|
|
</head> |
|
|
|
<body> |
|
<div class="search"> |
|
<input id="myinput" class="dropdown-input" list="mylist" /> |
|
<datalist id="mylist"> |
|
<option>1</option> |
|
<option>2</option> |
|
<option>3</option> |
|
<option>4</option> |
|
<option>5</option> |
|
<option>6</option> |
|
<option>7</option> |
|
</datalist> |
|
</div> |
|
|
|
<div class="numbers"> |
|
<span id="number">300</span> historier |
|
</div> |
|
<svg> |
|
</svg> |
|
|
|
<script> |
|
var width = 300, |
|
height = 600; |
|
|
|
var projection = d3.geoMercator() |
|
.scale(1100) |
|
.center([17, 63]) |
|
.translate([width/2, height/2]); |
|
|
|
//Define path generator |
|
var path = d3.geoPath() |
|
.projection(projection); |
|
|
|
var svg = d3.select("svg") |
|
.attr("width", width) |
|
.attr("height", height); |
|
|
|
var container = svg.append('g').classed('container',true); |
|
|
|
d3.json("lan.json", function(error, geo) { |
|
var paths = container |
|
.append('g') |
|
.classed('paths', true) |
|
.selectAll('g') |
|
.data(geo.features) |
|
.enter() |
|
.append('path') |
|
.attr('d', path) |
|
.attr('id', (d,i) => i) |
|
.classed("kommun", true); |
|
|
|
const dots = svg.append('g').classed('dots', true); |
|
|
|
paths |
|
.each(function(d,i) { |
|
var center = projection(d3.geoCentroid(d)); |
|
|
|
var noDots = Math.floor(Math.random() * 10) + 1; |
|
|
|
if (noDots > 8) { |
|
for (let i=0; i<noDots; i++) { |
|
var jitterX = Math.floor(Math.random() * 15) + 1; |
|
var jitterY = Math.floor(Math.random() * 15) + 1; |
|
|
|
dots.append("circle") |
|
.attr("cx", center[0] + jitterX) |
|
.attr("cy", center[1] + jitterY) |
|
.attr("r", 2); |
|
} |
|
} |
|
}); |
|
}); |
|
|
|
d3.selection.prototype.moveToFront = function() { |
|
return this.each(function(){ |
|
this.parentNode.appendChild(this); |
|
}); |
|
}; |
|
|
|
let active = d3.select(null); |
|
|
|
function clicked(d) { |
|
if (active.node() === this) return reset(); |
|
|
|
active.classed("active", false); |
|
active = d3.select(this).classed("active", true); |
|
|
|
var bounds = path.bounds(d), |
|
x = (bounds[0][0] + bounds[1][0]) / 2, |
|
y = (bounds[0][1] + bounds[1][1]) / 2, |
|
scale = 10; |
|
translate = [width / 2 - scale * x, height / 2 - scale * y]; |
|
|
|
var dots = svg.selectAll('circle'); |
|
dots.transition() |
|
.duration(750) |
|
.attr("r", "0.6") |
|
.attr("transform", "translate(" + translate + ")scale(" + scale + ")"); |
|
|
|
var g = svg.select('.container'); |
|
g.transition() |
|
.duration(750) |
|
.style("stroke-width", 1.5 / scale + "px") |
|
.attr("transform", "translate(" + translate + ")scale(" + scale + ")"); |
|
} |
|
|
|
|
|
function reset() { |
|
active.classed("active", false); |
|
active = d3.select(null); |
|
var g = svg.select('.container'); |
|
g.transition() |
|
.duration(750) |
|
.style("stroke-width", "1.5px") |
|
.attr("transform", ""); |
|
|
|
var dots = svg.selectAll('circle'); |
|
dots.transition() |
|
.duration(750) |
|
.attr("r", "2") |
|
.attr("transform", ""); |
|
} |
|
</script> |
|
</body> |