Giter VIP home page Giter VIP logo

maperture's Introduction

Maperture: Stamen's map compare tool

Maperture Science

A web application for comparing webmap styles.

View a demo here.

gif demo

Get started

  1. Install the dependencies: yarn install
  2. Make a local config module: cp public/config/local.example.js public/config/local.js and edit the config file as appropriate
  3. Start the dev server: yarn dev

Building and running in production mode

  1. Create an optimised version of the app: yarn build. If you will serve the built app from a subpath such as /compare-tool/ rather than the root domain, use the BASE_PATH environment variable to set it: BASE_PATH=/compare-tool/ yarn build
  2. Deploy public/ to a server.

Local config

The compare tool allows you to use a local config file (public/config/local.js) to customize for your use case.

Here, you can customize the following options:

  • mapboxGlAccessToken: Your Mapbox GL token to allow style reads

  • mapboxBaseApiUrl: (optional) Support for a Mapbox flavored style that is served from a different server other than api.mapbox.com, e.g., Mapbox Atlas.

  • googleMapsAPIKey: Your Google Maps API key to enable API usage

  • stylePresets: A list of styles with urls to show in the dropdowns. Styles must have the following keys:

    • id: a unique id
    • name: a display name
    • type: the type of map (mapbox-gl, maplibre-gl, google, leaflet)
    • url: (currently applies to mapbox-gl, maplibre-gl, and leaflet maps only) the style's url
    • mapId: (currently google only) the style's id
  • branchPatterns: An array of objects that specify how to build a URL to fetch a style living on a branch with the following keys:

    • pattern: a tokenized url pattern using {branch} and {style} tokens
    • styles: an array specifying specific styles you can view on the specified branch
    • type: the type of map (mapbox-gl, maplibre-gl, google, leaflet)
  • stylePresetUrls: An array of URLs pointing to additional presets. URLs must point to JSON arrays containing objects of the same shape as those in stylePresets.

  • gazetteer: An object that specifies the options available in the interface for navigating directly to specific geographic locations or changing other view options such as the pitch and zoom of the map. The object is a map of option group names to arrays of options. Each option is an object of names to map options to update.

    See defaultGazetteer in src/make-config.js for the default gazetteer, but as an example you might use:

    const gazetteer = {
      Locations: [
        {
          'San Francisco, CA': {
            zoom: 18,
            center: { lng: -122.4193, lat: 37.7648 },
          },
        },
        {
          'Washington DC': {
            zoom: 12,
            center: { lng: -77.0435, lat: 38.9098 },
          },
        },
      ],
    };

    This creates an option group called Locations with two options (San Francisco and Washington DC). Selecting San Francisco or Washington DC zooms and centers the map view as specified.

For more details on how these should look, see the example in public/config/local.example.js.

Setting up the app in your repo

1. Install this module into your repo.

npm i github:stamen/maperture#<release> or yarn add github:stamen/maperture#<release>

2. Set up files to serve app

When setting up the app in your repo, you'll want to create a directory that can house:

  • An index.html file to serve the app
  • A local config file (specified above)
  • The copied over module files (see step 3)

Your index.html file should look like the following:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />

    <title>Maperture</title>

    <link rel="stylesheet" href="./dist/bundle.css" />
  </head>

  <script type="module">
    import { startApp } from './dist/bundle.js';
    import * as localConfig from './local.js';

    startApp(document.body, { localConfig });
  </script>

  <body></body>
</html>

3. In addition, prior to serving the compare tool in your repo, you'll want to add a simple build script to your package that will copy our module files into the appropriate directory where tool/dir/path/ is the directory you've created to serve the app from:

"build-compare": "rm -rf tool/dir/path/dist && cp -r node_modules/maperture/dist tool/dir/path/dist"

You will run this build script prior to serving the app from index.html or publishing the app anywhere to ensure files are up to date.

The final directory structure should look like:

root/
  - maperture/
    - dist/
      - bundle.js
      - bundle.js.map
      - bundle.css
    - index.html
    - local.js

maperture's People

Contributors

almccon avatar aparlato avatar bdon avatar ebrelsford avatar peterqliu avatar rossthorn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

maperture's Issues

Compare with a Google Maps pane

There have been cases in the past (with our raster compare tool) when we included a raster Google Map as one of the compare options. Now we have a client requesting a Google Maps comparison again.

I assume the right way to do that would be to instantiate the google maps javascript API, but I can imagine that maybe a stopgap would be to implement a raster leaflet viewer instead, and load rasterized Google tiles instead? Either one would take work (because currently this compare tool is just for Mapbox GL in both panes)... just offering the idea if Leaflet seems significantly easier or quicker.

