Skip to content

Instantly share code, notes, and snippets.

@jimartincorral
Last active December 4, 2022 17:44
  • Star 18 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save jimartincorral/d936859eaa09db025b9b7e89176a8ffb to your computer and use it in GitHub Desktop.
Create a mini version of CartoDB.js from scratch.

Create a mini version of CartoDB.js from scratch

Context

The Engine team is working on the next version of CartoDB.js. We’ll be rewriting the API, supporting many new requirements from BUILDER and clients, and incorporating a new backend. This will involve some changes to the library. CartoDB.js is a library that abstracts several libraries (Leaflet, Tangram, Google Maps) to offer a unified API that developers can use to render and customise maps. On top of that, the new version of the library will provide functionality to manage widgets, analysis, etc. The library integrates with CARTO’s Maps API, which acts as the backend that provides tiles, interactivity grids, feature attributes, etc. One of the main challenges of the library is making all these components work / communicate nicely together. Sounds interesting to you? We would love to see how you would tackle these kind of problems by solving this little test.

Goals

Your mission is to write a little JS library (a mini version of CartoDB.js) that reads a config file describing a map and:

  1. Renders the map using one of the available mapping libraries (Leaflet, OpenLayers, Google Maps, d3.js… you choose!).
  2. Exposes an API to: 2.1. Show / hide any of the map layers. 2.2. Update the “sql” attribute of CartoDB layers that are rendered by Maps API.

This is quite a lot of work, but we think it’s interesting! There’s no time limit for this test. We know you probably have a busy life, so please, do as much as you possible can! And please, don’t let the scope of this test push you back. If you can only finish goal #1, it’s totally okay!

What you should do

  • Think about the architecture of your library, try to split your code into components / modules / files / folders.
  • Store your code in a github / gitlab / bitbucket repo.
  • Prepare an HTML file that uses your library to render the map and allows us to test the library from the browser’s console. Something similar to this.
  • Include a README file describing the library and explaining how to “install” and use it.
  • Send an email to pablo@carto.com and share your solution with us. Thanks! 👏👏👏

What you can do

  • Use Backbone.js (CartoDB.js uses it) or go with vanilla JS.
  • Use any other little JS library that might help you accomplish some basic things (eg: underscore, jQuery, etc.)
  • Use any bundling tool if you need to.
  • Use ES5/6/7.

What we will be looking for

  1. A nice architecture with nicely decoupled components. We’ll be asking ourselves questions like: “How easy would it be to switch the mapping library?”.
  2. Code that we can easily understand and makes sense to us.
  3. A developer friendly API.

Test description

Goal #1 - Render the map

Your library should be able to read the following config file:

{
  "center":"[52.5897007687178, 52.734375]",
  "zoom":4,
  "maps_api_config": {
    "user_name": "documentation",
    "maps_api_template": "http://{user}.cartodb.com:80"
  },
  "layers":[
    {
      "type":"tiled",
      "options":{     "urlTemplate":"http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png",
        "minZoom":"0",
        "maxZoom":"18",
        "attribution":"&copy; <a href=\"http://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors"
      }
    },
    {
      "type":"CartoDB",
      "options":{
        "sql":"select * from european_countries_e",
        "cartocss":"/** choropleth visualization */\n\n#european_countries_e{\n  polygon-fill: #FFFFB2;\n  polygon-opacity: 0.8;\n  line-color: #FFF;\n  line-width: 1;\n  line-opacity: 0.5;\n}\n#european_countries_e [ area <= 1638094] {\n   polygon-fill: #B10026;\n}\n#european_countries_e [ area <= 55010] {\n   polygon-fill: #E31A1C;\n}\n#european_countries_e [ area <= 34895] {\n   polygon-fill: #FC4E2A;\n}\n#european_countries_e [ area <= 12890] {\n   polygon-fill: #FD8D3C;\n}\n#european_countries_e [ area <= 10025] {\n   polygon-fill: #FEB24C;\n}\n#european_countries_e [ area <= 9150] {\n   polygon-fill: #FED976;\n}\n#european_countries_e [ area <= 5592] {\n   polygon-fill: #FFFFB2;\n}",
        "cartocss_version":"2.1.1"
      }
    },
    {
      "options": {
        "urlTemplate": "http://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png",
        "minZoom": "0",
        "maxZoom": "18",
        "attribution": "&copy; <a href=\"http://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors"
      },
      "type": "tiled"
    }
  ],
}

