React-mapbox-gl: Support for adding custom image at runtime using map.addImage

Created on 9 Sep 2017  路  15Comments  路  Source: alex3165/react-mapbox-gl

Mapbox-gl allow to add custom images at runtime using loadImage and addImage, I don't think loadImage is necessary, instead user should pass an HTMLImageElement to addImage and query for the image by their own using new window.Image().

In term of API I am not sure what is best between using prop of Layer component:

<Layer
  addImage={image}
>
</Layer>

Or having a component for that:

<ImageSource image={image}/>

See: https://www.mapbox.com/mapbox-gl-js/api/#map#addimage

Priority + To be defined Feature

Most helpful comment

For reference, the prop images has been added to react-mapbox-gl with the release 2.5.0, it can be use this way:

const image = new Image(30, 30);
image.src = 'image_source_url_or_base64';

const images = ['myImage', image];
...
<Layer
  layout={{ icon-image: 'myImage' }}
  images={images}
/>

All 15 comments

For reference, the prop images has been added to react-mapbox-gl with the release 2.5.0, it can be use this way:

const image = new Image(30, 30);
image.src = 'image_source_url_or_base64';

const images = ['myImage', image];
...
<Layer
  layout={{ icon-image: 'myImage' }}
  images={images}
/>

Hey, when I try this, I get the following error:
react-dom.development.js:12879 Uncaught DOMException: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state.
Any idea why?

This works for me (shows the image) but gives me a few errors when removing the the new image is associated with:

const image = new Image(40, 60);
image.src = '/img/new-icon.svg';

const images = ['newIcon', image];

{show && (
<Layer
  type="symbol"
  layout={{ 'icon-image': 'newIcon' }}
  images={images}
>
...
)}

Errors when !show:

mapbox-gl.js:484 Uncaught TypeError: Cannot read property 'style' of undefined
    at e.removeImage (mapbox-gl.js:484)
    at Array.forEach (<anonymous>)
    at Layer../N:/Dropbox/Work/wildcrowd-web-app/node_modules/react-mapbox-gl/lib/layer.js.Layer.componentWillUnmount (layer.js:129)
    at ReactCompositeComponent.js:406
    at measureLifeCyclePerf (ReactCompositeComponent.js:73)
    at ReactCompositeComponentWrapper.unmountComponent (ReactCompositeComponent.js:405)
    at Object.unmountComponent (ReactReconciler.js:76)
    at ReactCompositeComponentWrapper.unmountComponent (ReactCompositeComponent.js:415)
    at Object.unmountComponent (ReactReconciler.js:76)
    at Object.updateChildren (ReactChildReconciler.js:128)
    at ReactDOMComponent._reconcilerUpdateChildren (ReactMultiChild.js:204)
    at ReactDOMComponent._updateChildren (ReactMultiChild.js:308)
    at ReactDOMComponent.updateChildren (ReactMultiChild.js:295)
    at ReactDOMComponent._updateDOMChildren (ReactDOMComponent.js:944)
    at ReactDOMComponent.updateComponent (ReactDOMComponent.js:758)
    at ReactDOMComponent.receiveComponent (ReactDOMComponent.js:720)
    at Object.receiveComponent (ReactReconciler.js:122)
    at ReactCompositeComponentWrapper._updateRenderedComponent (ReactCompositeComponent.js:751)
    at ReactCompositeComponentWrapper._performComponentUpdate (ReactCompositeComponent.js:721)
    at ReactCompositeComponentWrapper.updateComponent (ReactCompositeComponent.js:642)
    at ReactCompositeComponentWrapper.receiveComponent (ReactCompositeComponent.js:544)
    at Object.receiveComponent (ReactReconciler.js:122)
    at Object.updateChildren (ReactChildReconciler.js:107)
    at ReactDOMComponent._reconcilerUpdateChildren (ReactMultiChild.js:204)
    at ReactDOMComponent._updateChildren (ReactMultiChild.js:308)
    at ReactDOMComponent.updateChildren (ReactMultiChild.js:295)
    at ReactDOMComponent._updateDOMChildren (ReactDOMComponent.js:944)
    at ReactDOMComponent.updateComponent (ReactDOMComponent.js:758)
    at ReactDOMComponent.receiveComponent (ReactDOMComponent.js:720)
    at Object.receiveComponent (ReactReconciler.js:122)
    at ReactCompositeComponentWrapper._updateRenderedComponent (ReactCompositeComponent.js:751)
    at ReactCompositeComponentWrapper._performComponentUpdate (ReactCompositeComponent.js:721)
    at ReactCompositeComponentWrapper.updateComponent (ReactCompositeComponent.js:642)
    at ReactCompositeComponentWrapper.performUpdateIfNecessary (ReactCompositeComponent.js:558)
    at Object.performUpdateIfNecessary (ReactReconciler.js:154)
    at runBatchedUpdates (ReactUpdates.js:148)
    at ReactReconcileTransaction.perform (Transaction.js:141)
    at ReactUpdatesFlushTransaction.perform (Transaction.js:141)
    at ReactUpdatesFlushTransaction.perform (ReactUpdates.js:87)
    at Object.flushBatchedUpdates (ReactUpdates.js:170)
    at ReactDefaultBatchingStrategyTransaction.closeAll (Transaction.js:207)
    at ReactDefaultBatchingStrategyTransaction.perform (Transaction.js:154)
    at Object.batchedUpdates (ReactDefaultBatchingStrategy.js:60)
    at Object.batchedUpdates (ReactUpdates.js:95)
    at dispatchEvent (ReactEventListener.js:145)