Load preset styles from urls

We currently have a way to add static style presets in the config file. As these presets may change often for some projects, we should additionally allow for dynamic preset styles loaded from a URL or URLs.

  • Add an entry to the config that can be overridden by the local config. This should be an array of URLs to JSON files that contain arrays of the same shape as the stylePresets array here.
  • On load, the app should load each of the URLs and concatenate the presets with the existing presets.

Discussion: Consider adding a debug mode to show all data in tiles

Maputnik uses a library to do this but the opinion of the team is that it isn't good enough:

image

We should consider

  • Is there a way to make the library Maputnik uses create a better view?
  • Is there another library we could use?
  • Should we do this ourselves?
  • Distinguishing between features that appear on the map and those filtered out by the style

Phone view so wide that it is overlapped by UI

Describe the issue

I was using the viewer earlier in Chrome and was seeing the style selection UI elements overlap the phone view when the window was at several different sizes. I'm not sure how they're positioned on the page but they seem quite wide:

Chrome - most of the screen on my 16" Macbook Pro
Screen Shot 2022-04-28 at 6 05 13 PM

Firefox - most of the screen on my 16" Macbook Pro
Screen Shot 2022-04-28 at 6 06 58 PM

It's hard to get a screenshot of them together without overlap when they're so far apart ๐Ÿ˜ฌ

Style input's text input unexpectedly disappears

It's a little hard to reproduce, but the custom URL text input disappears, presumably because something in the state is changing to hide it?

We should dig into the situations where this could happen to more solidly reproduce, then fix those.

For example, I can see it if I select a style, then select the custom URL option and hit [enter]. Then I see this inconsistent state:

image

Accept multiple branchPatterns for map style input

We have a project that requires multiple branchPattern objects, so it would be great to expand the map style input and configuration to allow for an array of branchPattern objects rather than strictly one object.

Ideally we would also be able to configure the group name within the dropdown.

I'm imagining an array like:

const branchPatterns = [
  {
    name: 'Styles on branch, group 1',
    pattern: 'https://example.com/styles/{branch}/group1/{style}/style.json',
    styles: ['styleA', 'styleB']
  },
  {
    name: 'Styles on branch, group 2',
    pattern: 'https://example.com/styles/{branch}/group2/{style}/style.json',
    styles: ['styleB', 'styleC']
  }
];

Note that not all styles are necessarily present in all groups, so I do think splitting this out into an array (rather than further complicating the url pattern) is preferable.

Map styles reset when other state changes

It looks like the handler for other state changes (eg view mode) is using the original maps.

Reproduce:

  1. Change either map pane to a different style
  2. Change the view mode

The map pane you changed the style for will be reset to the original style.

Add a way to load styles from a URL

Similar to other existing versions of this tool, we should be able to load a Mapbox GL style from a URL.

This should fit in the map's description box:

image

Let's start with a similar setup to what we have in other tools. Select it from a dropdown:

image

Then enter the URL:

image

Fix favicon

Maybe a default Stamen favicon? Currently it is the Svelte favicon which is clearly wrong!

Use a web framework

Let's port this tool to a web framework. I propose we use Svelte.

The benefits would be:

  • more maintainable
  • easier to fork for individual clients / hyper-specific requirements