As you can see, the config file contains:

  • Some initial config for the map (center & zoom).
  • Maps API configuration details.
  • 3 layers:
    • A tiled layer with options for the basemap.
    • A layer with some SQL and CartoCSS.
    • A tiled layer with options for the labels.

Tiled layers contain XYZ URL templates so they should be pretty straight forward to render(eg: using a L.TileLayer if you go with Leaflet). You will also be able to render the CartoDB layer with a plain old tiled layer, but… where’s the URL template to fetch those tiles? Don’t worry, we’ll help you this! The Maps API is the component that renders tiles for CARTO maps. Before you can fetch tiles for a map, your library will need to talk to Maps API so that it has some info about the tiles that you’re going to request. Here’re the steps that you’ll need to follow to generate a URL template for the CartoDB layer:

  1. Make a POST request to: http://documentation.cartodb.com/api/v1/map You should be able to easily generate this ^^ URL from the maps_api_config in the config file. You should also generate the payload (the MapConfig) for this request. All of the information you will need is in the config file as well. It should like this:
{
  "layers": [
    {
      "type": "http",
      "options": {
        "urlTemplate": "http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png"
      }
    },
    {
      "type": "mapnik",
      "options": {
        "cartocss": "/** choropleth visualization */\n\n#european_countries_e{\n  polygon-fill: #FFFFB2;\n  polygon-opacity: 0.8;\n  line-color: #FFF;\n  line-width: 1;\n  line-opacity: 0.5;\n}\n#european_countries_e [ area <= 1638094] {\n   polygon-fill: #B10026;\n}\n#european_countries_e [ area <= 55010] {\n   polygon-fill: #E31A1C;\n}\n#european_countries_e [ area <= 34895] {\n   polygon-fill: #FC4E2A;\n}\n#european_countries_e [ area <= 12890] {\n   polygon-fill: #FD8D3C;\n}\n#european_countries_e [ area <= 10025] {\n   polygon-fill: #FEB24C;\n}\n#european_countries_e [ area <= 9150] {\n   polygon-fill: #FED976;\n}\n#european_countries_e [ area <= 5592] {\n   polygon-fill: #FFFFB2;\n}",
        "cartocss_version": "2.1.1",
        "sql": "select * from european_countries_e",
        "interactivity": [
          "cartodb_id"
        ]
      }
    },
    {
      "type": "http",
      "options": {
        "urlTemplate": "http://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png"
      }
    }
  ]
}
  1. Generate the XYZ URL template to fetch tiles. This previous request should return something like:
{
  "layergroupid": "28186517f686d343f8e69342c5d74fe9:0",
  "metadata": {
    "layers": [ … ]
  }, ...
}
  • As long as you get a “layergroupid” and you can see some metadata for each of the layers, you are in a great position to now generate the XYZ URL template to fetch tiles for this map. Here’s what the template should look like: image
  1. Fetch tiles As mentioned, once you have your URL template, you will be able to use a tiled layer that will fetch tiles and render them in the map. Your map should look like this: image
Goal #2 - Create a little API for the library

This API should allow users to:

  1. Show / hide any of the layers (eg: layer.hide())
  2. Change the “sql” of the CartoDB layer (eg: layer.setSQL("select * from european_countries_e LIMIT 10"))

When users change the SQL of the CartoDB layer, your library will have to trigger a new request to the Maps API and generate a new url template to fetch new tiles for the CartoDB layer again. After changing the SQL, your map should no longer show all countries.

image

--

If you have any questions about this test, don’t hesitate to send us an email (ivan@carto.com) and we’ll help you. We can’t wait to see what you come up with! Thanks for you time!

@amir-ba
Copy link

amir-ba commented Aug 2, 2020

my attempt at this exercise https://github.com/amir-ba/cartoDb
I did one as a ts library and one integrated in an angular project just for fun. :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment