Skip to content

Instantly share code, notes, and snippets.

@erohinaelena
Last active February 8, 2016 19:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erohinaelena/dbf9a45164f7ce4619fb to your computer and use it in GitHub Desktop.
Save erohinaelena/dbf9a45164f7ce4619fb to your computer and use it in GitHub Desktop.
<html>
<head>
<meta charset="utf-8">
<link href="stars.css" rel="stylesheet">
</head>
<body>
<canvas></canvas>
<svg></svg>
<image class="landscape" src="welkin-080216-landscape-glow.png"></image>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>d3.select(self.frameElement).style("height", "600px")</script>
<script src="stars.js"></script>
</body>
</html>
body {
background: #113;
margin: 0;
}
svg {
position: absolute;
top: 0;
left: 0;
}
.globe-graticule {
stroke: #0D434F;
fill: none;
}
.globe-city {
fill: #0D434F;
}
.globe-names {
fill: #fff;
alignment-baseline: middle;
}
.landscape {
width: 100%;
position: absolute;
bottom: 0;
left: 0;
}
var width = window.innerWidth - 10,
height = window.innerHeight - 40;
var projection = d3.geo.stereographic()
.translate([width / 2, height])
.scale(380);
var fixedProjection = d3.geo.stereographic()
.scale(380)
.translate([width / 2, height])
.rotate([0, 0]);
var canvas = d3.select("canvas")
.attr("width", width)
.attr("height", height);
var c = canvas.node().getContext("2d");
var cities = {
Murmansk: {
coordinates: [33.10, 68.95],
name: 'Мурманск'
},
Moscow: {
coordinates:[37.50, 55.75],
name: 'Москва'
},
Anapa: {
coordinates: [37.33, 44.89],
name: 'Анапа'
},
Mecca: {
coordinates: [39.81, 21.43],
name: 'Мекка'
},
Nairobi: {
coordinates: [36.82, -1.29],
name: 'Найроби'
},
Johannesburg: {
coordinates:[28.04, -26.19],
name: 'Йоханнесбург'
}
};
var currentLat = cities['Moscow'].coordinates[1];
function getRetinaRatio() {
var devicePixelRatio = window.devicePixelRatio || 1;
var backingStoreRatio = c.webkitBackingStorePixelRatio ||
c.mozBackingStorePixelRatio ||
c.msBackingStorePixelRatio ||
c.oBackingStorePixelRatio ||
c.backingStorePixelRatio || 1;
return devicePixelRatio / backingStoreRatio
}
var ratio = getRetinaRatio();
var scaledWidth = width * ratio;
var scaledHeight = height * ratio;
canvas.node().width = scaledWidth;
canvas.node().height = scaledHeight;
canvas
.style("width", width + 'px')
.style("height", height + 'px');
c.scale(ratio, ratio);
var path = d3.geo.path()
.projection(projection)
.context(c);
var fixedPath = d3.geo.path()
.projection(fixedProjection)
.context(c);
var graticule = d3.geo.graticule()
.step([15, 15]);
var bgRGB = d3.rgb('#113');
var bgColor = ['#113', '#113'];
var colorScale = [
d3.scale.linear()
.domain([10, 3, -3, -10]) //высота Солнца над горизонтом в градусах при восходе
.range([
["#2E87E8", "#2E87E8"],
["#6767c8", "#F39217"],
["#6767c8", "#6767c8"],
["#113", "#113"]
])
.clamp(true),
d3.scale.linear()
.domain([-10, -3, 3, 10]) //при закате
.range([
["#113", "#113"],
["#6890B1", "#6890B1"],
["#6890B1","#D49A83"],
["#2E87E8", "#2E87E8"]
])
.clamp(true)
];
var geoConstellations = [];
d3.json("/erohinaelena/raw/ec635d68e8bf55586d40/starData.json", function(error, data) {
var starsMag = [];
data = data.map(function(constellation) {
constellation.stars = constellation.stars.filter(function(star) {
if (star.mag < 6) starsMag.push(star.mag);
return star.mag < 6
});
return constellation
});
var minMaxMag = d3.extent(starsMag);
var opacityScale = d3.scale.linear()
.domain(minMaxMag)
.range([1, 0.4]);
var magScale = d3.scale.linear()
.domain(minMaxMag)
.range([2.7, 1.7]);
data.forEach(function (constellation) {
var geometries = [];
constellation.stars.map(function (star) {
var rgb = d3.rgb(star.color);
var rgba = 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + opacityScale(star.mag) + ')';
geometries.push({
type: 'Point',
coordinates: [-star.ra, star.dec],
properties: {
color: rgba,
mag: magScale(star.mag)
}
})
});
var lines = constellation.lines.map(function (line) {
var p1 = [-line.ra1, line.dec1];
var p2 = [-line.ra2, line.dec2];
return [p1, p2]
});
geometries.push({
type: "MultiLineString",
coordinates: lines
});
geometries = {
type: 'GeometryCollection',
geometries: geometries
};
var geoConstellation = {
type: 'Feature',
geometry: geometries,
properties: {
name: constellation.name,
zodiac: constellation.zodiac,
center: d3.geo.centroid(geometries)
}
};
geoConstellations.push(geoConstellation)
});
draw(geoConstellations, [180, 90 - currentLat]);
var raStart, decStart;
function getStart() {
raStart = projection.invert(d3.mouse(this))[0];
decStart = fixedProjection.invert(d3.mouse(this))[1]
}
function move() {
var raFinish = projection.invert(d3.mouse(this))[0];
var decFinish = fixedProjection.invert(d3.mouse(this))[1];
var raRotate = raFinish - raStart;
var decRotate = decFinish - decStart;
var rotate = projection.rotate();
var newCenter = [rotate[0] + raRotate, 90 - currentLat];
draw(geoConstellations, newCenter);
decStart = fixedProjection.invert(d3.mouse(this))[1]
}
var drag = d3.behavior.drag()
.on("dragstart", getStart)
.on("drag", move);
canvas.call(drag)
});
var bgScale = d3.scale.linear()
.domain([0, height])
.range(bgColor);
function makeRadialGradient(geo) {
var x = projection(geo.coordinates)[0];
var y = projection(geo.coordinates)[1];
var r = geo.properties.mag;
var color = geo.properties.color;
var radialgradient = c.createRadialGradient(x, y, 0, x, y, r);
bgRGB = d3.rgb(bgScale(y));
radialgradient.addColorStop(0.2, color);
radialgradient.addColorStop(0.5,'rgba(' + bgRGB.r + ',' + bgRGB.g + ',' + bgRGB.b + ',0)');
radialgradient.addColorStop(0.5,'rgba(' + bgRGB.r + ',' + bgRGB.g + ',' + bgRGB.b + ',1)');
radialgradient.addColorStop(1,'rgba(' + bgRGB.r + ',' + bgRGB.g + ',' + bgRGB.b + ',0)');
c.fillStyle = radialgradient
}
function distance(p) {
var center = [width / 2, height / 2];
var xRotate = center[0] - p[0];
var yRotate = center[1] - p[1];
return Math.sqrt(Math.pow(xRotate, 2) + Math.pow(yRotate, 2))
}
function draw(constellations, center) {
var min = 0,
minDistance = distance(projection(constellations[0].properties.center));
if (center) projection.rotate(center);
c.clearRect(0, 0, width, height);
c.strokeStyle = "#fff";
c.lineWidth = .1;
c.beginPath(), path(graticule()), c.stroke();
c.lineWidth = .4;
c.beginPath(), path({type: "LineString", coordinates: [[-180, 0], [-90, 0], [0, 0], [90, 0], [180, 0]]}), c.stroke();
c.strokeStyle = "#f00";
c.beginPath(), fixedPath({type: "LineString", coordinates: [[-180, 0], [-90, 0], [0, 0], [90, 0], [180, 0]]}), c.stroke();
c.strokeStyle = "#f2f237";
c.beginPath(), path({type: "LineString", coordinates: [[-180, 0], [-90, 23.26], [0, 0], [90, -23.26], [180, 0]]}), c.stroke();
var sunScale = d3.scale.linear()
.domain([0, 365 / 4, 365 / 2, 3 * 365 / 4, 365])
.range([[-180, 0], [-90, 23.26], [0, 0], [90, -23.26], [180, 0]]);
var sunCoordinates = sunScale(90);
var sunPx = projection(sunCoordinates);
var fixedSunCoord = fixedProjection.invert(sunPx);
var left = (fixedSunCoord[0] < 0) * 1;
bgColor = colorScale[left](fixedSunCoord[1]);
bgScale.range(bgColor);
d3.select('body').attr('style', 'background: -webkit-gradient(linear, left top, left bottom, from(' +
bgColor[0] + '), to('+ bgColor[1] +'))' + ';');
c.strokeStyle = "#fff";
var sunLat = sunCoordinates[1];
function drawSunPath() {
var sunPath = d3.range(-180, 185, 5).map(function (deg) {
return [deg, sunLat]
});
c.beginPath(), path({type: "LineString", coordinates: sunPath}), c.stroke();
}
c.setLineDash([5]);
Object.keys(cities).forEach(function(city) {
projection.rotate([0, 90 - cities[city].coordinates[1]]);
drawSunPath();
});
c.setLineDash([]);
projection.rotate(center);
constellations.forEach(function(constellation, i) {
var currentDistance = distance(projection(constellations[i].properties.center));
if (currentDistance < minDistance) {
min = i;
minDistance = currentDistance
}
constellation.geometry.geometries.forEach(function(geo) {
if (geo.type == 'Point') {
makeRadialGradient(geo);
path.pointRadius([geo.properties.mag]);
c.beginPath(), path(geo), c.fill();
} else if (geo.type == 'MultiLineString') {
c.strokeStyle = (constellation.properties.zodiac)? '#f2f237':"#999";
c.beginPath(), path(geo), c.stroke();
}
})
});
c.fillStyle = "#f2f237";
var sunGeo = {
type: "Point",
coordinates: sunCoordinates,
properties: {
mag: 70,
color: '#fff'
}
};
makeRadialGradient(sunGeo);
path.pointRadius([70]);
c.beginPath(), path(sunGeo), c.fill();
}
var svg = d3.select('svg')
.attr('width', width / 6)
.attr('height', width / 6);
var globeProjection = d3.geo.orthographic()
.translate([svg.attr('width') / 2, svg.attr('width') / 2])
.scale(100)
.rotate([-75, -30])
.clipAngle(98);
globePath = d3.geo.path()
.projection(globeProjection);
var g = svg.append("g");
g.append("path")
.datum(graticule)
.attr("class", "globe-graticule")
.attr("d", globePath);
g.selectAll('circle')
.data(Object.keys(cities))
.enter()
.append('circle')
.attr('cx', function(d) {
return globeProjection(cities[d].coordinates)[0]
})
.attr('cy', function(d) {
return globeProjection(cities[d].coordinates)[1]
})
.attr('r', 3)
.attr('class', 'globe-city');
g.selectAll('text')
.data(Object.keys(cities))
.enter()
.append('text')
.text(function(d){return cities[d].name})
.attr('x', function(d) {
return globeProjection(cities[d].coordinates)[0] + 5
})
.attr('y', function(d) {
return globeProjection(cities[d].coordinates)[1]
})
.attr('class', 'globe-names')
.on('click', function(d) {
currentLat = cities[d].coordinates[1];
draw(geoConstellations, [180, 90 - currentLat]);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment