Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Canvas type #3765

Merged
merged 24 commits into from
Jan 20, 2017
Merged

Canvas type #3765

merged 24 commits into from
Jan 20, 2017

Conversation

lbud
Copy link
Contributor

@lbud lbud commented Dec 8, 2016

Closes #3580.

This adds a canvas source type, which can be used in raster layers like existing image and video sources.

To be resolved:

  • We have no solid plan for parity with GL Native for this feature. It's also not something that will be very useful in api-styles, because we're loading same-page-based canvases, unlike other sources which often live in the ☁️. These things are weird and we should make sure we're comfortable with this approach.
  • add tests
  • add example

Related feature but not a blocker: raster querying #1404 (came up in #3745)

Launch Checklist

  • briefly describe the changes in this PR
  • write tests for all new functionality
  • document any changes to public APIs (generated)

@lucaswoj
Copy link
Contributor

lucaswoj commented Dec 9, 2016

Do we want to support webgl contexts (less straightforward, not necessarily the use case we're targeting, and likely to be obseleted by custom layer types)?

Based on what I've heard about perf, we don't need to go out of our way to support WebGL canvases. If we get some support for free from texImage2D, that's a nice bonus.

@jliebrand
Copy link

Curious: will this feature allow me to draw to a 2d canvas, and have it show up on the map (correctly zooming/panning/etc)?

Eg will this allow me animate something on the chart, unrelated to geojson and webgl?

@lucaswoj
Copy link
Contributor

Curious: will this feature allow me to draw to a 2d canvas, and have it show up on the map (correctly zooming/panning/etc)?

Yes!

Eg will this allow me animate something on the chart, unrelated to geojson and webgl?

Yup 😄

@jliebrand
Copy link

jliebrand commented Dec 17, 2016 via email

@@ -45,6 +45,7 @@
"babel-eslint": "^7.0.0",
"benchmark": "~2.1.0",
"browserify": "^13.0.0",
"canvas": "^1.6.2",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOTE: this is a relatively nontrivial dep for something just used in one test…discuss

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you create a fake Canvas API using Sinon?

@lbud
Copy link
Contributor Author

lbud commented Jan 5, 2017

  • As currently implemented, this can support reading from either 2D or webgl canvas contexts. 2D is ideal and more performant and, in fact, gl.texImage2D / gl.texSubImage2D can take an HTML5 canvas element as an argument, meaning we don't even have to manually copy pixels. (When using a webgl context however this causes very incorrect rendering/artifacts.) Do we want to support webgl contexts (less straightforward, not necessarily the use case we're targeting, and likely to be obseleted by custom layer types)?

Alright, I simplified this a lot by using texImage2D/texSubImage2D no matter the context/not even doing context detection. This also allows us to take out the dimensions property since we don't manually readPixels. It performs fine on my simple canvas debug pages but I haven't made anything super flashy to stress test it with yet… We could prohibit webgl contexts, or we could just caveat emptor it. 🤔

Once I pull together a good example and tighten up the docs this should be good to 👀 & 🚢

  • We have no solid plan for parity with GL Native for this feature. It's also not something that will be very useful in api-styles, because we're loading same-page-based canvases, unlike other sources which often live in the ☁️. These things are weird and we should make sure we're comfortable with this approach.

🤔

@lbud
Copy link
Contributor Author

lbud commented Jan 19, 2017

Rebased; I think this is good to go. I actually think this is fine to merge without an example, at least for now. I do have an example I've been playing around with, but it depends on loading 60-some images…this can be a follow-up task 🤔🌩

Secondly, tests were failing by hanging/timing out at the ignored line-width property function test because the spec canvas_type branch is rebased off of current mb-pages, which says line-width property functions are not supported (they were rolled back). The suite implementation still renders even ignored tests, and just doesn't count them against the fail count. But in this case, it errors and hangs on validating the line-width property function test. It's not the cleanest, but I added a commit to this PR that creates a style separately of the map for each render test and then adds it to the map, so that we can pass in a validate boolean based on whether a test is ignored. 👍/:-1:? (This test has been hanging locally for me for weeks 😕)

