block by renecnielsen 28d20f0070ac05161ae45e918a4dc667

Migrants-Deaths-Visualization

Full Screen

Visulization of Migrant deaths in the Mediterranean

Used this very handy library called D3SvgOverlay which makes is very easy to overlay d3 components over leaflet maps.

Added some Crossfilter based timeline filtering via dc.js.

forked from shobhitg‘s block: Migrants-Deaths-Visualization

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.3/leaflet.css" />
        <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/dc/1.7.0/dc.css"/>
        <!--[if lte IE 8]>
        <link rel="stylesheet" href="//cdn.leafletjs.com/leaflet-0.5/leaflet.ie.css" />
        <![endif]-->
        <!--
        <script type="text/javascript" src="colorbrewer.js"></script>
        <script type="text/javascript" src="leaflet.points-layer.js"></script> -->
        <style type="text/css">
        body {
            padding: 0;
            margin: 0;
        }
        html, body, #map {
            height: 100%;
            width: 100%;
        }
        .tip {
            width: 150px;
            height: 100%;
            background: #EEEEFF;
            opacity:0.8;
            border-style: solid;
            border-width: 1px;
            font-size: 12px;
        }
        .leaflet-popup-content ul { padding-left: 1.5em; }
        .circle { visibility: hidden; }
        .circle.selected { visibility: visible; }
        svg {
            font: 10px sans-serif;
        }
        .axis path, .axis line {
            fill: none;
            stroke: #000;
            shape-rendering: crispEdges;
        }

        #time-chart {
            position: absolute;
            bottom: 0px;
            left: 50%;
            margin-left: -400px;
            background: #fafafa;
            opacity: 0.7;
        }
        </style>
    </head>
    <body>
        <div id='map' data-source="events.json"></div>
        <div id="time-chart" class="dc-chart">
        
        <script src="//cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.3/leaflet.js"></script>
        <script src="//d3js.org/d3.v3.js"></script>
        <script src="//cdnjs.cloudflare.com/ajax/libs/dc/1.7.0/dc.min.js"></script>
        <script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/1.0.0-rc.3/lodash.underscore.min.js"></script>
        <script src="https://cdn.rawgit.com/teralytics/Leaflet.D3SvgOverlay/master/L.D3SvgOverlay.min.js"></script>
        <script src="//labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.min.js"></script>
        <script type="text/javascript">var container = L.DomUtil.get('map');
var map = L.map('map').setView([45, 10], 3);

L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
    attribution: 'Map data &copy; <a href="//openstreetmap.org">OpenStreetMap</a> contributors, <a href="//creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="//mapbox.com">Mapbox</a>',
    maxZoom: 18,
    id: 'shobhitg.na7jk2f5',
    accessToken: 'pk.eyJ1Ijoic2hvYmhpdGciLCJhIjoiNmI1Nzg0ZmIzMWY4OGU4MGEzYzI3ZGIxMzBhZmQ4NmUifQ.z5e8zocByNWRqW6VPfxpwg'
}).addTo(map);
d3.json(container.dataset.source, function(migrantData) {
    var updateMap;
    var init = false;

    var d3Overlay = L.d3SvgOverlay(function(selection, projection) {


        updateMap = function() {

            var data = monthDimension.top(Infinity);
            if (data.length === migrantData.length) return;

            console.log(data.length);
            data = data.filter(function(d) {
                return !((d.latitude === "") || (d.longitude === ""));
            });


            var feature = selection.selectAll("circle")
                .data(data);

            tip = d3.tip()
                .offset([-10, 0])
                .attr('class', 'd3-tip').html(function(d) {
                    return '<div class="tip"><b>Dead or missing</b>: ' + d.dead_and_missing + '<BR><i>' + d.description + '</i></div>';
                    //return '<div class="tip">Dead or missing:' + d.dead_and_missing + '</div>';
                });

            /* Invoke the tip in the context of your visualization */
            selection.call(tip)

            feature.enter().append("circle")
                .style("stroke", "black")
                .attr('stroke-width', 1 / projection.layer._scale)
                .style("opacity", .2)
                .style("fill", "red")
                .attr("r", function(d) {
                    return Math.log(d.dead_and_missing) * 2 * 1 / Math.min(projection.layer._scale, 15);
                })
                .attr('cx', function(d) {
                    return projection.latLngToLayerPoint([parseFloat(d.latitude), parseFloat(d.longitude)]).x
                })
                .attr('cy', function(d) {
                    return projection.latLngToLayerPoint([parseFloat(d.latitude), parseFloat(d.longitude)]).y
                })
                .on('mouseover', tip.show)
                .on('mouseout', tip.hide);

            feature
                .exit().remove();

            feature
                .attr('stroke-width', 1 / projection.layer._scale)
                .attr("r", function(d) {
                    return Math.log(d.dead_and_missing) * 2 * 1 / Math.min(projection.layer._scale, 15);
                });

        };

        if (init === false) {
            init = true;

            cfData = crossfilter(migrantData);


            var timeChart = dc.barChart('#time-chart');

            var dateDimension = cfData.dimension(function(d) {
                return new Date(d.date)
            });

            window.monthDimension = cfData.dimension(function(d) {
                return new Date(d.date);
            });

            var openGroup = monthDimension.group().reduceSum(function(d) {
                return parseInt(d.dead_and_missing);
            });
            closeGroup = monthDimension.group().reduce(
                function(p, v) {
                    p.push(v.close);
                    return p;
                },
                function(p, v) {
                    p.splice(p.indexOf(v.close), 1);
                    return p;
                },
                function() {
                    return [];
                }
            );

            timeChart
                .width(800)
                .height(120)
            //.margins({top: 10, right: 50, bottom: 30, left: 50})
            .dimension(monthDimension)
                .group(openGroup)
                .x(d3.time.scale().domain([new Date("1999-01-01T00:00:00Z"), new Date("2016-09-30T00:00:00Z")]))
                .round(d3.time.days.round)
                .xUnits(d3.time.days)
                .elasticY(true)
                .on("filtered", updateMap)
                .filter([new Date("2006-01-01T00:00:00Z"), new Date("2013-09-30T00:00:00Z")]);

            dc.renderAll();

        }

        updateMap();


    });

    d3Overlay.addTo(map);

});</script>
    </body>
</html>