Proposed approach:

  • get ported application up to basic requirements
    • two map panes (for now, see #5)
    • just Mapbox GL maps for now (but flexible enough to eventually support others, see #7, #2)
    • change style for a pane by entering a style URL
    • simple controls at top of page
      • show/copy current map position
      • geocoder search
      • show label collisions switch
  • rename to map-compare as we would like to support other mapping libraries soon
  • make enhancement issues to reach parity with other internal tools

I have a version that I'm working on locally, if the above sounds good to you @aparlato I'll continue on that path, then push it here once we have a solid foundation.

More helpful error message on mismatch Google map id and API key

#77 turned out to be triggered by either missing your mapId for a Google map or having mismatched mapId and googleMapsAPIKey.

We should be able to give a more helpful error message when this is the case as the errors you get and the maps falling out of sync don't indicate that this is the core of the issue.

Allow three or more map panes to be compared

It was bound to happen eventually, but it happened for me pretty quick... I'm in a situation where it would be really handy to have three panes.

The swipe tool wouldn't work in this case, instead it would have to be three linked side-by-side views.

Could we implement this easily? And what are the UI implications? Would we want the option to add/remove that third pane, or to potentially add n panes? Could this work if we had a toggle between the "swipe" mode and "side-by-side" mode? But if you're in three-pane side-by-side view and then you want to switch to swipe mode, would it just drop one? Or prevent you from switching to swipe....? hmm.

Consider adding a way to view feature data within a map pane

Likely only for Mapbox GL styles. On click, show which features you clicked on and the data associated with those features.

Some things to consider:

  • Is this always on, or an option that you need to enable?
  • What should the interface look like?
  • Should the feature remain selected in the URL state?

Publish demo site on github pages

We need an easy way to show what this tool can do that is not project-specific.

Should include:

  • simple preset styles
  • simple gazetteer
  • no branch presets since those are project-specific
  • use its own demo Mapbox key
  • automatically build and publish to GitHub Pages when main changes
  • link to demo from the README

Handle pixel ratio in responsive mode

See #68 (review)

As a followup to allowing a responsive size mode: we should see if we can add a control for pixel ratio on the simulated device. Per comment โ˜๏ธ we can do this globally with window.devicePixelRatio. Let's see if there's a good way to do it just for our map view.

Add a way to load predefined styles

Following #11, in the same dropdown we should allow for a list of predefined styles that can be loaded in the map pane.

Let's define this as a JSON array of objects defining styles with keys that match the current config format.

There needs to be a way to easily override these defaults. Options for doing so:

  • A config file that is changed at build time
  • A file in public/ that is loaded when the app loads

The latter would be more flexible since the JSON file could be updated separately to the site (for example, if we have a list of released styles that we want to update periodically) without re-building the app.

Add a way to switch between view modes and locations

Let's add a way to move the map to preset locations in order to view specific features or places where it could be useful to compare map styles. In an existing tool this looks like:

image

And we should try to match this. Similarly to #13, this should pull from a JSON file that lists places and types of views, nested in groups as necessary. On select, the map views should change according to the selected preset (center, zoom, pitch, and bearing could all change).

Similarly to #13, it should be made straightforward for project-specific deploys of this tool to set their own presets.

Generalized comparison tool

Now that we've built a lot of compare tools for various clients, we should create a simple and basic client-agnostic tool that we could use for future clients and also potentially make public.

Features:

  • Two linked Mapbox GL maps, so that the zoom, center, pitch, etc is linked between both
  • A configurable list of stylesheets (stored in a separate JSON file probably) that would populate a drop-down menu for each of the two panes
  • A settings bar along the top that contains a geocoder, a configurable list of zoom locations ("scenarios") and other useful information

Add a way to load individual tiles and style them

Would be handy for situations where we are building tiles to debug the tile output.

One way this could work:

  1. Drag-and-drop tile into one of the map panes
  2. Dynamically switch the tile source to the given tile and style it based on the style you have loaded on that map pane

dark mode?

When working with dark styles, it might be nice to have the UI elements have a dark mode too.

Add mobile phone view

Sometimes it's useful to see the maps with the expected size and aspect ratio of a relatively common mobile phone as in this existing compare tool:

image

Let's add a dropdown to switch between swipe and phone views. The above screenshot adds a thick border to the maps to simulate a phone outline but we could also use a transparent image of a phone if that's useful.

Add mirror mode

In addition to existing view modes, let's add a side-by-side mode where the map panes take up proportional widths on the screen, and those widths are not modifiable by the user. The map views should still be synchronized, so their centers and zooms should remain the same when either map is interacted with.

This will initially work with two map panes but will lay the groundwork for > 2 panes (#5).

Update app state when hash changes

Currently we don't watch the hash for changes, so if someone copies and pastes a link into the same tab where the application is already loaded the changes app state doesn't update to reflect the changes present in the hash.

We should update the app to watch for hash changes and update the application state if there are differences between the hash and the current application state.

Google Map falls out of sync on drag

When using a Google map side by side with a Mapbox map, it appears to get out of sync if you drag the map from the Google side. Dragging from the Mapbox side works as expected so long as you haven't triggered this error yet.

To reproduce:

  • Set one map to a Mapbox map and your other map to a Google map
  • Drag the Google map
  • See failed to invert matrix error
  • Try dragging the Mapbox side
  • See same error continue on drag

image

Kapture 2022-06-07 at 18 00 08

Support other map engines

Eventually we may want to support other map engines:

We shouldn't start work on any of these until there's a concrete need. @almccon are there any others you can think of we might realistically want to support? We'd love to think ahead a bit and consider what changes might need to happen to support as many of these as we can.

Add a UI and/or URL parameter for config file

As @aparlato mentioned in #40, it might be helpful to let users modify the config for the app on the fly by changing it through a UI or by passing a URL to a config file.

If we do the URL way, we might actually be able to have project-specific versions of the tool without building and deploying a project-specific version--just point the app at a different config.

Add an easy way to consistently screenshot

When sharing with clients we often end up taking screenshots of the compare tool to share in documents. Is there some way we could make this quicker or easier or just generally more streamlined?

I'm imagining a "take screenshot" button that copies the relevant parts of the page to a canvas element, converts to an image, and copies to clipboard. Might be overkill but this is a common enough use case that it could be worth evaluating.

Info button in phone view overlaps with UI

Describe the issue

I noticed earlier that the info button used in the phone view overlaps the style selection UI element if the window is small enough (see bottom right):

Screen Shot 2022-04-28 at 6 12 38 PM

Watch local style files for changes

Once #11 is complete, let's watch any styles loaded from localhost for changes by polling the file and updating the map when a change is detected. This is a convenience for map development, where a cartographer may be editing the text file for the style. Rather than reload this tool the map should update automatically with any detected changes.

Add a way to load styles on git branches

In other projects we currently have styles in S3 buckets with URLs such as:

https://[bucket-url]/styles/branches/[branch-name]/[style-name]/style.json

And the compare tool has a way to load each style on a given branch name:

image

This tool should support this too.

Ideally, we could write a component that does this using the config to populate the dropdown with the styles that function this way, then replace portions of the URL template (as mocked up above) to get valid style URLs.

Failing that, let's make a component that can be used in project-specific forks of this tool. Project-specific forks would include this component/expand the existing one with the appropriate settings.

Make Prettier configuration consistent

Since we may have local configurations that are overriding each others, let's make a Prettier configuration file the makes them consistent.

I propose adding a .prettierrc that enforces single quotes and avoids parentheses in arrow functions, so:

{
  "arrowParens": "avoid",
  "singleQuote": true
}

How's that sound @aparlato? Any other settings I should include here?

Make a custom/responsive view mode

In addition to existing view modes (phone, swipe, and mirror) let's allow for a custom/responsive mode. I'm thinking this could be similar to the way most devtools work:

image

I think this should work with 1 or 2 map panes as long as when there are 2 map panes we adjust the dimensions of both map panes.

This should persist in the URL.

Create PR template

Per #46

We should create a PR template to remember and stay consistent with steps to address before merging to main:

  • merge latest main
  • update CHANGELOG
  • rebuild package with yarn build-package
  • squash & merge

Allow showing one map pane

Sometimes it makes sense to view one map style at a time.

Let's:

  • keep the default number of map panes at 2
  • make it possible to remove all but 1 map panes

Pull port number for local server

We have special handling to allow users of this tool to input a locally served style and poll on a localhost URL: (eg https://github.com/stamen/maperture/blob/main/src/components/MapStyleInput.svelte#L62).

The typical pattern for this is to serve the tool from the same repo as the styles so that on serving the tool locally, you can access the local styles. Currently it's required that these URLs are hard coded, so a user would write out the URL to specify the port they would expect their style to be served on (eg localhost:8000).

Unfortunately, if the user is already using that port and when serving the tool and styles, they will end up on a different random port and the hardcoded styles will return 404s due to referencing the expected port number rather than the actual.

Is there a way that we can pull the actual port number the tool is running on (and therefore the styles following this pattern)? We should investigate this and implement better handling if so to prevent this kind of confusion.

Retain branch when switching between branch patterns in dropdown

Currently we reset the branch name when switching between branch patterns in the dropdown. This can be pretty tedious if you're switching between styles and want to continue looking at the same branch (eg main).

We should retain the branch name and automatically load the style on the branch once the dropdown changes.

Instructions on using this as a git submodule

I'd like to include this viewer in a separate (private) repo, and I assume doing it as a submodule makes sense.

  • Is there anything we need to do to this repo to use it as submodule? Like, make it public maybe?
  • If there's nothing we need to do, let's write up some brief instructions in the README about how to include this in a separate repo (and get it running to view development stylesheets on localhost)

Remember branch names and autosuggest your most recent branch names

When using branch patterns it can be tedious typing in a branch name, especially one like main that is commonly used. Let's consider adding a feature that

  • tracks which branch names you've used in local storage
  • suggests (with autocomplete? a dropdown?) your most recent branches

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.