Skip to content

Instantly share code, notes, and snippets.

@darosh
Last active October 30, 2015 11:36
Show Gist options
  • Save darosh/14e2e4e14898f13e13c7 to your computer and use it in GitHub Desktop.
Save darosh/14e2e4e14898f13e13c7 to your computer and use it in GitHub Desktop.
Planetary Grid Browser I
function Config() {
'use strict';
return {
shift: 31.2,
lineWidth: 1,
symbolLine: 4,
dash: [2, 3],
fontSize: 16,
lineMid: 11,
titleSize: 18,
lineHeight: 19,
durationScale: 1.2,
durationSpeed: 1.5,
durationMin: 750,
durationMax: 2000,
frameLineWidth: 3,
mraf: !window.chrome,
filter: {
map: {},
graticule: {off: true},
'cool-line': {},
'hot-line': {},
'balanced-line': {},
'cool-point': {off: true},
'hot-point': {off: true},
'balanced-point': {off: true},
megalith: {},
mound: {},
pyramid: {},
temple: {},
volcano: {},
place: {}
},
colors: {
water: '#def4ff',
graticule: '#999',
land: '#ffffff',
border: 'rgba(0,0,0,0.5)',
cool: '#1f78b4',
hot: '#e31a1c',
balanced: '#333',
frame: '#333',
focus: 'rgba(0,0,0,0.87)',
selection: 'rgba(255,255,255,0.58)',
shape: '#333',
bg: '#fff'
},
shapes: {
megalith: '#299ae6',
mound: '#90de43',
pyramid: '#ffff4d',
temple: '#ff7f00',
volcano: '#e31a1c',
place: '#ccc'
},
sizes: {
megalith: 80,
mound: 66,
pyramid: 66,
temple: 80,
volcano: 48,
place: 48,
'hot-line': 80,
'cool-line': 80,
'balanced-line': 80,
'cool-point': 80,
'hot-point': 80,
'balanced-point': 80,
'map': 100
},
symbols: {
megalith: 'square',
mound: 'triangle-up',
pyramid: 'triangle-up',
temple: 'cross',
volcano: 'circle',
place: 'circle'
}
};
}
function SvgGlobe(root, width, height, cfg) {
'use strict';
var maxScale = 3;
var self;
var round = d3.geo.transform({
point: function (x, y) {
this.stream.point(~~x, ~~y);
}
});
var projectionGlobe = d3.geo
.orthographic()
.clipAngle(90)
.precision(0)
.translate([height / 2, height / 2])
.scale(height / 2);
var projectionRaw = d3.geo
.orthographic()
.precision(2)
.clipAngle(90)
.translate([height / 2, height / 2])
.scale(height / 2);
var projectionRawZero = d3.geo
.orthographic()
.precision(0)
.clipAngle(90)
.translate([height / 2, height / 2])
.scale(height / 2);
var projectionRawZeroRound = {
stream: function (s) {
return projectionRawZero.stream(round.stream(s));
}
};
var projectionGlobeCalc = d3.geo
.orthographic()
.clipAngle(90)
.translate([height / 2, height / 2])
.scale(height / 2);
var projectionLinesGlobe = d3.geo
.orthographic()
.rotate([cfg.shift, 0, 0])
.precision(10)
.clipAngle(90)
.translate([height / 2, height / 2])
.scale(height / 2);
var pathRaw = d3.geo.path()
.projection(projectionRaw);
var pathRawZero = d3.geo.path()
.projection(projectionRawZero);
var pathRawZeroRound = d3.geo.path()
.projection(projectionRawZeroRound);
var pathLinesGlobe = d3.geo.path()
.projection(projectionLinesGlobe);
var zoom = d3.behavior.zoom().scaleExtent([1, maxScale])
.on('zoomstart', zoomed)
.on('zoom', zoomed)
.on('zoomend', zoomed);
root.append('circle')
.attr('class', 'overlay-white')
.attr('cx', width / 2)
.attr('cy', height / 2)
.attr('r', height / 2);
root.append('circle')
.attr('class', 'map water')
.attr('cx', width / 2)
.attr('cy', height / 2)
.attr('r', height / 2);
var graticuleGlobe = root.append('path').datum(d3.geo.graticule()())
.attr('class', 'graticule')
.style('display', 'none')
.attr('d', pathRaw);
var landGlobe = root.append('path').attr('class', 'map land country');
var lineGlobeG = root.append('g').attr('stroke-width', 1);
root.call(zoom);
root.append('circle')
.attr('class', 'border')
.style('stroke-width', cfg.frameLineWidth)
.attr('cx', width / 2)
.attr('cy', height / 2)
.attr('r', height / 2);
var g = root.append('g');
var h = d3.geo.hexakisIcosahedron;
Utils.svgLines(lineGlobeG, pathLinesGlobe, h.icosahedronEdges(), 'cool-line', 'Cool line');
Utils.svgLines(lineGlobeG, pathLinesGlobe, h.hexakisCenterEdges(), 'hot-line', 'Hot line');
Utils.svgLines(lineGlobeG, pathLinesGlobe, h.hexakisSideEdges(), 'balanced-line', 'Balanced line');
var linesSelection = root.selectAll('.line');
var highlight = root.append('circle')
.style('display', 'none')
.attr('class', 'border land')
.attr('cx', width / 2)
.attr('cy', height / 2)
.attr('r', 5);
var a, pG, pGL;
function zoomed() {
var m = d3.mouse(this);
if (d3.event && d3.event.sourceEvent) {
d3.event.sourceEvent.stopPropagation();
d3.event.sourceEvent.preventDefault();
}
({
zoomstart: function () {
pG = projectionGlobe.rotate();
pGL = projectionLinesGlobe.rotate();
projectionGlobeCalc.rotate(pG);
a = projectionGlobeCalc.invert(m);
},
zoom: function () {
var b = projectionGlobeCalc.invert(m);
var pgR = [pG[0] + b[0] - a[0], pG[1] + b[1] - a[1]];
var plgR = [pGL[0] + b[0] - a[0], pGL[1] + b[1] - a[1]];
if (self.canZoom && !self.canZoom(pgR)) {
return;
}
if (!isNaN(b[0]) && !isNaN(b[1])) {
projectionRaw.rotate(pgR);
projectionRawZero.rotate(pgR);
projectionGlobe.rotate(pgR);
projectionLinesGlobe.rotate(plgR);
update();
if (self.onZoomed) {
var s = zoom.scale();
self.onZoomed(null, s, pgR);
}
}
},
zoomend: function () {
}
})[d3.event.type]();
}
function updateSelection() {
if (self.selection) {
var coo = self.selection.geometry ? self.selection : {
'type': 'Feature',
'geometry': {'type': 'Point', 'coordinates': [self.selection[0] + cfg.shift, self.selection[1], 0]}
};
var p = pathRaw.centroid(coo);
if (!isNaN(p[0]) && !isNaN(p[1])) {
p[0] -= width / 2;
p[1] -= height / 2;
highlight.style('display', null);
highlight.attr('transform', 'translate(' + p + ')');
} else {
highlight.style('display', 'none');
}
} else {
highlight.style('display', 'none');
}
}
function update(running) {
projectionLinesGlobe.precision(running ? 2 : 1);
if (!cfg.filter.map.off) {
landGlobe.attr('d', pathRawZeroRound);
}
if (!cfg.filter.graticule.off) {
graticuleGlobe.attr('d', pathRaw);
}
linesSelection.attr('d', pathLinesGlobe);
updateSelection();
}
function setZoom(t, s, i, running) {
zoom.scale(s);
projectionLinesGlobe.rotate([i[0] + cfg.shift, i[1]]);
projectionGlobe.rotate(i);
projectionRaw.rotate(i);
projectionRawZero.rotate(i);
update(running)
}
self = {
root: root,
land: landGlobe,
pathRaw: pathRaw,
setZoom: setZoom,
updateSelection: updateSelection,
update: update
};
return self;
}
<!DOCTYPE html>
<meta charset="utf-8">
<title>Planetary Grid I</title>
<link rel="stylesheet" href="style.css">
<body>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/topojson/1.6.19/topojson.min.js"></script>
<script src="/darosh/raw/2fe464efd794bde5ed68/hexakis-icosahedron.js"></script>
<script src="/darosh/raw/2d12a584a14910032ab8/togeojson.js"></script>
<script src="config.js"></script>
<script src="utils.js"></script>
<script src="globe.js"></script>
<script src="map.js"></script>
<script src="legend.js"></script>
<script src="list.js"></script>
<script src="info.js"></script>
<script>
(function () {
'use strict';
var widthList = 220;
var margin = 12;
var widthScrollBar = self.frameElement ? 0 : 20;
var widthScreen = Math.max(document.body.clientWidth || 0, 960) - widthScrollBar;
widthScreen = Math.min(1480, widthScreen);
var heightScreen = Math.max(500, widthScreen / (960 / 480));
margin = widthScreen > 960 ? margin * 2 : margin;
var widthGlobe = 200;
var heightGlobe = 200;
if (heightScreen > 660) {
widthGlobe = 280;
heightGlobe = 280;
}
var widthLegend = 140;
var widthMap = widthScreen - Math.max(widthLegend, widthGlobe / 2) - 2 * margin;
var heightMap = heightScreen - heightGlobe / 2 - 2 * margin;
var selected;
var cfg = new Config();
cfg.url = 'http://bl.ocks.org/darosh/14e2e4e14898f13e13c7';
var svg = d3.select('body').append('svg')
.attr('width', widthMap + Math.max(widthLegend, widthGlobe / 2) + 2 * margin)
.attr('height', heightMap + heightGlobe / 2 + 2 * margin);
var map = new SvgMap(svg, widthMap, heightMap, margin, cfg);
var legend = new SvgLegend(svg.append('g')
.attr('transform', 'translate(' + [widthMap + margin + cfg.lineMid, margin] + ')'),
cfg, clickedLegend
);
cfg.filter = legend.lookFilter;
var globe = new SvgGlobe(svg.append('g')
.attr('transform', 'translate(' + [widthMap - widthGlobe / 2 + margin, heightMap - heightGlobe / 2 + margin] + ')'),
widthGlobe, heightGlobe, cfg
);
var info = new HtmlInfo(d3.select('body').append('div')
.style('position', 'absolute')
.style('left', (2 * margin) + 'px')
.style('top', (2 * margin) + 'px')
.style('border', cfg.frameLineWidth + 'px solid ' + cfg.colors.frame)
.style('padding', (cfg.titleSize * 0.75) + 'px')
.style('min-width', (cfg.titleSize * 8) + 'px')
.style('background-color', cfg.colors.bg),
cfg
);
var controls = svg.append('g')
.attr('transform', 'translate(' + [margin * 1.5, heightMap + margin * .5 - 22] + ')');
Utils.svgControls(controls, setIndex, map.reset);
var list = new SvgList(svg.append('g')
.attr('transform', 'translate(' + [margin, (heightMap + margin + cfg.lineMid)] + ')'),
cfg, widthMap - widthGlobe / 2, widthList,
function (h) {
h = heightMap + h + 3 * margin;
svg.attr('height', h);
d3.select(self.frameElement).style('height', h + 'px');
},
selectedPlace
);
map.clickedPoint = function (p) {
selectedPlace(p);
};
map.onZoomed = globe.setZoom;
globe.onZoomed = map.setZoom;
globe.canZoom = function (i) {
var p = map.projection(i);
return !isNaN(p[0]) && !isNaN(p[1]);
};
if (self.frameElement) {
self.frameElement.focus();
}
d3.select('body').on('keydown', function () {
var i = null;
if (d3.event.keyCode === 37) {
i = -1;
} else if (d3.event.keyCode === 39) {
i = +1;
} else if (d3.event.keyCode === 27 && selected) {
selectedPlace(selected);
}
if (i !== null) {
setIndex(i);
}
});
d3.json('mercator-countries.json', function (topo) {
topojson.presimplify(topo);
map.countries.datum(topojson.mesh(topo, topo.objects.countries)).attr('d', map.path);
});
d3.json('mercator-land.json', function (topo) {
topojson.presimplify(topo);
map.land.datum(topojson.feature(topo, topo.objects.land)).attr('d', map.path);
});
d3.json('land.json', function (topo) {
globe.land.datum(topojson.feature(topo, topo.objects.land)).attr('d', globe.pathRaw);
});
d3.xml('/darosh/raw/2d12a584a14910032ab8/places.kml', function (xml) {
var geo = toGeoJSON.kml(xml);
Utils.parsePlaces(geo);
if (list) {
list.update(geo);
}
cfg.filtered = geo.features;
map.placesSelection = Utils.svgPlaces(map.g, geo, map.pathRaw, 1.25, cfg, selectedPlace);
});
function clickedLegend(d) {
map.root.selectAll('.' + d.key).style('display', d.off ? 'none' : null);
globe.root.selectAll('.' + d.key).style('display', d.off ? 'none' : null);
list.filter(legend.lookShapes);
if (!d.off) {
globe.update();
map.update();
}
}
function selectedPlace(d) {
list.selection(selected, d);
if (d === selected) {
d = null;
}
globe.selection = d;
if (d === null) {
globe.updateSelection();
}
info.update(d);
selected = d;
map.zoomTo(d, info.size);
}
function setIndex(i) {
var f = cfg.filtered;
var c = f.indexOf(selected);
c = c === -1 ? 0 : (c + i);
c = (c + f.length) % f.length;
if (list) {
list.selection(selected, f[c]);
}
info.update(f[c]);
globe.selection = f[c];
setTimeout(function () {
map.zoomTo(f[c], info.size);
}, 50);
selected = f[c];
}
})();
</script>
</body>
function HtmlInfo(root, cfg) {
'use strict';
var self;
var previous;
var a = root.append('a')
.style('font-size', (cfg.titleSize * 1.25) + 'px')
.style('line-height', 1)
.style('font-weight', 'bold')
.style('color', '#333')
.attr('href', 'http://bl.ocks.org/darosh/7b816a50e66bb62208a7')
.attr('target', '_blank')
.text('Planetary Grid');
root = root.append('div')
.style('display', 'none');
var b = root.append('b')
.style('display', 'block')
.style('font-size', cfg.titleSize + 'px');
var s = b.append('svg')
.attr('width', cfg.titleSize * 1.6)
.attr('height', cfg.titleSize * 1.6)
.style('float', 'left')
.style('margin-top', (-cfg.titleSize * 0.25) + 'px')
.style('margin-left', (-cfg.titleSize * 0.25) + 'px')
.style('margin-right', (cfg.titleSize * 0.25) + 'px')
.append('path')
.style('stroke-width', 2)
.attr('transform', 'translate(' + [cfg.titleSize * 1.6 / 2, cfg.titleSize * 1.6 / 2] + ')');
var t = b.append('span');
var c = root.append('small')
.style('display', 'block')
.style('text-align', 'right')
.style('margin-top', (cfg.titleSize / 4) + 'px')
.style('margin-bottom', (cfg.titleSize / 2) + 'px');
var d = root.append('a')
.style('display', 'block')
.attr('target', '_blank')
.text('Wikipedia');
var e = root.append('a')
.style('display', 'block')
.attr('target', '_blank')
.text('Google');
var f = root.append('a')
.style('display', 'block')
.attr('target', '_blank')
.text('Google Maps');
var g = root.append('a')
.style('display', 'block')
.attr('target', '_blank')
.text('Google Earth');
function update(feature) {
if (previous === feature) {
return;
}
previous = feature;
if (feature) {
t.text(feature.properties.name);
s
.attr('class', feature.coordinates ? 'legend-symbol ' + feature.type : 'symbol ' + feature.properties.description)
.attr('d', function () {
var s = cfg.sizes[feature.properties.description || 'place'] * cfg.titleSize / 6;
return d3.svg.symbol().size(s).type(cfg.symbols[feature.properties ? feature.properties.description : 'circle'])();
});
if (feature.type !== 'Feature') {
d.style('display', 'none');
e.style('display', 'none');
} else {
d.style('display', 'block');
e.style('display', 'block');
}
var coo = [feature.geometry.coordinates[1], feature.geometry.coordinates[0]];
coo[0] = d3.round(coo[0], 3);
coo[1] = d3.round(coo[1], 3);
c.text(d3.round(coo[0], 2) + ', ' + d3.round(coo[1], 2));
d.attr('href', 'https://wikipedia.org/wiki/Special:Search/' + feature.properties.name);
e.attr('href', 'https://www.google.com/search?q=' + feature.properties.name);
f.attr('href', 'https://www.google.com/maps/@' + coo[0] + ',' + coo[1] + ',12z');
g.attr('href', 'https://www.google.com/maps/@' + coo[0] + ',' + coo[1] + ',512m/data=!3m1!1e3');
a.style('display', 'none');
root.style('display', null);
self.size = root.node().getBoundingClientRect();
} else {
a.style('display', null);
root.style('display', 'none');
}
}
return self = {
update: update
};
}
Display the source blob
Display the rendered blob
Raw
{"type":"Topology","objects":{"land":{"type":"GeometryCollection","bbox":[-180,-90.00000000000003,180.00000000000014,83.64513000000002],"geometries":[{"type":"Polygon","arcs":[[0,1]]},{"type":"Polygon","arcs":[[2,3]]},{"type":"Polygon","arcs":[[4,-1,5,-3,6]]},{"type":"Polygon","arcs":[[7,8,9,10]]},{"type":"Polygon","arcs":[[11]]},{"type":"Polygon","arcs":[[12]]},{"type":"Polygon","arcs":[[13]]},{"type":"Polygon","arcs":[[14]]},{"type":"Polygon","arcs":[[15]]},{"type":"Polygon","arcs":[[16,17]]},{"type":"Polygon","arcs":[[18,19,20]]},{"type":"Polygon","arcs":[[21]]},{"type":"Polygon","arcs":[[22]]},{"type":"Polygon","arcs":[[23,24]]},{"type":"Polygon","arcs":[[25]]},{"type":"Polygon","arcs":[[26]]},{"type":"Polygon","arcs":[[27,28,29,30]]},{"type":"Polygon","arcs":[[31,-29,32]]},{"type":"Polygon","arcs":[[33,34]]},{"type":"Polygon","arcs":[[35]]},{"type":"Polygon","arcs":[[36]]},{"type":"Polygon","arcs":[[37,38,39,40]]},{"type":"Polygon","arcs":[[41,42]]},{"type":"Polygon","arcs":[[43,-40,44,45]]},{"type":"Polygon","arcs":[[46]]},{"type":"Polygon","arcs":[[47]]},{"type":"Polygon","arcs":[[48,49]]},{"type":"Polygon","arcs":[[50]]},{"type":"Polygon","arcs":[[51]]},{"type":"Polygon","arcs":[[52]]},{"type":"Polygon","arcs":[[53]]},{"type":"Polygon","arcs":[[54,55,56,57,58,59,60,61,62,-9,63,64,65,66,67,68,69,70,71,72,73,74,75]]},{"type":"Polygon","arcs":[[76,77,78,-74,79,80,-71,81,82,83]]},{"type":"Polygon","arcs":[[-77,84]]},{"type":"Polygon","arcs":[[85,86,87,88,89]]},{"type":"Polygon","arcs":[[90]]},{"type":"Polygon","arcs":[[91,92]]},{"type":"Polygon","arcs":[[93]]},{"type":"Polygon","arcs":[[94]]},{"type":"Polygon","arcs":[[95,96,97]]},{"type":"Polygon","arcs":[[-49,98,99,100,-42,101,102,103,104,105],[106]]},{"type":"Polygon","arcs":[[-98,107,108]]},{"type":"Polygon","arcs":[[109,110]]},{"type":"Polygon","arcs":[[-110,111]]},{"type":"Polygon","arcs":[[112]]},{"type":"Polygon","arcs":[[113,114,115,116,117,118,119]]},{"type":"Polygon","arcs":[[120]]}]}},"arcs":[[[56,25],[-2,0]],[[54,25],[2,0]],[[77,29],[0,-2]],[[77,27],[-4,-2],[2,4],[2,0]],[[42,23],[12,-3],[0,5]],[[56,25],[21,-2],[0,4]],[[77,29],[1,4],[4,3],[0,-3],[-3,-1],[3,-5],[0,-5],[-6,-4],[-5,-4],[14,-4],[5,1],[14,1],[-4,4],[9,4],[7,7],[11,0],[4,2],[8,0],[6,-2],[4,4],[3,-2],[11,6],[3,-3],[6,0],[1,-7],[3,4],[6,4],[12,0],[2,2],[23,-2],[7,0],[5,-2],[11,-4],[0,-4],[-4,-3],[-3,-8],[9,-5],[-219,0],[-7,2],[5,5],[-7,2],[7,4],[9,2],[10,1]],[[74,52],[0,0]],[[74,52],[1,0]],[[75,52],[2,2]],[[77,54],[2,-3],[-2,-2],[-3,3]],[[225,71],[1,0],[0,-4],[-1,1],[0,3]],[[245,70],[-3,-4],[0,-4],[-2,2],[5,6]],[[245,70],[0,9],[1,-4],[2,0],[-1,-4],[-2,-1]],[[159,110],[0,-7],[-1,-1],[0,-5],[-1,-4],[-2,0],[-1,4],[1,1],[0,8],[2,0],[1,5],[1,-1]],[[224,109],[1,-5],[3,-5],[2,-6],[0,-3],[1,-1],[-1,-3],[0,-4],[-1,0],[-1,-7],[-6,-1],[-3,8],[-1,-1],[-3,3],[-5,-2],[0,-2],[-2,1],[-3,-2],[0,5],[-2,5],[0,9],[6,4],[0,2],[1,3],[0,2],[5,1],[1,3],[3,-1],[-1,-4],[4,-4],[0,6],[1,2],[1,-3]],[[205,117],[-4,0],[-5,2],[2,2]],[[198,121],[3,-1],[4,-3]],[[226,120],[4,3]],[[230,123],[0,-1]],[[230,122],[-1,-2],[-3,0]],[[226,120],[0,-2],[3,-4],[-3,1],[0,2],[-2,1],[0,-3],[-5,2],[0,4],[0,2],[-3,0],[0,6],[2,-5],[1,2],[4,-2],[2,0],[0,-3],[1,-1]],[[210,131],[-1,-3],[0,-4],[-2,-3],[0,8],[1,2],[2,0]],[[198,121],[-3,2],[-2,9],[-4,4],[3,1],[2,-5],[1,0]],[[195,132],[1,-4],[2,-2],[0,-5]],[[206,132],[-1,-8],[-4,0],[-1,2],[0,6],[3,2],[0,2],[3,3],[0,-7]],[[210,142],[0,1],[2,-3],[-2,-3],[0,1],[0,4]],[[210,142],[-1,2]],[[209,144],[1,1]],[[210,145],[0,0]],[[210,145],[0,-3]],[[210,146],[0,-1]],[[209,144],[1,2]],[[210,147],[-1,1]],[[209,148],[-1,1],[0,7],[1,-1],[0,-5],[1,-3]],[[74,158],[3,-1],[0,-2],[-4,0],[1,3]],[[69,162],[4,-4],[-2,0],[-2,4]],[[218,178],[-2,-1]],[[216,177],[0,1]],[[216,178],[1,0]],[[217,178],[1,0]],[[135,184],[0,-1]],[[135,183],[0,1]],[[218,178],[-1,0]],[[216,178],[0,-1]],[[216,177],[0,3],[2,0],[1,3],[2,0],[1,4],[0,-8],[-4,-1]],[[224,191],[0,-2],[-2,1],[1,4],[1,-3]],[[85,203],[0,-3],[3,0],[0,-4],[-4,0],[1,7]],[[222,204],[0,1]],[[222,205],[2,0],[0,-5],[-1,-2],[-1,6]],[[120,204],[-2,-1],[1,5],[2,-1],[-1,-3]],[[122,213],[1,-4],[3,-6],[-3,-3],[-2,3],[1,3],[-2,6],[2,1]],[[114,224],[1,-2],[-3,-2],[-3,1],[5,3]],[[0,228],[6,-4],[-3,-3],[-3,3],[0,4]],[[66,229],[2,-4],[-3,-1],[-6,-8],[2,-5],[6,-4],[2,-5],[1,5],[2,2],[-2,4],[0,5]],[[70,218],[3,0],[4,-5],[3,1],[3,-6],[3,-2],[-1,-3]],[[85,203],[-2,-3],[-3,0]],[[80,200],[-1,-2],[1,-2]],[[80,196],[1,-1]],[[81,195],[2,0],[-4,-4],[1,3],[-4,-3],[0,-2],[-3,-2],[-1,-8],[-4,-5],[1,-4],[0,-5],[-2,3],[0,4],[-4,-1],[-3,1],[-3,-3],[0,-10],[1,-3],[2,-1],[2,2],[0,2],[2,1],[0,-5],[-1,-3],[4,-1],[0,-8],[5,-1],[0,2],[5,1],[0,-1],[5,0]],[[82,144],[0,-1]],[[82,143],[2,-4],[2,-2],[3,-1],[1,-5],[-1,-2],[2,0],[3,-3],[3,-2],[3,-2],[0,-7],[-2,-3],[0,-5],[-1,-3],[-1,-7],[-4,-2],[-1,-3],[0,-4],[-3,-5],[-1,-4],[-3,1],[1,-2],[0,-4],[-3,-1],[-3,-3],[2,-2],[-2,-1],[0,-6],[-2,-4],[0,-3]],[[77,54],[-2,-2]],[[74,52],[-2,3],[0,7],[1,1],[0,6],[1,3],[0,6],[1,2],[0,9],[1,3],[0,11],[-2,3],[-2,1],[0,3],[-2,4],[0,4],[-2,5],[1,1],[0,6],[2,3],[0,6],[-2,3],[0,-3],[-4,4],[-1,5],[-2,0],[-2,4],[-3,0],[-4,3],[-3,9],[-4,8],[1,-5],[2,-5],[-1,0],[-1,4],[-2,2],[1,2],[-2,2],[-2,6],[-1,0],[-2,6],[0,14]],[[39,198],[0,1]],[[39,199],[-1,1]],[[38,200],[-3,2]],[[35,202],[-3,7],[-5,6],[-5,1],[-4,-1],[0,-3]],[[18,212],[-7,-5],[5,6],[-5,0],[1,2],[-2,1]],[[10,216],[0,2],[2,2],[-4,2],[3,3],[-2,2],[4,4],[12,-1],[3,-2],[14,1],[2,-1]],[[44,228],[1,0]],[[45,228],[1,-1]],[[46,227],[4,1]],[[50,228],[0,0]],[[50,228],[4,-2],[5,1],[0,4]],[[59,231],[6,-5],[1,3]],[[50,234],[2,-1]],[[52,233],[2,-4]],[[54,229],[-4,-1]],[[50,228],[-4,-1]],[[46,227],[-1,1]],[[44,228],[-2,5]],[[42,233],[3,1]],[[45,234],[5,-3],[0,3]],[[50,234],[2,-1]],[[69,233],[1,0]],[[70,233],[2,0]],[[72,233],[6,-3],[4,-6],[-3,-6],[-4,0],[-2,4],[0,5]],[[73,227],[-7,2]],[[66,229],[-4,2],[1,4],[6,-2]],[[59,231],[-1,4],[4,0],[-3,-4]],[[45,234],[-3,-1]],[[42,233],[-5,-2],[4,5],[4,-2]],[[50,238],[-1,-2],[-7,1],[8,1]],[[164,230],[-4,1],[5,5],[-1,-6]],[[59,240],[1,-3]],[[60,237],[-2,3]],[[58,240],[1,0]],[[222,204],[0,-4],[-3,-5],[-2,-5],[-1,1],[-3,-4],[1,-8],[-2,-1],[0,5],[-2,3],[-4,-1],[1,-3],[2,1],[-2,-4],[2,-4],[0,-5],[-2,-4],[0,-2],[-5,-4],[-1,-2]],[[201,158],[-1,2],[-2,-1],[0,-4],[2,-4],[0,-5],[-4,-5],[-1,6],[-2,-2],[1,-6],[2,-2],[0,-4],[-1,-1]],[[195,132],[-1,6],[-2,3],[1,2],[0,5],[-1,1],[0,4],[-3,-1],[0,3],[-2,5],[-4,-3],[0,-2],[-3,-3],[0,-8],[-2,-3],[-1,1],[0,4],[-1,1],[-1,5],[0,8],[-2,-1],[0,2],[-2,2],[-1,3],[-4,-1],[-2,1],[0,2],[-2,-1],[-4,6],[0,-4],[2,-6],[3,3],[1,-3],[2,-1],[-2,-7],[-3,-4],[-1,0],[-4,-4],[-2,1],[0,6],[-2,4],[0,3],[-2,3],[0,3],[-2,4],[0,-5],[2,-5],[0,-5],[1,-3],[3,-5],[0,-3],[2,-1],[3,1],[0,-6],[-1,-4],[-3,-4],[-3,-7],[0,-12],[1,-1],[-1,-7],[-3,-2],[0,-9],[-2,0],[0,-5],[-2,-5],[-3,-3],[-1,1],[-4,-1],[0,5],[-2,4],[0,4],[-1,2],[0,4],[-1,2],[0,9],[1,1],[0,6],[-1,1],[0,4],[-2,2],[0,11],[-2,0],[-2,3],[-3,0],[0,-2],[-4,0],[-1,-1],[-3,4],[-1,4],[-2,3],[0,17],[1,1],[1,5],[3,3],[0,4],[2,2],[0,2],[3,0],[3,2],[6,0],[0,-5],[6,-5],[0,3],[2,1],[4,-3],[5,2],[0,6],[-4,0],[-2,2],[0,4],[6,2],[4,0],[-3,4],[2,3],[-8,-3],[0,-4],[-4,-3],[1,-5],[-2,1],[-1,3],[0,5],[-5,4],[1,-4],[3,-3],[-2,-4]],[[135,184],[0,3],[-2,0],[-2,6],[-7,-8],[-1,-3],[-5,0],[0,9],[3,0],[2,0],[1,4],[-3,4],[2,0],[7,7],[0,5],[2,-2]],[[132,209],[-1,-2],[8,1],[0,3],[5,5],[-5,0],[0,4],[3,2],[-1,2],[-5,-7],[0,-6],[-3,-3]],[[133,208],[0,1]],[[133,209],[-1,5],[-4,-1],[0,5],[4,4],[9,9],[9,-3],[3,-3],[-4,-1],[0,-3],[6,3],[0,3],[9,0],[2,2],[6,-2],[0,7],[3,-3],[10,4],[2,3],[8,2],[8,-3],[-3,-2],[12,0],[2,-4],[5,0],[3,3],[13,-5],[7,1],[-242,-2]],[[0,228],[249,-10],[-4,0],[-3,-3],[-5,-1],[0,-5],[-4,-7],[-1,7],[4,7],[-1,2],[-6,-5],[-6,1],[-5,-6],[4,-3]],[[158,187],[0,-3],[2,-2],[2,0],[-2,9],[1,3],[-1,2],[-3,-1],[1,-8]],[[58,240],[0,0]],[[58,240],[1,0]],[[47,240],[1,0]],[[48,240],[-1,0]],[[47,240],[1,0]],[[137,243],[-1,-4],[-4,3],[5,1]],[[78,244],[-6,-1],[-1,-4],[-6,-1],[-2,2]],[[63,240],[1,2]],[[64,242],[1,1]],[[65,243],[-1,1]],[[64,244],[-1,0]],[[63,244],[-2,2]],[[61,246],[21,2],[-4,-4]],[[78,244],[10,2],[10,3],[18,-3],[-5,-3],[0,-7],[-4,-8],[-11,-6],[-2,-7],[-3,1],[-3,5],[-1,4],[0,8],[-5,5],[-5,0],[-3,4],[4,2]]],"transform":{"scale":[1.4457831325301205,0.69737],"translate":[-180,-90]}}
function SvgLegend(root, cfg, clicked) {
'use strict';
var shapes = cfg.symbols;
var data = d3.map(shapes).entries().filter(function (d) {
return d.key !== 'undefined'
});
data.forEach(function (v) {
v.classed = 'symbol ' + v.key;
v.symbol = true;
});
data = data.concat([
{key: 'cool-line', value: 'circle', path: 'M-10,0 L10,0'},
{key: 'hot-line', value: 'circle', path: 'M-10,0 L10,0'},
{key: 'balanced-line', value: 'circle', path: 'M-10,0 L10,0'},
{key: 'cool-point', value: 'circle', classed: 'cool-point', off: true},
{key: 'hot-point', value: 'circle', classed: 'hot-point', off: true},
{key: 'balanced-point', value: 'circle', classed: 'balanced-point', off: true},
{key: 'graticule', value: 'circle', path: 'M-8.25,0 L8.25,0', off: true},
{key: 'map', value: 'square', classed: 'map'}
]);
var l = root.selectAll('legend').data(data);
var g = l.enter().append('g')
.attr('class', 'legend')
.attr('transform', function (d, i) {
return 'translate(' + [0, i * cfg.lineHeight] + ')';
})
.style('opacity', function (d) {
return d.off ? 0.25 : null;
})
.on('click', function (d) {
d.off = !d.off;
d3.select(this).style('opacity', d.off ? 0.25 : null);
clicked(d);
});
g.append('path')
.attr('class', function (d) {
return d.classed || d.key;
})
.style('stroke-width', function (d) {
return (d.key === 'map') ? 1.5 : ((d.path || d.classed) && !d.symbol) ? 2 : 1;
})
.attr('transform', 'translate(' + [cfg.fontSize / 2, cfg.lineMid] + ')')
.attr('d', function (d) {
return d.path || d3.svg.symbol().size(cfg.sizes[d.key]).type(d.value)();
});
g.append('text')
.attr('dy', cfg.fontSize)
.attr('dx', cfg.fontSize + cfg.lineMid)
.text(function (d) {
return d.key.replace('-', ' ');
});
var lookShapes = {};
var lookFilter = {};
data.forEach(function (d) {
lookFilter[d.key] = d;
if (shapes[d.key]) {
lookShapes[d.key] = d;
}
});
return {
data: data,
lookShapes: lookShapes,
lookFilter: lookFilter
};
}
function SvgList(root, cfg, width, minItemWidth, updated, clicked) {
'use strict';
var self;
var shapes = cfg.symbols;
var cols = Math.floor(width / minItemWidth);
var itemWidth = Math.floor((width + cfg.fontSize) / cols);
var data;
var previousData = [];
function selection(o, n) {
root.selectAll('g').data(o ? [o, n] : [n], function (d) {
return d && d.properties ? d.properties.id : null;
})
.style('font-weight', function (d) {
return ((d === n) && (n !== o)) ? 'bold' : null;
})
.selectAll('text')
.each(wrap);
}
function update(topo) {
data = topo.features;
self.filtered = data;
var lastRow = Math.ceil(data.length / cols);
var height = lastRow * cfg.lineHeight;
updated(height);
enter(data, previousData);
previousData = data;
}
function filter(l) {
var filtered = data.filter(function (d) {
var t = d.properties.description;
return !l[t].off;
});
enter(filtered, previousData);
previousData = filtered;
cfg.filtered = filtered;
}
function enter(filtered, previousData) {
var lastRow = Math.ceil(filtered.length / cols);
var g = root.selectAll('g').data(filtered, function (d) {
return d.properties.id;
});
g.exit().remove();
g.transition().attr('transform', function (d, i) {
var row = i % lastRow;
var col = (i - row) / lastRow;
return 'translate(' + [col * itemWidth, row * cfg.lineHeight] + ')';
});
var a = g.enter().append('g')
.attr('class', 'item')
.style('opacity', previousData.length ? 0 : 1)
.attr('transform', function (d, i) {
var row = i % lastRow;
var col = (i - row) / lastRow;
return 'translate(' + [col * itemWidth, row * cfg.lineHeight] + ')';
})
.on('click', clicked);
a.transition().delay(previousData.length ? 250 : 0)
.style('opacity', 1);
a.append('path')
.attr('class', function (d) {
return 'symbol ' + d.properties.description;
})
.attr('transform', 'translate(' + [cfg.fontSize / 2, cfg.lineMid] + ')')
.attr('d', function (d) {
var s = cfg.sizes[d.properties.description];
return d3.svg.symbol().size(s).type(shapes[d.properties.description])();
});
a.append('text')
.attr('dy', cfg.fontSize)
.attr('dx', cfg.fontSize + cfg.lineMid)
.text(function (d) {
return d.properties.name;
})
.each(wrap);
}
function wrap() {
var self = d3.select(this);
var text = self.data()[0].properties.name;
self.text(text);
var textLength = self.node().getComputedTextLength();
while (textLength > (itemWidth - 50) && text.length > 0) {
text = text.slice(0, -1);
self.text(text + '…');
textLength = self.node().getComputedTextLength();
}
self.text(self.text().replace(' …', '…'));
}
self = {
update: update,
filter: filter,
selection: selection
};
return self;
}
function SvgMap(svg, width, height, margin, cfg) {
'use strict';
var maxScale = 3;
var self;
var focused;
var arrowStart;
var prevScale;
var referenceSize = Math.sqrt(height * height + width * width) * cfg.durationScale;
var clip = d3.geo.clipExtent().extent([[-width / 2, -height / 2], [width / 2, height / 2]]);
var projection = d3.geo.mercator()
.translate([0, 0])
.precision(0)
.scale(width / 2 / Math.PI);
var simplify = d3.geo.transform({
point: function (x, y, z) {
if (z >= projectionSimplified.area) {
this.stream.point(~~(x * width), ~~(y * width));
}
}
});
var round = d3.geo.transform({
point: function (x, y) {
this.stream.point(~~(x * 10) / 10, ~~(y * 10) / 10);
}
});
var projectionRounded = {
stream: function (s) {
return projection.stream(round.stream(s));
},
baseArea: 4e-3 / width
};
var projectionLinesRounded = {
stream: function (s) {
return projectionLines.stream(round.stream(s));
},
baseArea: 4e-3 / width
};
var projectionSimplified = {
stream: function (s) {
return simplify.stream(clip.stream(s));
},
baseArea: 4e-3 / width
};
projectionSimplified.area = projectionSimplified.baseArea;
var projectionLines = d3.geo.mercator()
.rotate([cfg.shift, 0, 0])
.translate([0, 0])
.precision(1)
.scale(width / 2 / Math.PI);
var path = d3.geo.path()
.projection(projectionSimplified);
var pathRaw = d3.geo.path()
.projection(projection);
var pathRawRounded = d3.geo.path()
.projection(projectionRounded);
var pathLines = d3.geo.path()
.projection(projectionLines);
var pathLinesRounded = d3.geo.path()
.projection(projectionLinesRounded);
var zoom = d3.behavior.zoom()
.scaleExtent([1, maxScale])
.on('zoom', zoomed);
var defs = svg.append('defs');
defs.append('clipPath')
.attr('id', 'clip-map')
.append('rect')
.attr("x", -width / 2)
.attr("y", -height / 2)
.attr("width", width)
.attr("height", height);
defs.append('clipPath')
.attr('id', 'clip-arrow')
.append('rect')
.attr("x", margin)
.attr("y", margin)
.attr("width", width)
.attr("height", height);
var clipGroup = svg.append("g")
.attr("transform", "translate(" + [width / 2 + margin, height / 2 + margin] + ")")
.style('clip-path', 'url(#clip-map)')
.call(zoom);
clipGroup.append("rect")
.attr("class", "map water")
.attr("x", -width / 2)
.attr("y", -height / 2)
.attr("width", width)
.attr("height", height);
clipGroup.append("rect")
.attr("class", "overlay")
.attr("x", -width / 2)
.attr("y", -height / 2)
.attr("width", width)
.attr("height", height);
var g = clipGroup.append('g');
var graticulePath = g.append('path')
.datum(d3.geo.graticule()())
.attr('class', 'graticule')
.style('display', 'none')
.attr('d', pathRaw);
var land = g.append('path').attr('class', 'map land');
var countries = g.append('path').attr('class', 'map country');
var h = d3.geo.hexakisIcosahedron;
var coolLines = Utils.svgLines(g, pathLines, h.icosahedronEdges(), 'cool-line');
var hotLines = Utils.svgLines(g, pathLines, h.hexakisCenterEdges(), 'hot-line');
var balancedLines = Utils.svgLines(g, pathLines, h.hexakisSideEdges(), 'balanced-line');
var coolPointsData = Utils.pointsToFeatures(h.icosahedronPoints(), 'cool-point', 'Cool point', cfg.shift);
var hotPointsData = Utils.pointsToFeatures(h.hexakisCenterPoints(), 'hot-point', 'Hot point', cfg.shift);
var balancedPointsData = Utils.pointsToFeatures(h.hexakisCrossPoints(), 'balanced-point', 'Balanced point', cfg.shift);
Utils.svgPoints(g, coolPointsData, 'cool-point', projectionLines, clickedPoint, 'none');
Utils.svgPoints(g, hotPointsData, 'hot-point', projectionLines, clickedPoint, 'none');
Utils.svgPoints(g, balancedPointsData, 'balanced-point', projectionLines, clickedPoint, 'none');
function clickedPoint(d) {
self.clickedPoint(d);
}
var placesGroup = g.append('g');
var selectedCircleGroup = svg.append('g')
.style('display', 'none')
.style('clip-path', 'url(#clip-arrow)');
var selectedCircle = selectedCircleGroup.append('circle')
.attr('cx', margin)
.attr('cy', margin)
.attr('r', 20)
.attr('class', 'border');
var selectedArrow = selectedCircleGroup.append('line')
.attr('x1', margin * 4)
.attr('y1', margin * 4)
.attr('class', 'border');
svg.append("rect")
.attr("class", "border")
.style('stroke-width', cfg.frameLineWidth)
.attr("transform", "translate(" + [width / 2 + margin, height / 2 + margin] + ")")
.attr("x", -width / 2 + cfg.frameLineWidth / 2)
.attr("y", -height / 2 + cfg.frameLineWidth / 2)
.attr("width", width - cfg.frameLineWidth)
.attr("height", height - cfg.frameLineWidth);
function getFixedZoom(t, s) {
var S = (width - height) / 2;
t[0] = Math.min(width / 2 * (s - 1), Math.max(width / 2 * (1 - s), t[0]));
t[1] = Math.min(height / 2 * (s - 1) + S * s, Math.max(height / 2 * (1 - s) - S * s, t[1]));
}
function fixZoom() {
var t = zoom.translate();
var s = zoom.scale();
getFixedZoom(t, s);
zoom.translate(t);
}
function roundTranslate(t) {
t[0] = Math.round(t[0]);
t[1] = Math.round(t[1]);
}
function zoomed() {
fixZoom();
var t = zoom.translate();
var s = zoom.scale();
var i = projection.invert([t[0] / s, t[1] / s]);
update();
if (self.onZoomed) {
self.onZoomed(t, s, i);
}
}
function update(running) {
var t = zoom.translate();
var s = Math.min(maxScale, d3.round(zoom.scale(), 6));
roundTranslate(t);
g.attr('transform', 'translate(' + t + ')scale(' + s + ')');
var ps = (running === true) ? 1 : zoom.scale();
var c = translateToCenter(t, s);
var ce = [[
-width / 2 + c[0] - width / 2 / s,
-height / 2 + c[1] - height / 2 / s], [
-width / 2 + c[0] + width / 2 / s,
-height / 2 + c[1] + height / 2 / s]];
clip.extent(ce);
projectionLines.precision(running ? 1 : Math.sqrt(1 / 2) / s / s);
projectionSimplified.area = projectionSimplified.baseArea / ps / ps;
projection.clipExtent(ce);
projectionLines.clipExtent(ce);
var localPathRaw, localPathLines;
if (running) {
localPathRaw = pathRawRounded;
localPathLines = pathLinesRounded;
} else {
localPathRaw = pathRaw;
localPathLines = pathLines;
}
if (!cfg.filter['graticule'].off) {
graticulePath.attr('d', localPathRaw);
}
if (!cfg.filter['cool-line'].off) {
coolLines.attr('d', localPathLines);
}
if (!cfg.filter['hot-line'].off) {
hotLines.attr('d', localPathLines);
}
if (!cfg.filter['balanced-line'].off) {
balancedLines.attr('d', localPathLines);
}
if (!cfg.filter.map.off) {
land.attr('d', path);
countries.attr('d', path);
}
if (prevScale !== s) {
g.style('stroke-width', 1 / s);
if (!cfg.filter['graticule'].off) {
graticulePath.style('stroke-dasharray', (2 / s ) + ',' + (3 / s));
}
//self.placesSelection.attr('transform', function (d) {
// return d.translate + 'scale(' + 1 / s + ')';
//});
self.placesSelection.defs.attr('transform', function () {
return 'scale(' + 1 / s + ')';
});
prevScale = s;
}
if (focused) {
var f = [width / 2 + focused[0] * s + t[0], height / 2 + focused[1] * s + t[1]];
var l = [[arrowStart.width / 2 + 2 * margin, arrowStart.height / 2 + 2 * margin], [f[0] + margin, f[1] + margin]];
var d = Math.sqrt(Math.pow(l[1][0] - l[0][0], 2) + Math.pow(l[1][1] - l[0][1], 2));
var r = (d - 20) / d;
l[1][0] = l[0][0] + r * (l[1][0] - l[0][0]);
l[1][1] = l[0][1] + r * (l[1][1] - l[0][1]);
selectedCircle
.attr('transform', 'translate(' + [d3.round(f[0]), d3.round(f[1])] + ')');
selectedArrow
.attr('x1', l[0][0])
.attr('y1', l[0][1])
.attr('x2', l[1][0])
.attr('y2', l[1][1]);
selectedCircleGroup.style('display', null);
} else {
selectedCircleGroup.style('display', 'none');
}
}
function setZoom(t, s, i) {
var p = projection(i);
zoom.scale(s);
zoom.translate([p[0] * s, p[1] * s]);
fixZoom();
update();
}
function translateToCenter(t, s) {
return [-t[0] / s + width / 2, -t[1] / s + height / 2];
}
function centerToTranslate(c, s) {
return [s * (-c[0] + width / 2), s * (-c[1] + height / 2)];
}
function zoomTransition(p, toScale) {
var fromScale = zoom.scale();
var fromTranslate = zoom.translate();
var toTranslate = [-p[0] * toScale, -p[1] * toScale];
getFixedZoom(toTranslate, toScale);
var from = translateToCenter(fromTranslate, fromScale);
from[2] = referenceSize / fromScale;
var to = translateToCenter(toTranslate, toScale);
to[2] = referenceSize / toScale;
var zi = d3.interpolateZoom(from, to);
var dur = Math.min(cfg.durationMax, Math.max(cfg.durationMin, zi.duration * cfg.durationSpeed));
d3.transition().duration(dur).tween('tween', tween);
function tween() {
return function (t) {
var z = zi(t);
var s = referenceSize / z[2];
var tr = centerToTranslate(z, s);
getFixedZoom(tr, s);
zoom.translate(tr);
zoom.scale(s);
update(t < 1);
if (self.onZoomed) {
var i = projection.invert([tr[0] / s, tr[1] / s]);
self.onZoomed(z, s, i, t < 1);
}
};
}
}
function zoomTo(d, ast) {
if (!d) {
focused = null;
selectedCircleGroup.style('display', 'none');
return;
}
var c = d.geometry ? [d.geometry.coordinates[0], d.geometry.coordinates[1]] : [d[0] + cfg.shift, d[1]];
var p = projection(c);
arrowStart = ast;
focused = p;
zoomTransition(p, maxScale)
}
function reset() {
zoomTransition(projection([0, 0]), 1);
}
self = {
root: svg,
land: land,
countries: countries,
path: path,
pathRaw: pathRaw,
g: placesGroup,
projection: projection,
setZoom: setZoom,
zoomTo: zoomTo,
reset: reset,
update: update
};
return self;
}
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
body {
margin: 0;
padding: 0;
font-family: Arial, Helvetica, sans-serif;
font-size: 16px;
line-height: 19px;
text-rendering: optimizeLegibility;
color: rgba(0,0,0,0.87);
}
svg, canvas {
display: block;
}
a {
text-decoration: none;
color: #1f78b4;
}
a:hover {
text-decoration: underline;
color: #e31a1c;
}
a:visited {
color: #333;
}
small {
color: rgba(0,0,0,0.64);
}
.no-select {
user-select: none;
}
.point {
pointer-events: all;
cursor: pointer;
}
.water {
fill: #def4ff;
}
.border {
fill: none;
stroke-width: 2.5;
stroke: #444;
stroke-opacity: 1;
}
.overlay {
fill: none;
pointer-events: all;
}
.overlay-white {
fill: #fff;
pointer-events: all;
}
.country {
stroke: #000;
stroke-opacity: .33;
fill: none;
}
.land {
fill: rgba(255, 255, 255, 0.87);
stroke: 0;
}
.graticule {
fill: none;
stroke: #bbb;
stroke-opacity: 0.66;
}
.cool-point {
fill: none;
stroke: #1f78b4;
stroke-opacity: 0.85;
}
.hot-point {
fill: none;
stroke: #e31a1c;
stroke-opacity: 0.86;
}
.balanced-point {
fill: none;
stroke: #333;
stroke-opacity: 0.85;
}
.cool-line {
fill: none;
stroke: #1f78b4;
stroke-opacity: .85;
}
.hot-line {
fill: none;
stroke: #e31a1c;
stroke-opacity: .85;
}
.balanced-line {
fill: none;
stroke: #333;
stroke-opacity: .85;
}
.symbol {
stroke-width: 1;
stroke: #000;
cursor: pointer;
}
.place {
fill: #888;
fill-opacity: 0.33;
}
.pyramid {
fill: #ffff4d;
}
.megalith {
fill: #299ae6;
}
.temple {
fill: #ff7f00;
}
.mound {
fill: #90de43;
}
.volcano {
fill: #e31a1c;
}
.graticule {
stroke-dasharray: 2, 3;
}
.legend {
cursor: pointer;
pointer-events: all;
}
.item {
cursor: pointer;
}
.control {
cursor: pointer;
}
.legend-symbol {
stroke-width: 2;
}
.legend .map {
fill: #def4ff;
stroke: #333;
}
var Utils = (function () {
'use strict';
function parsePlaces(geo) {
geo.features.sort(function (a, b) {
return a.properties.name.localeCompare(b.properties.name);
});
geo.features.forEach(function (v, k) {
v.properties.id = k;
v.properties.description = v.properties.description || 'place';
});
}
function pointsToFeatures(points, type, name, shift) {
return points.coordinates.map(function (p) {
var sh = p[0] + shift;
sh = (sh > 180) ? (sh - 360) : sh;
return {
coordinates: p,
geometry: {
coordinates: [sh, p[1]],
type: 'Point'
},
type: type,
properties: {
name: name
}
}
});
}
function trans(path) {
return function (d) {
var p = path.centroid(d);
if (isNaN(p[0]) || isNaN(p[1])) {
p[0] = -1e10;
p[1] = -1e10;
}
return d.translate = 'translate(' + p + ')';
};
}
function addSymbols(root, cfg, scale) {
var g = root.append('defs');
d3.keys(cfg.symbols).forEach(function (d) {
g.append('path')
.attr('id', d)
.attr('class', 'symbol ' + d)
.attr('d', d3.svg.symbol()
.size(scale * scale * cfg.sizes[d])
.type(cfg.symbols[d])());
});
return g.selectAll('path');
}
function svgPlaces(root, geo, t, scale, cfg, clicked) {
t = trans(t);
var defs = addSymbols(root, cfg, scale);
var places = root.selectAll()
.data(geo.features)
.enter()
.append('use')
.attr('transform', t)
.attr('xlink:href', function (d) {
return '#' + d.properties.description;
})
.on('click', clicked);
return {
defs: defs,
places: places
}
}
function _svgPlaces(root, geo, t, scale, cfg, clicked) {
t = trans(t);
return root.selectAll()
.data(geo.features)
.enter()
.append('path')
.attr('transform', t)
.attr('class', function (d) {
return 'symbol ' + d.properties.description;
})
.attr('d', function (d) {
return d3.svg.symbol()
.size(scale * cfg.sizes[d.properties.description])
.type(cfg.symbols[d.properties.description])();
})
.on('click', clicked);
}
function svgLines(root, path, data, type) {
return root.append('path')
.datum(data)
.attr('class', 'line ' + type)
.attr('d', path);
}
function svgPoints(root, points, type, projection, clicked, display) {
points = points.filter(function (d) {
var p = projection(d.coordinates);
if (Math.abs(p[0]) !== Infinity && Math.abs(p[1]) !== Infinity) {
d.projected = p;
return true;
}
});
var p = root.selectAll('.point.' + type).data(points);
p.enter().append('circle')
.attr('class', 'point ' + type)
.style('display', display)
.attr('r', 5)
.attr('transform', function (d) {
return 'translate(' + d.projected + ')';
})
.on('click', clicked);
}
function svgControls(root, setIndex, reset) {
root.append('path')
.attr('class', 'control')
.attr('d', d3.svg.symbol().size(120).type('triangle-up'))
.attr('transform', 'translate(60,10)rotate(90)')
.on('click', function () {
setIndex(+1);
});
root.append('path')
.attr('class', 'control')
.attr('d', d3.svg.symbol().size(120).type('circle'))
.attr('transform', 'translate(35,10)')
.on('click', reset);
root.append('path')
.attr('class', 'control')
.attr('d', d3.svg.symbol().size(120).type('triangle-up'))
.attr('transform', 'translate(10,10)rotate(-90)')
.on('click', function () {
setIndex(-1);
});
}
return {
svgLines: svgLines,
svgPoints: svgPoints,
svgPlaces: svgPlaces,
svgControls: svgControls,
parsePlaces: parsePlaces,
pointsToFeatures: pointsToFeatures
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment