block by devgru 05d123632bc0c4e39a12

05d123632bc0c4e39a12

Full Screen

index.html

<html>
<head>
    <meta charset="utf-8">
    <link href="stars.css" rel="stylesheet">
</head>
<body>
<h1></h1>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="stars.js"></script>
</body>
</html>

18b0ebf01dac2d1e5922.iml

<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
  <component name="NewModuleRootManager" inherit-compiler-output="true">
    <exclude-output />
    <content url="file://$MODULE_DIR$" />
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
  </component>
</module>

stars.coffee

http = require 'http'
fs = require 'fs'
async = require 'async'
_ = require 'underscore'

httpGet = (host,path, callback) ->
    data = ""
    if debug
        console.log "getting", path
        httpGet.counter++
    http.get(
        hostname: host,
        port: 80
        path: path
        method: "GET"
        headers: 'user-agent': 'Mozilla/5.0'
    , (response) ->
        response.setEncoding "utf8"
        response.on "data", (chunk) ->
            data += chunk

        response.on "end", ->
            if debug
                httpGet.counter--
                console.log "got", path, "(" + httpGet.counter + " requests left)"
            callback null, data

    ).on("error", (e) ->
        console.log "problem with request, waiting 5s: " + e.message + " on " + path
        setTimeout (-> httpGet host, path, callback), 5000
    ).end()

debug = true
httpGet.counter = 0

extractAllMatches = (data, expr) ->
  link = expr.exec data
  arr = []
  while link?
    arr.push link
    link = expr.exec data
  return arr

getColors = (callback) ->
    httpGet "isthe.com", "/chongo/tech/astro/HR-temp-mass-table-bytemp.html", (err,data)->
        _.filter data.split('\n'),  (line) -> line.indexOf('<TR><TD ALIGN="LEFT">') > -1
        expr = /ALIGN="LEFT">([\w\d]+).*FONT COLOR="(#[\w\d]{6})"/g
        colors = extractAllMatches  data, expr
        colors = colors.map (line) -> sc: line[1], color: line[2]

        callback null, colors

addLines = (starData, callback) ->
    linesTxt = fs.readFileSync "constellations.txt",{encoding: "utf8"}
    zodiac = ["Aries", "Taurus", "Gemini" , "Cancer", "Leo", "Virgo", "Libra", "Scorpius", "Sagittarius", "Capricornus", "Aquarius", "Pisces"]

    starData = starData.map (constellation) ->
        constellation.lines = []
        constellation.zodiac = false
        name = (constellation.name.split ' ').join ''

        lines = extractAllMatches linesTxt, new RegExp('Constellation\\(\"(' + name + ')\",([\\d\\.-]+),([\\d\\.-]+),([\\d\\.-]+),([\\d\\.-]+)\\);', 'g')
        lines = lines.map (line) ->
            dec1: line[2],
            ra1: ((line[3] * 15).toFixed 4),
            dec2: line[4],
            ra2: ((line[5] * 15).toFixed 4)
        constellation.lines = lines if lines

        constellation.zodiac = true if _.find zodiac, (zodName) -> zodName is name
        constellation

    callback null, starData

addBoundaries = (starData, callback) ->
    getRaDec = (d) ->
        coord = extractAllMatches d, /([\d]+)\s([\d]+)\s([\d\.]+)\|([\s-\d\.]+)\|[\w]{3}/g
        coord = coord.map (c) ->
            h = c[1]|0
            m = (c[2]|0) / 60
            s = +c[3] / 3600
            ra = h + m + s
            ra = ra * 15

            dec = +c[4]

            [(+ra.toFixed 4), (+dec.toFixed 4)]
        coord.push coord[0]
        coord
    getBoundary = (constellation, callback) ->
        constellation.boundary = []
        url = constellation.abbr.toLowerCase()
        if url is 'ser'
            httpGet "www.iau.org", "/static/public/constellations/txt/ser1.txt", (error, d1) ->
                constellation.boundary.push(getRaDec d1)
                httpGet "www.iau.org", "/static/public/constellations/txt/ser2.txt", (error, d2) ->
                    constellation.boundary.push(getRaDec d2)
                    callback null, constellation
        else
            httpGet "www.iau.org", "/static/public/constellations/txt/#{url}.txt", (error, data) ->
                constellation.boundary = getRaDec data
                callback null, constellation
    async.map starData, getBoundary, callback

async.waterfall [
    (callback) ->
        httpGet "en.wikipedia.org", "/wiki/88_modern_constellations", callback
    (data, callback) ->
        expr = /<tr>\n<td><a href="\/wiki\/([\w%_]+)(?:_\(constellation\))?"\stitle="([\w\sö]+)(?:\s\(constellation\))?".*\n.*\n<td>([\w]{3})<\/td>/g
        callback null, extractAllMatches data, expr
    (constellations, callback) ->
        async.waterfall [
            getColors
            (sclasses, callback) ->
                getConstellation = (link, callback) ->
                    [unused, url, humanReadable, abbr] = link

                    httpGet "en.wikipedia.org", "/wiki/List_of_stars_in_#{url}", (error, data) ->
                        expr = /<td>([\d]+)<sup>h<\/sup>&#160;([\d]+)<sup>m<\/sup>&#160;([\d\.]+)<sup>s<\/sup><\/td>\n<td>([\d+−]+)°&#160;([\d]+)′&#160;([\d\.]+)″<\/td>\n<td>([\d+−\.]+)<\/td>\n<td>[\d+−\.]+<\/td>\n<td>[\d]+<\/td>\n<td>([\w\d\s\.+-:]+)<\/td>/g
                        stars = extractAllMatches data, expr
                        stars = stars.map (star) ->
                            # RA
                            h = star[1]|0
                            m = (star[2]|0) / 60
                            s = +star[3] / 3600
                            ra = h + m + s
                            ra = ra * 15

                            # Dec
                            deg = star[4]
                            isNegativeDeg = 0 is deg.indexOf '−'
                            deg = deg.slice 1
                            deg = deg|0

                            min = star[5]|0
                            sec = +star[6]
                            dec = deg + min / 60 + sec / 3600
                            dec *= -1 if isNegativeDeg
                            # mag
                            mag = +star[7]

                            sclass = star[8]

                            thisClass = _.find sclasses, (cl) -> cl.sc is sclass
                            if thisClass
                                color = thisClass.color
                            else
                                #console.log "no color for class " + sclass
                                color = "white"
                            mag: mag, ra: (+ra.toFixed 4), dec: (+dec.toFixed 4), class: star[8], color: color
                        #stars = _.filter stars, (star) -> star.mag < 5.5
                        callback null, name: humanReadable, stars: stars, abbr: abbr
                async.map constellations, getConstellation, callback
            addLines
            addBoundaries
        ], (err, results) ->
                callback  null, results
], (err, results) ->
      #console.log results
      fs.writeFile "starData.json", JSON.stringify results



stars.css

body {
    background: #000313;
}
h1 {
    position: absolute;
    top: 280px;
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-size: 18px;
    text-align: center;
    width: 960px;
    color: #fff;
}

stars.js

var width = 960,
    height = 500;

var projection = d3.geo.stereographic()
    .scale(600)


var canvas = d3.select("body").append("canvas")
    .attr("width", width)
    .attr("height", height)

var c = canvas.node().getContext("2d")

var path = d3.geo.path()
    .projection(projection)
    .context(c)

var graticule = d3.geo.graticule()
    .step([15, 15])

var title = d3.select("h1")

d3.json("starData.json", function(error, data) {

    var geoConstellations = []

    data.forEach(function (constellation) {
        var geometries = []

        constellation.stars.map(function (star) {
            if (star.mag < 6)
                geometries.push({
                    type: 'Point',
                    coordinates: [-star.ra, star.dec],
                    properties: {
                        color: star.color,
                        mag: Math.pow(1.3, 4 - star.mag)
                    }
                })
        })

        var lines = constellation.lines.map(function (line) {
            var p1 = [-line.ra1, line.dec1]
            var p2 = [-line.ra2, line.dec2]

            return [p1, p2]
        })
        if (!lines.length){
            console.log(constellation.name)
        }

        geometries.push({
            type: "MultiLineString",
            coordinates: lines
        })

        if (constellation.name == 'Serpens'){
            var bound1 = constellation.boundary[0].map(function (coords) {
                return [-coords[0], coords[1]]
            })
            var bound2 = constellation.boundary[1].map(function (coords) {
                return [-coords[0], coords[1]]
            })
            geometries.push({
                type: "LineString",
                coordinates: bound1
            })
            geometries.push({
                type: "LineString",
                coordinates: bound2
            })
        } else {
            var boundLines = constellation.boundary.map(function (coords) {
                return [-coords[0], coords[1]]
            })
            geometries.push({
                type: "LineString",
                coordinates: boundLines
            })
        }

        geoConstellations.push({
                type: 'Feature',
                geometry: {
                    type: 'GeometryCollection',
                    geometries: geometries
                },
                properties: {
                    name: constellation.name,
                    zodiac: constellation.zodiac
                }
            }
        )
    })

    ready(geoConstellations)
})
function makeRadialGradient(x, y, r, color) {
    var radialgradient = c.createRadialGradient(x, y, 0, x, y, r)
    radialgradient.addColorStop(0.2, color)
    radialgradient.addColorStop(0.5,'rgba(0,3,19,1)')
    radialgradient.addColorStop(1,'rgba(0,3,19,0)')
    c.fillStyle = radialgradient
}

function ready (constellations) {
    var i = -1,
        n = constellations.length;

    (function transition() {
        d3.transition()
            .duration(1250)
            .each("start", function() {
                title.text(constellations[i = (i + 1) % n].properties.name)
            })
            .tween("rotate", function() {
                var p = d3.geo.centroid(constellations[i]),
                    r = d3.interpolate(projection.rotate(), [-p[0], -p[1]])
                return function(t) {
                    projection.rotate(r(t))

                    c.clearRect(0, 0, width, height)
                    c.strokeStyle = "#fff"
                    c.lineWidth = .2
                    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.beginPath(), path({type: "LineString", coordinates: [[0, -75], [0, 0], [0, 75]]}), c.stroke()

                    constellations.forEach(function(constellation){
                        constellation.geometry.geometries.forEach(function(geo){
                            if (geo.type == 'Point') {
                                makeRadialGradient(
                                    projection(geo.coordinates)[0],
                                    projection(geo.coordinates)[1],
                                    geo.properties.mag + 1.2,
                                    geo.properties.color)
                                path.pointRadius([geo.properties.mag + 2])
                                c.beginPath(), path(geo), c.fill();
                            } else if (geo.type == 'LineString'){
                                c.strokeStyle = '#05a'
                                c.lineWidth = .4
                                c.beginPath(), path(geo),c.stroke()
                            } else if (geo.type == 'MultiLineString'){
                                c.strokeStyle = (constellation.properties.zodiac)?'#f2f237':"#fff"
                                c.lineWidth = .4
                                c.beginPath(), path(geo), c.stroke();
                            }
                        })
                    })
                    c.strokeStyle = "#f00"
                    c.lineWidth = 1.2
                    constellations[i].geometry.geometries.forEach(function(geo){
                        if (geo.type == 'LineString'){
                            c.beginPath(), path(geo), c.stroke()
                        }
                    })
                };
            })
            .transition()
            .each("end", transition)
    })();
}