1

I am trying to make a Mapbox map that would show data chronologically for a given year, and I am trying to make the year be specified automatically in sequence.

However, I am having a problem using setInterval to move the time slider in the following script automatically, and it gives me a [object HTMLLabelElement] without the slider moving.

Am I setting the setInterval to the wrong function?

<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8' />
    <title></title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.29.0/mapbox-gl.js'></script>
    <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.29.0/mapbox-gl.css' rel='stylesheet' />
    <style>
        body { margin:0; padding:0; }
        #map { position:absolute; top:0; bottom:0; width:100%; }
    </style>
</head>
<body>

<style>
.map-overlay {
    font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
    position: absolute;
    width: 25%;
    top: 0;
    left: 0;
    padding: 10px;
}

.map-overlay .map-overlay-inner {
    background-color: #fff;
    box-shadow:0 1px 2px rgba(0, 0, 0, 0.20);
    border-radius: 3px;
    padding: 10px;
    margin-bottom: 10px;
}

.map-overlay h2 {
    line-height: 24px;
    display: block;
    margin: 0 0 10px;
}

.map-overlay input {
    background-color: transparent;
    display: inline-block;
    width: 100%;
    position: relative;
    margin: 0;
    cursor: ew-resize;
}
</style>

<div id='map'></div>

<div class='map-overlay top'>
    <div class='map-overlay-inner'>
        <h2>Tel-Aviv Cinemas 1914-2016</h2>
        <label id='Year'></label>
        <input id='slider' type='range' min='0' max='102' step='1' value='0' />
    </div>
    <div class='map-overlay-inner'></div>
</div>

<script src="https://d3js.org/d3.v4.js"></script>

<script>
mapboxgl.accessToken = 'pk.eyJ1Ijoia3Z5YiIsImEiOiJjaXUwMHEwcmgwMDAxMnlvM3NzMm0xbGozIn0.JL_eeNZL_lDoJxijNqFPoA';
var map = new mapboxgl.Map({
    container: 'map',
    style: 'mapbox://styles/mapbox/dark-v9',
    center: [34.775981, 32.081287],
    zoom: 11
});

var Years = ['1914', '1915', '1916', '1917', '1918', '1919', '1920', '1921', '1922', '1923', '1924', '1925', '1926', '1927', '1928', '1929', '1930', '1931', '1932', '1933', '1934', '1935', '1936', '1937', '1938', '1939', '1940', '1941', '1942', '1943', '1944', '1945', '1946', '1947', '1948', '1949', '1950', '1951', '1952', '1953', '1954', '1955', '1956', '1957', '1958', '1959', '1960', '1961', '1962', '1963', '1964', '1965', '1966', '1967', '1968', '1969', '1970', '1971', '1972', '1973', '1974', '1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982', '1983', '1984', '1985', '1986', '1987', '1988', '1989', '1990', '1991', '1992', '1993', '1994', '1995', '1996', '1997', '1998', '1999', '2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010', '2011', '2012', '2013', '2014', '2015', '2016'];

function filterBy(Year) {
    var filters = ['==', 'Year', Year];
    map.setFilter('cinema-circles', filters);
    map.setFilter('cinema-labels', filters);

    // Set the label to the Year
    document.getElementById('Year').textContent = Year;
}

map.on('load', function() {

    // Data courtesy of https://earthquake.usgs.gov/
    // Query for significant earthquakes in 2015 URL request looked like this:
    // https://earthquake.usgs.gov/fdsnws/event/1/query
    //    ?format=geojson
    //    &starttime=2015-01-01
    //    &endtime=2015-12-31
    //    &minmagnitude=6'
    //
    // Here we're using d3 to help us make the ajax request but you can use
    // Any request method (library or otherwise) you wish.
    d3.json('https://cldex.net/visual/cinema_telaviv.geojson', function(err, data) {
        if (err) throw err;

        // Create a Year property value based on time
        // used to filter against.
        data.features = data.features.map(function(d) {
        return d;
        });

        map.addSource('cinemas', {
            'type': 'geojson',
            'data': data
        });

        map.addLayer({
            'id': 'cinema-circles',
            'type': 'circle',
            'source': 'cinemas',
            'paint': {
                'circle-color': {
            property: 'sqrt',
            stops: [
                [0, '#f1f075'],
                [1500, '#e55e5e']
                ]
                },
                'circle-opacity': 0.75,
                'circle-radius': 20
            }
        });

        map.addLayer({
            'id': 'cinema-labels',
            'type': 'symbol',
            'source': 'cinemas',
            'layout': {
                'text-field': '{Cinema}',
                'text-font': ['Open Sans Bold', 'Arial Unicode MS Bold'],
                'text-size': 12
            },
            'paint': {
                'text-color': 'rgba(0,0,0,0.5)'
            }
        });

        // Set filter to first Year of the Year
        // 0 = 1914
        filterBy(1914);
        document.getElementById('slider').addEventListener('input', function(e) {
              var Year = window.setInterval(function() { parseInt(Years[e.target.value]) }, 1000);
            filterBy(Year);
        });
        // Create a popup, but don't add it to the map yet.
        var popup = new mapboxgl.Popup({
            closeButton: false,
            closeOnClick: false
});

map.on('mousemove', function(e) {
    var features = map.queryRenderedFeatures(e.point, { layers: ['cinema-circles'] });
    // Change the cursor style as a UI indicator.
    map.getCanvas().style.cursor = (features.length) ? 'pointer' : '';

    if (!features.length) {
        popup.remove();
        return;
    }

    var feature = features[0];

    // Populate the popup and set its coordinates
    // based on the feature found.
    popup.setLngLat(feature.geometry.coordinates)
        .setHTML(feature.properties.Cinema+'<b> Cinema Information</b>'+'<br><b>Number: </b>'+feature.properties.Number+'<br><b>Number of Screens: </b>'+feature.properties.Screens+'<br><b>Number of Seats: </b>'+feature.properties.Seatss)
        .addTo(map);
});
});
});
</script>

</body>
</html>

My Data can be found in a geojson: https://cldex.net/visual/cinema_telaviv.geojson

Kristian Vybiral
  • 509
  • 9
  • 20

2 Answers2

2

Your usage of setInterval is incorrect currently, and you have a few syntax errors.

Where you currently have this:

var Year =  set.Interval(function() { parseInt(Years[e.target.value] }, 1000);

Try this instead:

var Year = window.setInterval(function() { parseInt(Years[e.target.value]) }, 1000);

You may still have some issues elsewhere, but I was having difficulty getting your data endpoint parsing correctly in d3. It may help to post up a codepen or something of this to get more help if you need it.


Edit:

I've created a codepen from your current setup, which may help you to tinker around a little easier: http://codepen.io/anon/pen/EZjKqM

As you can see I've made a few more changes, such as adding something to increment through the array of years which uses your filterBy function. It doesn't work perfectly, but you can see how it's parsing the data correctly and changing the year by the second.

This is achieved by using the following JS:

// Automatically cycle through years.
var yearSlider = document.getElementById('slider');
var curYearIndex = -1;

function advanceYear() {
    ++curYearIndex;
    if (curYearIndex >= years.length) {
        curYearIndex = 0;
    }
    return years[curYearIndex];
}

var cycleYears = window.setInterval(function() { 
    var currentYear = advanceYear();
    filterBy(parseInt(currentYear));
}, 1000);

Unfortunately this is probably as far as I'll get with this, as I've other things to work on, but it perhaps gives you a bit of a starting point.

Wakeuphate
  • 493
  • 3
  • 13
  • Solving the syntax errors gives still does not give a good result. How do I make the slider move on interval? – Kristian Vybiral Jan 05 '17 at 12:48
  • @KristianVybiral I've added a bit more to this and edited my post. Unfortunately it doesn't look like the slider is moving, but the data is now parsing and the text is updating. Perhaps you need to tinker a bit more to change the slider while updating the text in your `filterBy` function. Hope this helps. – Wakeuphate Jan 06 '17 at 16:22
  • @KristianVybiral also, while I'd generally not recommend adding bloat with jQuery, it may make your life easier here. It's worth looking down that avenue at least. – Wakeuphate Jan 06 '17 at 16:23
  • Thank you for the elaborate solution - awesome! I will definitely take a look at jQuery and improve this question in the future, when I have time to work on it. – Kristian Vybiral Jan 06 '17 at 17:24
1

@Wakeuphate, this is an awesome solution (up-voted accordingly). I was able to implement quickly for my project.

It seems the missing item was moving the slider as well. I was able to achieve this by simply adding the following line:

    document.getElementById('slider').value = currentYear;

So that the full function looks like:

var cycleYears = window.setInterval(function() { 
        var currentYear = advanceYear();
        filterBy(parseInt(currentYear));
        document.getElementById('slider').value = currentYear;
    }, 1000);
greenbergé
  • 346
  • 2
  • 9