and

An image with this name already exists.
    at t.addImage (mapbox-gl.js:374)
    at e.addImage (mapbox-gl.js:484)
    at layer.js:89
    at Array.forEach (<anonymous>)
    at Layer._this.initialize (layer.js:88)
    at e.Layer._this.onStyleDataChange (layer.js:101)
    at e.Evented.fire (mapbox-gl.js:510)
    at e._onData (mapbox-gl.js:484)
    at e.Evented.fire (mapbox-gl.js:510)
    at t.Evented.fire (mapbox-gl.js:510)
    at t.update (mapbox-gl.js:374)
    at e._render (mapbox-gl.js:484)

@Valid Yep, same exact issue when trying to remove a layer with an associated image. Have you found a work around for this?

Nope, haven't found a workaround yet. @alex3165 should this be re-opened, or another issue created?

Hi, sorry for the late reply, it is related to https://github.com/alex3165/react-mapbox-gl/issues/464 and I have created a PR on mapbox-gl-js to get this fixed https://github.com/mapbox/mapbox-gl-js/pull/5775. I am just waiting to have thismap.hasImage released with mapbox v0.43 to fix it.

@alex3165 well mapbox v0.43 with map.hasImage is released since 7 days :stuck_out_tongue:

I have the same issue with "react-mapbox-gl": "^3.8.0", and "mapbox-gl": "^0.46.0",

it's some time throw this error and some time everything is nice

the full error is this ::

