Code Monkey home page Code Monkey logo

flowmap.gl's Introduction

flowmap.gl

IMPORTANT: This repository is in maintenance-only mode.

Flow map drawing layer for deck.gl. Can be used for visualizing movement of people (e.g. migration) or objects between geographic locations. The layer is rendered in WebGL and can handle large numbers of flows with a good rendering performance.

Try flowmap.blue for an easy way of publishing a flow map backed by a Google Sheets spreadsheet (no programming skills required).

Check out the live examples Storybook or the minimal example apps: with React, without React.

Features

Given an array of locations and an array of flows between these locations the layer will do the following:

  • Represent the flows as lines of varying thickness depending on the flow magnitudes
  • The flow lines are sorted so that the larger flows are drawn above
  • GeoJSON geometries of the location areas are rendered as polygons
  • Total incoming and outgoing flows for the locations are calculated and represented as circles of varying sizes.

Location totals

Both the incoming and outgoing totals for the locations are represented. A darker outline means that there are more incoming flows, a lighter outline means that there are more outgoing flows.

For instance, below we compare between the evening and the morning commuting behaviors of a large city:

Difference mode

The layer can be used to show the difference between two moments in time.

Usage

First install the required dependencies:

npm install @flowmap.gl/core deck.gl react-map-gl

Then, you can either use as a deck.gl layer or flowmap.gl as a React component:

Usage as a deck.gl layer

With this approach you can use flowmap.gl together with other deck.gl layers.

import { StaticMap } from 'react-map-gl';
import { DeckGL } from 'deck.gl';
import FlowMapLayer from '@flowmap.gl/core';             
import * as ReactDOM from 'react-dom';

ReactDOM.render(
  <DeckGL
    controller={true}
    initialViewState={{ longitude: 0, latitude: 0, zoom: 1 }}
    layers={[
      new FlowMapLayer({
        id: 'my-flowmap-layer',
        locations:
          // either array of location areas or a GeoJSON feature collection
          [{ id: 1, name: New York, lat: 40.713543, lon: -74.011219 }, 
           { id: 2, name: London, lat: 51.507425, lon: -0.127738 }, 
           { id: 3, name: Rio de Janeiro, lat: -22.906241, lon: -43.180244 }],
        flows: 
          [{ origin: 1, dest: 2, count: 42 },
           { origin: 2, dest: 1, count: 51 },
           { origin: 3, dest: 1, count: 50 },
           { origin: 2, dest: 3, count: 40 },
           { origin: 1, dest: 3, count: 22 },
           { origin: 3, dest: 2, count: 42 }],
        getFlowMagnitude: (flow) => flow.count || 0,
        getFlowOriginId: (flow) => flow.origin,
        getFlowDestId: (flow) => flow.dest,
        getLocationId: (loc) => loc.id,
        getLocationCentroid: (location) => [location.lon, location.lat],
      })
    ]}
  >
    <StaticMap mapboxApiAccessToken={mapboxAccessToken} />
  </DeckGL>,
  document.body
)

Usage as a React component

Install this additional dependency:

npm install @flowmap.gl/react
import FlowMap, { getViewStateForLocations } from '@flowmap.gl/react'

const MapVis = ({ width, height }) =>
    <div style={{ width, height }}>
        <FlowMap
          initialViewState={getViewStateForLocations(
            locations, l => l.properties.centroid, [ width, height ]
          )}
          mapboxAccessToken={mapboxAccessToken}
          flows={flows}
          locations={locations}
          getLocationId={l => l.id}
          getLocationCentroid={l => l.properties.centroid}
          getFlowOriginId={f => f.origin}
          getFlowDestId={f => f.dest}
          getFlowMagnitude={f => f.count}
          pickable={true} 
        />
    </div>

The full list of supported props:

