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
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
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},
];
id="point"
layout={{
'icon-image': 'myImage',
'icon-allow-overlap': true
}}
images={images}
>
{point.map((point, 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
Most helpful comment
For reference, the prop
imageshas been added to react-mapbox-gl with the release2.5.0, it can be use this way: