GithubHelp home page GithubHelp logo

mapbox / mapbox-gl-js Goto Github PK

View Code? Open in Web Editor NEW
10.7K 10.7K 2.2K 498.16 MB

Interactive, thoroughly customizable maps in the browser, powered by vector tiles and WebGL

Home Page: https://docs.mapbox.com/mapbox-gl-js/

License: Other

JavaScript 90.47% HTML 5.94% GLSL 3.07% Shell 0.06% CSS 0.34% EJS 0.13%
3d javascript maps webgl

mapbox-gl-js's Introduction

Mapbox logo

Mapbox GL JS is a JavaScript library for interactive, customizable vector maps on the web. It takes map styles that conform to the Mapbox Style Specification, applies them to vector tiles that conform to the Mapbox Vector Tile Specification, and renders them using WebGL.

Mapbox GL JS is part of the cross-platform Mapbox GL ecosystem, which also includes compatible native SDKs for applications on Android, iOS, macOS, Qt, and React Native. Mapbox provides building blocks to add location features like maps, search, and navigation into any experience you create. To get started with GL JS or any of our other building blocks, sign up for a Mapbox account.

In addition to GL JS, this repository contains code, issues, and test fixtures that are common to both GL JS and the native SDKs. For code and issues specific to the native SDKs, see the mapbox/mapbox-gl-native repository.

Mapbox GL JS gallery of map images

Caption: (Mapbox GL JS maps, left-to-right, top-to-bottom): Custom styled point clusters, custom style with points, hexbin visualization on a Dark style map with Popups, data-driven circles over a raster layer with satellite imagery, 3D terrain with custom Markers, Mapbox Movement data visualization.

License

Mapbox Web SDK

Copyright © 2021 - 2023 Mapbox, Inc. All rights reserved.

The software and files in this repository (collectively, “Software”) are licensed under the Mapbox TOS for use only with the relevant Mapbox product(s) listed at www.mapbox.com/pricing. This license allows developers with a current active Mapbox account to use and modify the authorized portions of the Software as needed for use only with the relevant Mapbox product(s) through their Mapbox account in accordance with the Mapbox TOS. This license terminates automatically if a developer no longer has a Mapbox account in good standing or breaches the Mapbox TOS. For the license terms, please see the Mapbox TOS at https://www.mapbox.com/legal/tos/ which incorporates the Mapbox Product Terms at www.mapbox.com/legal/service-terms. If this Software is a SDK, modifications that change or interfere with marked portions of the code related to billing, accounting, or data collection are not authorized and the SDK sends limited de-identified location and usage data which is used in accordance with the Mapbox TOS. [Updated 2023-01]

mapbox-gl-js's People

Contributors

1ec5 avatar akoylasar avatar alexey-romanov avatar anandthakker avatar andrewharvey avatar ansis avatar astojilj avatar avpeery avatar bhousel avatar brunoabinader avatar chrisloer avatar dependabot[bot] avatar dmitrig01 avatar endanke avatar jfirebaugh avatar jtorresfabra avatar karimnaaji avatar katydecorah avatar kkaefer avatar mikemorris avatar mollymerp avatar mourner avatar mpulkki-mapbox avatar scothis avatar snailbones avatar stepankuzmin avatar tatsvc avatar tmcw avatar tristen avatar yhahn 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  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

mapbox-gl-js's Issues

Vector tile analysis

@kkaefer has been pining for some stats regarding our vector tiles. I'm guessing he's interested in maxes but some kind of median/average value would be useful as well.

  • Determine sample size/method -- e.g. grab tiles from major cities, minor cities, across several zoom levels ?
  • Decide on necessary analyses (number of features, number of coordinates per feature, etc.)
  • Build out basic script to fetch and run analysis

Guessing even without strong decisions around these we can adjust as it becomes clearer what kind of info is necessary.

Label rendering

