JS and Svelte: Error converting JS to GeoJSON - Parse failure Unexpected token (1:7)

Viewed 69

I have CSV file which looks like this. I need to convert it into a GeoJSON format to visualize it with Mapbox. I used this reference of what a geojson needs to look like from Mapbox and wrote the following script that could produce a similar file from the data I had:

const fs = require('fs');
const CWD = process.cwd();
const { parse } = require('csv/sync');
const inPath = `${CWD}/src/data/`;
const outPath = `${CWD}/src/data/`;
// Read file
const csv = fs.readFileSync(`${inPath}organizations.csv`, 'utf8');

const json = parse(csv, { columns: true });
const jsonWithId = json.map((el, i) => ({ ...el, id: i + 1 }));
const features = jsonWithId.map(el => ({
    type: 'Feature',
    properties: el,
    geometry: {
        type: 'Point',
        coordinates: [el.scatterLong, el.scatterLat ]
    }
}));
// Create the feature collection
const featureCollection = {
    type: 'FeatureCollection',
    crs: {
        type: 'name',
        properties: {
            name: 'urn:ogc:def:crs:OGC:1.3:CRS84'
        },
}, 
features: features

};
// Write the GEOJSON file
fs.writeFileSync(`${outPath}organizations.geojson`, JSON.stringify(featureCollection));

This converts my file and produces this geojson which seems to be the correct result. When I try to run it on JSFiddle like here, everything works perfectly. However when I copy the same code into my Svelte website and run it like so:

import { mapbox, key } from './mapbox.js';
import { setContext } from 'svelte';
import geoData from "$data/organizations.geojson"
    setContext(key, {
        getMap: () => map,
    });
    // Function load to create a new map and add to div
const load = () => {
    map = new mapbox.Map({
        container: container,
        style: 'mapbox://styles/username/cl4ktlt35001d16mim8rtqh8i',
        center: [-103.5917, 40.6699],
        zoom: 3
    });

    map.on('load', () => {
        map.addSource('earthquakes', {
            type: 'geojson',
            data: geoData,
            cluster: true,
            clusterMaxZoom: 14, // Max zoom to cluster points on
            clusterRadius: 50 // Radius of each cluster when clustering points (defaults to 50)
        });

// Rest of the code

I get the following error:

500
Parse failure: Unexpected token (1:7)
Contents of line 1: [the entire contents of the file follow]

What does this mean? What is wrong with my file, why does it run fine on JSFiddle but not on my actual website? And how can I fix this?

1 Answers

I'd assume that there's something wrong with how/when you call load because it works in a REPL using an action like this with the code from your JSFiddle and giving the same result (not sure if it's wise to make the accessToken public? If not let me know and I delete the REPL)

The official tutorial context-api section using mapbox-gl

mapboxgl.js
import mapboxgl from 'mapbox-gl';

// https://docs.mapbox.com/help/glossary/access-token/
mapboxgl.accessToken = '*****';

const key = Symbol();

export { mapboxgl, key };
Map.svelte
<script>
    import { onDestroy, setContext } from 'svelte';
    import { mapboxgl, key } from './mapboxgl.js';

    setContext(key, {
        getMap: () => map,
    });

    let map
    
    function initMap(container) {
        
        map = new mapboxgl.Map({
            container: container,
            style: 'mapbox://styles/mapbox/dark-v10',
            center: [-103.5917, 40.6699],
            zoom: 3
        });

        map.on('load', () => {
            // Add a new source from our GeoJSON data and
            // set the 'cluster' option to true. GL-JS will
            // add the point_count property to your source data.
            map.addSource('earthquakes', {
                type: 'geojson',
                // Point to GeoJSON data. This example visualizes all M1.0+ earthquakes
                // from 12/22/15 to 1/21/16 as logged by USGS' Earthquake hazards program.
                data: 'https://gist.githubusercontent.com/thedivtagguy/0a07453f2081be9c0f5b6fc2a2681a0f/raw/3c41dbbba93f88a78af1cf13e88443d2eed7d6ec/geodata.geojson',
                cluster: true,
                clusterMaxZoom: 14, // Max zoom to cluster points on
                clusterRadius: 50 // Radius of each cluster when clustering points (defaults to 50)
            });

            map.addLayer({
                id: 'clusters',
                type: 'circle',
                source: 'earthquakes',
                filter: ['has', 'point_count'],
                paint: {
                    // Use step expressions (https://docs.mapbox.com/mapbox-gl-js/style-spec/#expressions-step)
                    // with three steps to implement three types of circles:
                    //   * Blue, 20px circles when point count is less than 100
                    //   * Yellow, 30px circles when point count is between 100 and 750
                    //   * Pink, 40px circles when point count is greater than or equal to 750
                    'circle-color': [
                        'step',
                        ['get', 'point_count'],
                        '#51bbd6',
                        100,
                        '#f1f075',
                        750,
                        '#f28cb1'
                    ],
                    'circle-radius': [
                        'step',
                        ['get', 'point_count'],
                        20,
                        100,
                        30,
                        750,
                        40
                    ]
                }
            });

            map.addLayer({
                id: 'cluster-count',
                type: 'symbol',
                source: 'earthquakes',
                filter: ['has', 'point_count'],
                layout: {
                    'text-field': '{point_count_abbreviated}',
                    'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'],
                    'text-size': 12
                }
            });

            map.addLayer({
                id: 'unclustered-point',
                type: 'circle',
                source: 'earthquakes',
                filter: ['!', ['has', 'point_count']],
                paint: {
                    'circle-color': '#11b4da',
                    'circle-radius': 4,
                    'circle-stroke-width': 1,
                    'circle-stroke-color': '#fff'
                }
            });

            // inspect a cluster on click
            map.on('click', 'clusters', (e) => {
                const features = map.queryRenderedFeatures(e.point, {
                    layers: ['clusters']
                });
                const clusterId = features[0].properties.cluster_id;
                map.getSource('earthquakes').getClusterExpansionZoom(
                    clusterId,
                    (err, zoom) => {
                        if (err) return;

                        map.easeTo({
                            center: features[0].geometry.coordinates,
                            zoom: zoom
                        });
                    }
                );
            });

            // When a click event occurs on a feature in
            // the unclustered-point layer, open a popup at
            // the location of the feature, with
            // description HTML from its properties.
            map.on('click', 'unclustered-point', (e) => {
                const coordinates = e.features[0].geometry.coordinates.slice();
                const mag = e.features[0].properties.mag;
                const tsunami =
                            e.features[0].properties.tsunami === 1 ? 'yes' : 'no';

                // Ensure that if the map is zoomed out such that
                // multiple copies of the feature are visible, the
                // popup appears over the copy being pointed to.
                while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
                    coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
                }

                new mapboxgl.Popup()
                    .setLngLat(coordinates)
                    .setHTML(
                    `magnitude: ${mag}<br>Was there a tsunami?: ${tsunami}`
                )
                    .addTo(map);
            });

            map.on('mouseenter', 'clusters', () => {
                map.getCanvas().style.cursor = 'pointer';
            });
            map.on('mouseleave', 'clusters', () => {
                map.getCanvas().style.cursor = '';
            });
        });

    }
</script>

<div use:initMap></div>

<style>
    div {
        position: absolute;
        inset: 0 0 80px 0;
    }
</style>
Related