mapbox-gl.js:28 Uncaught DOMException: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state.
    at Object.getImageData (http://localhost:3006/static/js/bundle.js:36457:936)
    at o.addImage (http://localhost:3006/static/js/bundle.js:36461:280818)
    at http://localhost:3006/static/js/bundle.js:66612:25
    at Array.forEach (<anonymous>)
    at Layer._this.initialize (http://localhost:3006/static/js/bundle.js:66611:34)
    at Layer../node_modules/react-mapbox-gl/lib/layer.js.Layer.componentWillMount (http://localhost:3006/static/js/bundle.js:66642:14)
    at callComponentWillMount (http://localhost:3006/static/js/bundle.js:50491:14)
    at mountClassInstance (http://localhost:3006/static/js/bundle.js:50548:7)
    at updateClassComponent (http://localhost:3006/static/js/bundle.js:50930:9)
    at beginWork (http://localhost:3006/static/js/bundle.js:51319:16)
    at performUnitOfWork (http://localhost:3006/static/js/bundle.js:53287:16)
    at workLoop (http://localhost:3006/static/js/bundle.js:53396:28)
    at HTMLUnknownElement.callCallback (http://localhost:3006/static/js/bundle.js:42013:14)
    at Object.invokeGuardedCallbackDev (http://localhost:3006/static/js/bundle.js:42052:16)
    at invokeGuardedCallback (http://localhost:3006/static/js/bundle.js:41909:27)
    at performWork (http://localhost:3006/static/js/bundle.js:53514:7)
    at scheduleUpdateImpl (http://localhost:3006/static/js/bundle.js:53899:19)
    at scheduleUpdate (http://localhost:3006/static/js/bundle.js:53838:12)
    at Object.enqueueSetState (http://localhost:3006/static/js/bundle.js:50360:7)
    at ReactMapboxGl../node_modules/react/cjs/react.development.js.Component.setState (http://localhost:3006/static/js/bundle.js:77962:16)
    at o.<anonymous> (http://localhost:3006/static/js/bundle.js:66955:31)
    at o.D.fire (http://localhost:3006/static/js/bundle.js:36457:8423)
    at o._render (http://localhost:3006/static/js/bundle.js:36461:287118)
    at http://localhost:3006/static/js/bundle.js:36461:288021
The above error occurred in the <Layer> component:
    in Layer (created by EnhancedLayer)
    in EnhancedLayer (at CenterMap.js:17)
    in div (created by ReactMapboxGl)
    in ReactMapboxGl (at CenterMap.js:16)
    in div (at CenterMap.js:15)
    in CenterMap (at Centers.js:356)
    in div (at Centers.js:291)
    in div (at Centers.js:214)
    in Center (created by Connect(Center))
    in Connect(Center) (created by Route)
    in Route (at RouteSwitch.js:28)
    in Switch (at RouteSwitch.js:26)
    in div (at RouteSwitch.js:25)
    in RouteSwitch (at MyRoute.js:13)
    in div (at MyRoute.js:11)
    in MyRoute (at App.js:26)
    in ScrollToTop (created by Connect(ScrollToTop))
    in Connect(ScrollToTop) (created by Route)
    in Route (created by withRouter(Connect(ScrollToTop)))
    in withRouter(Connect(ScrollToTop)) (at App.js:24)
    in Router (created by BrowserRouter)
    in BrowserRouter (at App.js:23)
    in div (at App.js:21)
    in Provider (at App.js:20)
    in App (at index.js:70)

Consider adding an error boundary to your tree to customize error handling behavior.
You can learn more about error boundaries at https://fb.me/react-error-boundaries.
Uncaught DOMException: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state.
    at Object.getImageData (http://localhost:3006/static/js/bundle.js:36457:936)
    at o.addImage (http://localhost:3006/static/js/bundle.js:36461:280818)
    at http://localhost:3006/static/js/bundle.js:66612:25
    at Array.forEach (<anonymous>)
    at Layer._this.initialize (http://localhost:3006/static/js/bundle.js:66611:34)
    at Layer../node_modules/react-mapbox-gl/lib/layer.js.Layer.componentWillMount (http://localhost:3006/static/js/bundle.js:66642:14)
    at callComponentWillMount (http://localhost:3006/static/js/bundle.js:50491:14)
    at mountClassInstance (http://localhost:3006/static/js/bundle.js:50548:7)
    at updateClassComponent (http://localhost:3006/static/js/bundle.js:50930:9)
    at beginWork (http://localhost:3006/static/js/bundle.js:51319:16)
    at performUnitOfWork (http://localhost:3006/static/js/bundle.js:53287:16)
    at workLoop (http://localhost:3006/static/js/bundle.js:53396:28)
    at HTMLUnknownElement.callCallback (http://localhost:3006/static/js/bundle.js:42013:14)
    at Object.invokeGuardedCallbackDev (http://localhost:3006/static/js/bundle.js:42052:16)
    at invokeGuardedCallback (http://localhost:3006/static/js/bundle.js:41909:27)
    at performWork (http://localhost:3006/static/js/bundle.js:53514:7)
    at scheduleUpdateImpl (http://localhost:3006/static/js/bundle.js:53899:19)
    at scheduleUpdate (http://localhost:3006/static/js/bundle.js:53838:12)
    at Object.enqueueSetState (http://localhost:3006/static/js/bundle.js:50360:7)
    at ReactMapboxGl../node_modules/react/cjs/react.development.js.Component.setState (http://localhost:3006/static/js/bundle.js:77962:16)
    at o.<anonymous> (http://localhost:3006/static/js/bundle.js:66955:31)
    at o.D.fire (http://localhost:3006/static/js/bundle.js:36457:8423)
    at o._render (http://localhost:3006/static/js/bundle.js:36461:287118)
    at http://localhost:3006/static/js/bundle.js:36461:288021

any updates ...

import Icon from './download.svg';

const image = new Image(30, 30);
image.src = Icon;
const images = ['myImage', image];

const point = [
{-70.903827,
42.584152},
{-71.905205,
42.211716},
{-70.903827,
42.584152},
];

type="symbol"
id="point"
layout={{
'icon-image': 'myImage',
'icon-allow-overlap': true
}}
images={images}
>
{point.map((point, i) => (
key={i}
coordinates={point}

                />
              ))}
        </Layer>

Try something like that. This working in react.

some solution?

Try this code above.

I've already tried

worked for me, thanks @alex3165

Was this page helpful?
0 / 5 - 0 ratings