interface Props {
  id: string;
  locations: Locations;
  flows: Flow[];
  diffMode?: boolean;
  animate?: boolean;    
  animationCurrentTime?: number;
  animationTailLength?: number;
  colors?: Colors | DiffColors;
  getLocationId?: LocationAccessor<string>;
  getLocationCentroid?: LocationAccessor<[number, number]>;
  getLocationTotalIn?: LocationAccessor<number>;
  getLocationTotalOut?: LocationAccessor<number>;
  getLocationTotalWithin?: LocationAccessor<number>;
  getFlowOriginId?: FlowAccessor<string>;
  getFlowDestId?: FlowAccessor<string>;
  getFlowMagnitude?: FlowAccessor<number>;
  getAnimatedFlowLineStaggering?: FlowAccessor<number>;
  getFlowColor?: FlowAccessor<string | undefined>;
  maxFlowThickness?: number;
  flowMagnitudeExtent?: [number, number];
  locationTotalsExtent?: [number, number];
  maxLocationCircleSize?: number;
  minPickableFlowThickness?: number;
  showTotals?: boolean;
  showLocationAreas?: boolean;
  showOnlyTopFlows?: number;
  selectedLocationIds?: string[];
  highlightedLocationId?: string;
  highlightedLocationAreaId?: string;
  highlightedFlow?: Flow;
  outlineThickness?: number;
  pickable?: boolean;
  onClick?: PickingHandler<FlowLayerPickingInfo>;
  onHover?: PickingHandler<FlowLayerPickingInfo>;
}

Development

Create an .env file in the project root containing one line:

MapboxAccessToken=<your-mapbox-access-token>

Then, run:

yarn install
yarn start
open http://localhost:6006

If you want to make changes to the core and react packages and have them automatically recompiled, run the following:

yarn core-dev
yarn react-dev

Acknowledgements

Many thanks to Philippe Voinov for his help with the first version of the FlowLinesLayer.

License

flowmap.gl Copyright 2018 Teralytics