Figure out approach:

  • render the text to a texture with 2D context, and load it.
    • this works sufficiently well, and texture sizes of 2048x2048 are supported
      by all webgl implementations. we can fit a lot of labels on 2048x2048 pixels
    • we could try rendering every glyph separately, so we have a texture atlas and
      don't need to render every label separately, potentially saving a lot of memory.
      the drawback with this is that one glyph currently requires about 64 bytes of
      memory for all the texture coordinates and offsets
      we could place the labels in cpu time and not use the shaders to calculate the
      position, then use STREAM_DRAW mode to feed the new placements to the gpu and
      reduce the required memory per glyph
    • halos can be easily rendered with strokeText, but the halo can't grow too
      large because the winding fill mode (can't be changed?) inverts overlapping
      strokes
    • issues:
      • canvas 2D context has limited text styling options, e.g. kerning doesn't
        work in canvas.
      • texture has 32 bit depth, but we really just need 8 bit depth because we're
        defining the color via the shader anyway and just the image as an alpha mask
      • rotated labels can't be easily added to the texture by just using the bbox,
        because we'd waste a lot of space.
      • we have to find a good way for estimating the bbox with halos
      • measureText() is not accurate, because it measures the sum of glyph advances,
        but not the overall bounding box width of the text
  • use glyph metrics extracted with freetype to do glyph rendering and placement
    rather than using 2D canvases .fillText() mode
    • advantages:
      • we can correctly pack glyphs into the canvas, even for fonts that are exceeding
        the regular glyph advance bbox. those are usually cursive fonts like Zapfino.
      • we could get correct kerning for labels and correct subpixel placement
      • we can use these metrics to compute rotated labels with their actual, rotated
        bbox rather than the non-rotated bbox.
    • disadvantages:
      • filling every character separately
      • subpixel placement for glyphs is hard because we couldn't reuse glyphs
        across labels. rather, we'd have to render every label separately into the
        textures (as we do currently). we could try mipmapping for horizontal
        subpixel placement, but always force to an integer coordinate for vertical
        placement, so that we don't get blurry baselines
  • we could compile freetype to javascript and use that in a web worker to do all
    of that. this would allow us to accept arbitrary fonts and be very exact about
    their metrics.
  • figure out a way to use harfbuzz for non-latin text, or for automatic replacements
    like ligatures. we probably need someone to tell us more about non-latin text.

Rotation key sometimes gets stuck

Sometimes, when you rotate the map, they keyup event isn't fired. When you then want to pan, you're rotating instead. Maybe we should change rotation to the right mouse key rather than relying on modifier keys.

Decisions

Skia or Agg?

There are sample apps for both in the repository. Speedwise, Skia has a slight edge (~8%) on my machine with the current build settings (I haven't investigated possible ways of tuning it), but it's very narrow. The binaries using the Skia renderer, however, are a lot larger; the stripped binaries are 1283 KB vs. 158 KB.

Skia has includes text rendering support, so we don't have to mess around with freetype and is under active development in contrast to Agg. However, that might also mean that rendering results produced by Skia are more likely to change.

Shared renderer

Currently, the renderer (Agg/Skia) is statically linked into the binary (or the .so files we would produce in an actual setup). This gives us a lot of renderer stability (e.g. future updates to Skia wouldn't break our existing maps), but duplicates the renderer's code for every single map. We could use the renderer as a shared library, so we'd only have one single instance of the renderer loaded into memory. Sharing a renderer also allows us benefit from bug fixes and speed improvements across all of our maps and not just those that were uploaded after the fact.

I think we /should/ share the renderer across maps and potentially risk slightly broken maps. I assume that the only thing that might change about the renderer are minor visual things like antialiasing, miter calculation, or pixel grid alignments. We'd still compile all of our placement algorithms and vertex handling code into every single compiled map.

Portability

When compiling maps into shared objects (.so files), they aren't portable anymore and tied to the system's architecture and standard library. We could probably still share compiled maps on our infrastructure given that it's pretty homogenous, but we would likely run into trouble when upgrading the operating system or anything else on our machines. In that case, we'd have to recompile the maps, but to maintain backwards-compatibility, we'd use the llmr state on the day the user created/uploaded the map. This means, we'd have to maintain legacy software and potentially port our own software to new platforms every couple of months or years. This is less of an issue if we use a shared renderer, but it still /is/ an issue.

Lua bindings

Rather than producing a separate .so file for every compiled map, we could also look into creating Lua bindings for Skia or Agg and then use Lua rather than actual compiled code. The advantage is that we don't have to generate/compile C/C++ code for every map and we'd likely run into fewer legacy maintenance issues when having our algorithms in Lua. When using LuaJIT, we should get a pretty decent performance close to native code as LuaJIT compiles the Lua file (which includes all the vertex processing + placement algorithms) into native bytecode on the fly.

Lua bindings

Satellite layer

We should add the capability to display satellite (or generic raster) imagery alongside our maps. We could either do this by integrating leaflet and doing all the tiling in leaflet (#36), or by loading the raster tiles as a texture (cross domain problems!).

Tests

Also future-ish but as soon as we have any documented API surface we should start on this.

Direction

compile c++ application

  • use agg, freetype, etc. directly?
  • use a stripped down version of mapnik?
  • benefits
    • exact code least amount of things that could change
  • drawbacks
    • system-specific binary
    • lots of executable code needs to be loaded/unloaded into memory
    • renderer speedup won't help old maps

lua-scripted llmr

  • wrap agg + freetype + pbf and expose to lua
  • benefits
    • fast?
    • portable
  • drawbacks
    • lots of custom code
    • wrapper might change

Canvas-based renderer

  • benefits
    • could work in the browser
    • existing canvas implementation unlikely to change, would break lots of other scripts
  • drawbacks
    • slow? (see kothic)

=> Implement canvas interface with agg?

Recombine split up streets

for label placement on short broken segments of streets (e.g. in a street grid), we'd have to recombine all segments of a street before placing labels so that we get a large enough straight line (this is something we could use for mapnik too!) recombination could be done on a vector tile level by joining all lines that shared the same name and have at least one vertex in common.

Wrap world

If the user zooms out enough, we should start wrapping the world and then confine the internal transform coordinates (and the url hash) to -180...180 (it'll look the same if we wrap)

'make' stops for tessellate branch

cd proto && protoc vector_tile.proto --cpp_out=../src
mv src/vector_tile.pb.cc src/vector_tile.pb.cpp
make: *** No rule to make target `deps/poly2tri/libpoly2tri.a', needed by `server'.  Stop.

/cc @kkaefer

HarfBuzz

@springmeyer, you were talking about replacing ICU/freetype with HarfBuzz. Could you please write up your thoughts about this or point me to where the reasons are explained?

Lower memory usage

  • find a way to have the original compressed buffer gc'ed, so that we lower the overall memory usage
  • use a mru cache to avoid reparsing the tiles

handle 3d context losses

there is a possibility for a rendering context to get "lost" due to certain events like low memory, browser tab changing or any other reasons. in those cases, the browser sends a "context lost" event that we should handle. in this case, we have to reacquire the context and begin setting up the map again. shouldn't be too hard. there's also an API that simulates context losses for debugging purposes.

Styling language

Going to look into this today, feel out the difficulty of styling a map without editing the source of this project.

Easing functionality

Future-ish. I guess the core question is whether we want to treat the map object and interaction code in this project as just a bootstrap for the renderer, or expect this project to eclipse other 'map frameworks'

rotation into canada bug

The video isn't perfectly clear, but basically somehow if you rotate just right, at some point it snaps to somewhere else (the video starts out in California and somehow ends with the map centered in Canada). Somehow where ever this bug happens, it always goes to somewhere in Canada.

Geometry issues

This ticket is for collecting issues we find with the geometry in our vector tiles:

  • make sure the polygons for a zoom level aren't overly detailed. this is currently happening with zoom level 6 for example
  • fix clipping; this introduces very weird artifacts that are visible in our mapnik-rendered image tiles, but especially apparent when zooming in
  • find other ways to reduce the buffer size; oscim's data sizes are about 20x smaller than ours!? (when zooming into a particular point from the world view)
  • don't reencode the street lines again for label layers; find a more efficient way to define label layers
  • ideally, we'd only load every other (or every third) zoom level rather than every zoom level. minimum rendered tile size should be something like 512 or 1024 so that we only need to load 1-2 tiles per map view
  • remove objects with only coincident points that should be lines. this happens when scaling very small lines and rounding them to integers. we have code that eliminates duplicate points that result from this, but we don't have any code that removes entire line segments like this
  • combine long lines, there are thousands of very short line segments that should be joined. this allows us to draw proper line joins
  • merge double-carriageway roads on low zoom level tiles
    • use centerline of adjacent roads
  • combine long road segments in a tile on low zoom levels
    • easier simplification?
  • broken border/admin lines on z3, z4, z5
  • broken roads (motorway vs. motorway_link?, bridges!)
  • merge large water polygons that have the same tags. This allows us to draw fewer edge antialiasing fragments and removes weird artifacts.
    • many water polygons are duplicates and overlapping, sometimes because the OSM source data is that way and sometimes because we have generalized and non-generalized polygons in the same data source
    • we store lots of small river polygon segments, but not the actual rivers in low zoom levels. might be good to store them instead and throw away riverbank polygons (and just retain the lakes)
    • a better metric to determine what riverbank polygon to retain, we should use something like the maximum circle we can fit into the polygon at any location (e.g. using a delaunay triangulation?)
    • no overlapping rtree polygons
    • line thinning for narrow rivers => convert to waterway
    • prevent "broken" rivers, water polygons that are part of a river but are
      too small to be included in a tile

Survey presence of STENCIL_BUFFER across WebGL implementations

this is why I changed it to use the depth/z buffer so that all fragments are discarded that are outside the prerendered tile outline. this is usually the stencil buffer's task, but we use the depth buffer instead because the stencil buffer is not a guaranteed part of webgl (TODO: verify this, and gather statistics on whether this is really the case)

Improve data generalization

  • make sure the polygons for a zoom level aren't overly detailed. this is currently happening with zoom level 6 for example
  • fix clipping; this introduces very weird artifacts that are visible in our mapnik-rendered image tiles, but especially apparent when zooming in
  • find other ways to reduce the buffer size; oscim's data sizes are about 20x smaller than ours!? (when zooming into a particular point from the world view)
  • don't reencode the street lines again for label layers; find a more efficient way to define label layers

Tile doesn't render with no data

Sometimes, when viewing empty tiles, the tile doesn't render at all. This happens when the server returns an empty file -- presumably because there's no data in that tile. However, we should still show something.

Currently, it looks like this:

What's happening is that since the tile is empty, xhr.response is null, and the second branch is getting in this if statement: https://github.com/mapbox/llmr/blob/gl/js/vectortileloader.js#L146-L150. That gets passed back as an error when in fact there is no error -- just no data at all.
I have a feeling the server is at fault -- the client needs to at least know what layer to color in...

Label placement

  • currently, labels are only placed to the right hand side; code up a way to try out alternative label positions
  • figure out what to do when the user zooms the tile so that it's smaller than the initially labels places
  • handle tile bounding boxes correctly; use other tile's tree to do collission detection
  • for label placement on short broken segments of streets (e.g. in a street grid), we'd have to recombine all segments of a street before placing labels so that we get a large enough straight line (this is something we could use for mapnik too!) recombination could be done on a vector tile level by joining all lines that shared the same name and have at least one vertex in common
  • label placement for rotated rects, e.g. for street names:
    • find an algorithm that extracts all parts of streets that are straight enough to have labels at the top zoom level, or at lower zoom levels
    • do collision detect with rotated rects
    • could be easier if we do collision detection with every (non-rotated) glyph bbox rather than one bbox, even for glyphs that are rotated (like mapnik)

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.