Code Monkey home page Code Monkey logo

react-mapfilter's Introduction

Mapeo View Components

These components are designed for viewing data in Mapeo. They share a common interface:

Common Props

Name Type Default Description
observations Observation[] [] Array of Mapeo observations
onUpdateObservation func Callback fired when an observation has been updatedby the view.

Signature:
(observation: Observation) => void observation: The updated observation
presets Preset[] [] Array of Mapeo Presets with an array of Fields instead of Field ids.
filter array Filter expression used to filter the observations that will be shown.
getMediaUrl func Function called with an id of an image attachment and a size, should return a valid URL to the image.

Signature:
`(id: string, size: 'thumbnail'
getIconUrl func Function called with an id of an icon, should return a valid URL to the icon.

Signature:
(id: string) => string

Contents

<MapView />

Displays observations on a map.

MapView Props

Name Type Default Description
onMapMove func Called with CameraOptions with properties center, zoom, bearing, pitch whenever the map is moved
initialMapPosition object Initial CameraOptions position for map - an object with properties center, zoom, bearing, pitch. If this is not set then the map will by default zoom to the bounds of the observations. If you are going to unmount and re-mount this component (e.g. within tabs) then you will want to use onMove to store the position in state, and pass it as initialPosition for when the map re-mounts.
mapStyle string 'mapbox://styles/mapbox/outdoors-v10' A Mapbox Style URL
mapboxAccessToken string A Mapbox Access Token used to access the style

MapView instance methods

flyTo({center, zoom}, eventData?)

Changes any combination of center, zoom, bearing, and pitch, animating the transition along a curve that evokes flight. The animation seamlessly incorporates zooming and panning to help the user maintain her bearings even after traversing a great distance, takes the same options as the flyTo method of mapbox-gl-js

fitBounds(bounds, options?, eventData?)

Pans and zooms the map to contain its visible area within the specified geographical bounds. This function will also reset the map's bearing to 0 if bearing is nonzero, takes the same options as the fitBounds method of mapbox-gl-js

<MediaView />

Display a grid of all the media attachments from the observations.

MediaView Props

MediaView does not currently have any additional props beyond the common props above.

<ReportView />

Display observations as a report that can be printed.

ReportView Props

ReportView shares several props with MapView. These props apply to the inset map in the ReportView.

Name Type Default Description
onMapMove func Called with CameraOptions with properties center, zoom, bearing, pitch whenever the map is moved
initialMapPosition object Initial CameraOptions position for map - an object with properties center, zoom, bearing, pitch. If this is not set then the map will by default zoom to the bounds of the observations. If you are going to unmount and re-mount this component (e.g. within tabs) then you will want to use onMove to store the position in state, and pass it as initialPosition for when the map re-mounts.
mapStyle string 'mapbox://styles/mapbox/outdoors-v10' A Mapbox Style URL
mapboxAccessToken string A Mapbox Access Token used to access the style

react-mapfilter's People

Contributors

gmaclennan avatar okdistribute avatar thibautre 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-mapfilter's Issues

Custom fields

It would be good to add custom fields which are derived from existing fields. Could use some kind of simple variable substitution like: Location: {{village}}, {{region}}, {{country}}

Field display settings

We need a settings dialog for deciding which fields are visible in the detail / report views, with also the option to rename the field names to something more human-readable.

Should be a list view with toggle switch and text field for entering new name.

Persist config

should be easy to use redux-persist to persist some of the state to localstorage - the main thing is keeping config between sessions.

Controllable filterFields and filters

Feature Request:

Currently, it seems that the FilterPane can only be populated using a best guess algorithm or by explicit user selection via settings. Allow the MapFilter props for filterFields and filters to be controllable. The idea behind this would be to:

  • Supply the MapFilter component with a set of filters that initially appear in the FilterPane
  • This set of initial filters should be able to take an initial value as well, i.e. checked or not checked for discrete filters, or a date range (value and min/max) for date filters.
  • Consumers should be able to listen for changes to these filters.

Support delimited fields

ODK Collect returns data from multi-select fields as space-delimited fields, e.g.

{impacts: 'deforestation contamination loss_of_biodiversity'}

This is a little tricky to use heuristics to recognize, so short-term we will probably need to manually define which fields are space-delimited.

They are also tricky to filter. We are restricted in this new version by Mapbox's filter language which only does exact matches on fields - for performance reasons I assume.

I think the solution is to flatten these fields into multiple fields e.g.:

{
  'impacts.0': 'deforestation',
  'impacts.1': 'contamination',
  'impacts.2': 'loss_of_biodiversity'
}

Then set the same filter on each of those fields. With datasets when many options are selected in a multi-select this might be a performance issue, but we will have to see. In many datasets there will only be max 3-4 options selected - in our field analysis we can track the max number so we only need ot set that number of filters.

Remove online dependencies

Spotted so far:

  • Roboto (Google Fonts) in #54
  • Intl polyfill
  • resizer.digital-democracy.org
  • Mapbox style mapbox://styles/gmaclennan/cio7mcryg0015akm9b6wur5ic
  • Vector tiles (source defined in style)

Controllable Map Properties

Feature Request:

Allow the following map properties to be controlled (i.e. being able to supply initial values for these and subscribe to the map to listen for changes to these properties)

  • Map Center Point (lat/lng) (listen for move changes)
  • Map Zoom (listen for zoom changes)

This is critical for users where a small set of custom tiles is being used and not all zoom levels are provided with the tile set.

Add responsive image component

Displaying images could be more efficient. We use our own resizing service which is running on http://resizer.digital-democracy.org/ to get thumbnails and previews. We need an <Image> component that uses [react-dimensions](https://github.com/digidem/react-dimensions] to choose the best size to request. Our resizer currently whitelists certain domains - we should detect 403 errors and just load the original full-size image in that case.

We could speed things up more by keeping track of sizes of image that have been loaded and when requesting a larger image show a smaller one that will be in the browser cache first whilst the larger version loads.

Fit columns in detail view

We should better fit the left column in detail view so that it auto-fits the contents, rather than both columns being 50% width each.

mapfilter-detail-view-clip

Report view

Report view should be similar to the print view in the original Mapfilter:

mapfilter old print view

In this new version the report view is going to be live-filterable, so we need to use react-virtualized so we don't render every feature, only the ones in the viewport.

Needs a selector that uses feature-filter to select filtered features to render.

Update CHANGELOG.md

@jlev can you update the CHANGELOG.md with the changes as you go? I've been trying to standardize the CHANGELOG is all our repos to this: http://keepachangelog.com

Let's keep semver, as much as it makes sense for a front-end app like this. I don't know what a breaking change would be, but minor for features added, patch for bug-fixes. I think as you do this work right now we shouldn't call it a release, but probably each PR should include an update to the CHANGELOG with the feature added under "Unreleased" and a link back to the PR.

Add data loading options

Currently the sample data is hard coded in. We need to implement async action creators for loading geojson from a url and parsing (dates need to be coerced).

We should use Auth0 to get auth tokens for loading a geojson from Github or other authenticated service.

We need an "empty" page that allows the user to select a local file, enter a URL, or load the sample data.

Share config via urls

We should have a settings page for sharing config, which will create a url with the config encoded as json and base64-url as a url parameter, then a user can just click that link and import the configuration settings.

Allow any vector tile style

Right now the marker sprites need to be added to any vector tile style that is used. mapbox-gl-js currently only allows one sprite sheet per style, so you need to use Mapbox Studio to add the marker sprites to the style online. Ideally we want to enable any custom style to be used as a background in MapFilter, without modifying the sprites.

My current strategy for solving this is to concatenate the remote sprite file from the map style with the sprite for the marker sprites, using concat-sprites. This can be done dynamically in the browser, but getting the new merged sprite into mapbox-gl-js is a challenge. We could serve the sprite over an objectURL but mapbox-gl-js currently expects both the json and png to share the same url root. We could serve both using Service Workers, but with limited browser support, or create a fork of mapbox-gl-js and write a custom image_sprite.js. I'm thinking the latter might be the easier (hacky) solution for now. Hopefully Mapbox will support dynamic sprites in the near future.

Filter settings

We need a settings dialog to change which fields can be filtered. Currently we make a best-guess choice of filters to show.

This should be a dialog that shows a list of all filterable fields with a toggle switch to turn the filter on or off.

Should also have options to define which fields are used for:

  • color coding
  • titles
  • subtitle

Discuss: Handling photos

To discuss:

I was able to get pictures to show by mapping picture: <string> to picture: { url: <string> }, then using the fieldTypes prop to tell MapFilter that pictures.url was an image. Is there an easier way to do this, or is this THE way?

Add filter / view sharing

We can encode the current filter using base64-url and store it as a url parameter, then add a hook in componentDidMount() to load it from the url and update the store. The map state is automatically stored in the url too. URLs will be long, so we should only generate when needed - probably some kind of share button on the app bar. Could also use a link-shortening service.

Add print button and print styles

We can use react-match-media to render the page specifically for printing. This will be necessary since the report view will not render all features by default. react-match-media allows us to hook into the user print event and render the page specifically for that, see: https://www.tjvantoll.com/2012/06/15/detecting-print-requests-with-javascript/

Print view for the map page will be trickier. We probably need to show a modal that allows tweaking the layout on the page before printing. Longer term we will want to tile larger maps onto multiple sheets, using map.getCanvas().toBlob() multiple times to get png tiles and printing one per page.

v1.0 rewrite [WIP] / not yet started

Writing this app has been a lesson in how quickly a Backbone / MVC app can race out of control and become hard to maintain. v1.0 will be a re-write using React and Flux. By building each part of Mapfilter as an individual component with clearly defined specifications it is much easier for others to contribute without breaking other parts of the app, and it means that we can re-use different components to mix-and-match our own custom builds of Mapfilter for different use cases and integration with a broader "monitoring platform" according to local community / partner needs.

The shortlist I have for a framework for flux architecture:

A lot of these I think use too much "magic"- especially reflux - and whilst that can minimize typing, it is another thing to learn. Tom MacWright from Mapbox in this talk (terrible quality) explains why they are using just vanilla Flux from Facebook.

For me minimal flux seems the best option right now. It provides some minimal helpers around the core flux ideas, and the source is simple to understand and it is minimal enough that we do not need to become dependent on the framework moving forwards.

There are some helpful React components already built:

For filtering I think we should keep using crossfilter because it is still faster than anything else.

We need a way to pass filter definitions through the app. Because of the one-way data flow the filter component (the UI for building the filter) needs to pass the filter query through the dispatcher to crossfilter. Feature-Filter is a simple way of defining features and should meet our needs. I'm not sure if we should follow their approach of building a string and eval'ing, or build a mini language interpreter.

For the UI I have created some mockups in #14 using Google's material UI principles. Without a UX designer on the team right now I think this is the easiest way of us getting some way towards a good UI. We can use material ui which is a collection of material design components implemented in React.

The rough architecture will be, which each being its own self-contained compent:

  • Views - which just render the list of data they are passed:
    • Map View (wrap react-leaflet)
    • List View (wrap fixed-data-grid)
    • Photo View (wrap fixed-data-grid)
    • Print View (will need to write our own component)
  • Filter - need to be able to choose fields to filter by, and then filter continuous or discrete data as in the current version of Mapfilter
  • Layer chooser - need to be able to choose which background tiles to use, and load and choose overlays to filter by
  • App bar / toolbar.

We will have a central store wrapping crossfilter which will respond to events from the filter component and return a list of filtered points.

I will start laying down some bare-bone architecture in the v1.0.0 branch soon.

Add range filter for numbers

We don't have a filter component for numeric fields yet. Simplest could just be two numeric form fields for min & max, but better would be a slider.

Removing a filter field from the UI should remove the filter

Expected behaviour:

When you open the settings "Change Filter" and turn off a filter for a field, it should be removed from the UI, and any filters that were set for that field should be removed.

Actual behaviour:

Turning off a field with filters set in the filter settings does not remove it from the UI. After turning it off once all the filters are removed it magically disappears.

Possible solution:

Use the UPDATE_FILTER action to reset filters for a field that is removed from the UI.

[WIP] Redesign material design

I have started a redesign following Google's material design principles. The aim is improve the user experience and add new functionality, such as a photos and list view. I am also designing with mobile in mind, so that this app will also work on mobile.

screenshot

There is still a lot to figure out, but an initial interactive prototype is here:

MapFilter redesign interactive prototype

  • Map View
    • Map marker hover
    • Map marker click
    • Map photo zoom
  • Photo View
  • List View
  • Print View
  • Filter menu
  • Map layer chooser
  • Login screen

All feedback welcome. Discussion here. You can also add annotations to the prototype.

Explicit selection of title, subtitle fields

Feature Request:

There seems to be a fieldMapping attribute that can be used to declare which fields appear as title, subtitle, etc on feature popups on the MapView and in the ReportView. Can this mapping be exposed as a controllable prop such that one can select which field to use as title, subtitle, etc?

Display options for filter labels

Feature Request:

Allow the options for discrete filters to have custom labels. This would allow for translations or custom formatting to be applied.

Specifically, the issue I am having is with the "Happening" field -- a special field that contains both a label and a color in the format ${label}^${color}. The displayed label shows the full string, where I would want to have the ^${color} portion removed for display purposes. Having the color information is important, though, for correlating the field color with MapFilter settings.

mapfiltercolors

Support custom tile layers

We should support custom tile layers and have initial options that include both satellite tiles and vector tiles. We should store background tile options on state so that we can support dynamically adding new layers and sharing config that has different tilesets.

To do this with the flexibility to accept any style layer we will need to fix #51 first.

Support 0 or >1 photos

Currently we assume there is a photo linked from each feature. We need to display the feature details with no media, and also show multiple photos in detail view using nuka-carousel

Use lo-res images in info pane

Right now we load the full-res image in the info pane every time we hover a point. This can take a while to load since original images are about 2Mb. We should load a thumbnail image. Depends on digidem/wapichanao-data#2

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.