This product includes software developed at The Apache Software Foundation (http://www.apache.org/).

Portions of this software were developed at Teralytics (http://www.teralytics.net)

flowmap.gl's People

Contributors

dependabot[bot] avatar etra0 avatar fnberta avatar ilya-vassilenko avatar ilyabo avatar neon-ninja avatar peterbraden avatar yuriy-sng 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  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  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  avatar

Watchers

 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

flowmap.gl's Issues

Problem running the dev setup

I don't have a lot of experience in react or node development so this could definitely be a quirk of my particular setup but when running the commands listed in the developing flowmap.gl section of the readme I'm not getting a storybook that knows about flowmap at all...Cannot find module '@flowmap.gl/core' is the error (full details below).

I did also have to manually install the storybook command line tool as well using the below command so I'm not sure if that is related.

npm i --save-dev @storybook/react
Console output
[./node_modules/strip-ansi/index.js] 161 bytes {vendors~main} [built]
[./node_modules/webpack-hot-middleware/client-overlay.js] (webpack)-hot-middleware/client-overlay.js 2.16 KiB {vendors~main} [built]
[./node_modules/webpack-hot-middleware/client.js?reload=true] (webpack)-hot-middleware/client.js?reload=true 7.59 KiB {vendors~main} [built]
    + 793 hidden modules

ERROR in ./src/index.tsx
Module not found: Error: Can't resolve '@flowmap.gl/react' in '/Users/jamescook/git/flowmap.gl/examples/src'
 @ ./src/index.tsx 29:27-55
 @ ./.storybook/config.js
 @ multi ./node_modules/@storybook/core/dist/server/common/polyfills.js ./node_modules/@storybook/core/dist/server/preview/globals.js ./.storybook/config.js (webpack)-hot-middleware/client.js?reload=true

ERROR in ./src/GSheetsExample.tsx
Module not found: Error: Can't resolve '@flowmap.gl/react' in '/Users/jamescook/git/flowmap.gl/examples/src'
 @ ./src/GSheetsExample.tsx 26:27-55
 @ ./src/index.tsx
 @ ./.storybook/config.js
 @ multi ./node_modules/@storybook/core/dist/server/common/polyfills.js ./node_modules/@storybook/core/dist/server/preview/globals.js ./.storybook/config.js (webpack)-hot-middleware/client.js?reload=true

ERROR in [at-loader] ./src/NonInteractiveExample.tsx:52:28
    TS2552: Cannot find name 'FlowMapLayer'. Did you mean 'flowMapLayer'?

ERROR in [at-loader] ./src/NonInteractiveExample.tsx:56:43
    TS2339: Property 'properties' does not exist on type 'Location'.

ERROR in [at-loader] ./src/index.tsx:18:46
    TS2307: Cannot find module '@flowmap.gl/core'.

ERROR in [at-loader] ./src/index.tsx:19:101
    TS2307: Cannot find module '@flowmap.gl/react'.

ERROR in [at-loader] ./src/GSheetsExample.tsx:18:84
    TS2307: Cannot find module '@flowmap.gl/react'.
Child HtmlWebpackCompiler:
                          Asset     Size               Chunks  Chunk Names
    __child-HtmlWebpackPlugin_0  558 KiB  HtmlWebpackPlugin_0  HtmlWebpackPlugin_0
    Entrypoint HtmlWebpackPlugin_0 = __child-HtmlWebpackPlugin_0
    [./node_modules/html-webpack-plugin/lib/loader.js!./node_modules/@storybook/core/dist/server/templates/index.ejs] 1.75 KiB {HtmlWebpackPlugin_0} [built]
    [./node_modules/lodash/lodash.js] 527 KiB {HtmlWebpackPlugin_0} [built]
    [./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {HtmlWebpackPlugin_0} [built]
    [./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {HtmlWebpackPlugin_0} [built]

About AnimatedFlowLinesLayer

hi,I have a problem when i set the property animate=true, the animation looks like and i don`t know how to fix it,please help,thanks.
1571736397

How do I control the thickness of the line ?

Is it possible to control the size of the line?
I'm trying to display flow where weight is not a concern but I still think the lines are too tichk.
Can I change them myself using a custom rule?

Uncaught TypeError: Class constructor CompositeLayer cannot be invoked without 'new'

I'm using the interleaved integration between deck.gl and Maplibre GL: https://deck.gl/docs/get-started/using-with-map

It works fine when I test with an ArcLayer:

import { Map } from "maplibre-gl";
import { MapboxLayer } from "@deck.gl/mapbox";
import { ArcLayer } from "@deck.gl/layers";

const map = new Map({
  container: "map",
  style: "https://basemaps.cartocdn.com/gl/positron-gl-style/style.json",
});

map.on("load", () => {
  map.addLayer(
    new MapboxLayer({
      id: "deckgl-arc",
      type: ArcLayer,
      data: [
        {
          source: [-122.3998664, 37.7883697],
          target: [-122.400068, 37.7900503],
        },
      ],
      getSourcePosition: (d) => d.source,
      getTargetPosition: (d) => d.target,
      getSourceColor: [255, 208, 0],
      getTargetColor: [0, 128, 255],
      getWidth: 8,
    })
  );
});

When I try the same with FlowMapLayer I get an error:

Uncaught TypeError: Class constructor CompositeLayer cannot be invoked without 'new'

import { Map } from "maplibre-gl";
import { MapboxLayer } from "@deck.gl/mapbox";
import FlowMapLayer from "@flowmap.gl/core";

const map = new Map({
  container: "map",
  style: "https://basemaps.cartocdn.com/gl/positron-gl-style/style.json",
});

map.on("load", () => {
  map.addLayer(
    new MapboxLayer({
      id: "deckgl-flow",
      type: FlowMapLayer,
      locations: [
        {
          id: 1,
          name: "New York",
          lat: 40.713543,
          lon: -74.011219,
        },
        { id: 2, name: "London", lat: 51.507425, lon: -0.127738 },
        {
          id: 3,
          name: "Rio de Janeiro",
          lat: -22.906241,
          lon: -43.180244,
        },
      ],
      flows: [
        { origin: 1, dest: 2, count: 42 },
        { origin: 2, dest: 1, count: 51 },
        { origin: 3, dest: 1, count: 50 },
        { origin: 2, dest: 3, count: 40 },
        { origin: 1, dest: 3, count: 22 },
        { origin: 3, dest: 2, count: 42 },
      ],
      getFlowMagnitude: (flow) => flow.count || 0,
      getFlowOriginId: (flow) => flow.origin,
      getFlowDestId: (flow) => flow.dest,
      getLocationId: (loc) => loc.id,
      getLocationCentroid: (location) => [location.lon, location.lat],
    })
  );
});

Screenshot 2021-09-05 at 22 51 41

https://github.com/MasterMaps/flowmap/blob/main/src/Map.js

Any idea what could be wrong?

flowmap.gl does not support react 18.2

when I installed flowmap.gl and run 'npm i flowmap.gl', an error was occured.

npm ERR! Found: [email protected]
npm ERR! node_modules/react
npm ERR! react@"^18.2.0" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer react@"0.14.x - 16.x" from [email protected]
npm ERR! node_modules/flowmap.gl
npm ERR! flowmap.gl@"*" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.

Does flowmap.gl not support higher versions of react16?

How to control speed of animation?

How do I control the animation speed of the flow?
I am currently passing a number variable through requestAnimationFrame but can't seem to control the speed of the animation unlike the example..

Re-evaluate selectors

The Selectors class has a grown quite substantially. Maybe some of the logic doesn't need to be a selector. Re-evaluate the thing.

LocationArea Opacity

Hello,

Is it possible to change the locationArea fill color when they are at normal state without the warning printing?
I am trying to match the locationArea color to match the default mapbox shape tile color and change the opacity when a locationArea is hovered.

For example, I have :
locationAreas: { normal: "rgba(0,0,0,0)" }

And it keeps on giving me this warning, colors.js?4931:96 Invalid color: rgba(NaN, NaN, NaN, 0.5)
I have tried adding the color in as hex #fff0 but no luck..

Thank you in advance!

Add the ability to set selectedLocationIds to null

In the case that I want to handle manually the selectedLocationIds (I believe that's a possibility since we can pass the list as an attribute), there's no way to set selectedLocationIds to null since it checks if it's null before passing it to the state:

if (props.selectedLocationIds && props.selectedLocationIds !== state.selectedLocationIds) {

I believe that the solution should be as simple as changing that line to

if (typeof(props.selectedLocationIds) !== 'undefined' && props.selectedLocationIds !== state.selectedLocationIds)

I tried locally and it works.

Doesn't work with latest version of Deck GL

This layer does not work with the latest version of Deck GL (version 7.2.0 as of 12/08/2019) - highest tested version of Deck GL at the time of writing is 6.3.1

The error message is as follows:
./node_modules/flowmap.gl/dist-esm/FlowLinesLayer/FlowLinesLayer.js Module not found: Can't resolve 'luma.gl'

After installing Luma.gl there is a "multiple versions of luma gl detected" error message.

Non-react version won't animate

Hi - when I try set animate: true in my fork of flowmap.gl-purejs-example (neon-ninja/flowmap.gl-purejs-example@cfdcc0b), I get the following error:

layers-pass.js:186 deck: error during drawing of Layer({id: 'my-flowmap-layer-my-flowmap-layer:::FLOWS'}) TypeError: Cannot read property 'length' of undefined
    at toTypedArray (uniforms.js:37)
    at toFloatArray (uniforms.js:62)
    at eval (uniforms.js:189)
    at Program.setUniforms (program.js:255)
    at Model.draw (model.js:306)
    at AnimatedFlowLinesLayer.draw (AnimatedFlowLinesLayer.js:147)
    at eval (layer.js:883)
    at withParameters (unified-parameter-api.js:96)
    at AnimatedFlowLinesLayer.drawLayer (layer.js:852)
    at DrawLayersPass._drawLayersInViewport (layers-pass.js:175)

Here's a live repro: https://neon-ninja.github.io/flowmap.gl-purejs-example/dist/

how to set opacity, pickable (MapboxLayer interleaving FlowMapLayer)

There is no corresponding option in v6.1.0.
v4.0.0 has a corresponding option.

[my used version v6.1.0]
pickable: false, => not working
opacity: 0.1 ~ 1 => not working

my flowmap.gl viewing logics
=> as in the example in [https://deck.gl/showcases/gallery/mapbox-layer]
deck.gl interleaving(MapboxLayer()) used FlowMaplayer display.

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.