@lucaswoj lucaswoj changed the title [not ready] Canvas type Canvas type Jan 19, 2017

if (!this.tile) return; // not enough data for current position
this._prepareImage(this.map.painter.gl, this.canvas, this.resize);
this.resize = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe convert this to a local var?

}
if (this._hasInvalidDimensions()) {
return this.fire('error', new Error('Canvas dimensions cannot be less than or equal to zero.'));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe make this a no-op instead of a failure

classes: options.classes,
interactive: false,
attributionControl: false,
preserveDrawingBuffer: true
});

const _style = new Style(style, map, { validate: !options.ignored });
map.setStyle(_style);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use skipped flags to get around validating these tests without adding new code

* make resize a local var
* fail silently on invalid canvas dimensions
* use 'skipped' rather than changing suite_implementation for line-width property fn test
Copy link
Contributor

@lucaswoj lucaswoj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a regression test that also uses a data-driven line width. If you skip that one, everything should be 🍏 and you're clear to :shipit:!

@lbud
Copy link
Contributor Author

lbud commented Jan 20, 2017

There's a regression test that also uses a data-driven line width. If you skip that one, everything should be 🍏 and you're clear to :shipit:!

aha 🕵️‍♀️ I saw line-width was still failing and didn't get a chance to look into it yet. Alright, will do!

@lbud lbud merged commit 5082fec into master Jan 20, 2017
@lbud lbud deleted the canvas_type branch January 20, 2017 19:57
@averas
Copy link
Contributor

averas commented Jan 26, 2017

This is awesome! One use case I feel I haven't found an optimal solution for has been to effectively show small thumbnail images in Mapbox GL JS, to create maps like this:

screen shot 2015-06-03 at 20 53 08

While it is possible to come up with something quite close to that with the marker plugin I found it hard to make a seamless experience that switches between symbols (dots/icons) and thumbnails based on zoom, and the markers are not data-driven in a similar manner as with other sources which makes it tedious to add and remove them based on map interaction.

Could the canvas source type be used to create a data driven thumbnail map like the one above?

@lucaswoj
Copy link
Contributor

@averas

It would be possible to create a canvas source which renders and places all of the thumbnails. I anticipate the difficulty of implementing this (you'll need to work with the canvas API and explicitly do some projections) may outweigh the benefits.

Have you tried using implementing this using the image source?

@averas
Copy link
Contributor

averas commented Jan 27, 2017

@lucaswoj

Have you tried using implementing this using the image source?

No..? The image source can only reference a single image, and once created can't be mutated (one has to replace the source to update the image). I imagine it would be quite ineffective to push/pop potentially hundreds of sources/layers when panning/zooming a map, but I may be wrong?

I think the best Mapbox GL JS examples of this are:
https://www.mapbox.com/blog/custom-markers-mapboxgl/
https://www.mapbox.com/mapbox-gl-js/example/custom-marker-icons/

.. but again, both of these use markers and are therefore 1) not data driven by sources (i.e. you have to micro manage the marker behaviour with discrete code hooked into map interaction and other events), and 2) inherently not benefited by WebGL as they are based on regular HMTL in the DOM.

What I typically do in a case like this is falling back to a data driven, projected SVG overlay using d3.js. That often solves some of the hurdles, such as projection and a declarative data-driven approach, however, it obviously lacks the ability to work directly with Mapbox sources, such as vector tiles, and you are still not benefiting from WebGL.

@yangdonglai
Copy link
Contributor

marked and keep attention

@lbud lbud restored the canvas_type branch August 16, 2017 18:17
@jfirebaugh jfirebaugh deleted the canvas_type branch September 21, 2017 17:03
@bennlich
Copy link

(you'll need to work with the canvas API and explicitly do some projections)

@lucaswoj I'm working with a canvas source right now, wondering this exact thing. I how do I project from lat/lng to canvas coordinates?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

"canvas" source type
6 participants