ghettovoice / vuelayers

Web map Vue components with the power of OpenLayers
https://vuelayers.github.io/
MIT License
683 stars 229 forks source link

'TypeError: coordinates must be finite numbers' when changing map/view projection #405

Closed felnne closed 3 years ago

felnne commented 3 years ago

Hi @ghettovoice,

I am trying to create a web-map that supports multiple projections, in this case for the Antarctic (EPSG:3031) and Arctic (EPSG:3413).

I've been experimenting getting this to work with VueLayers (v0.12.0-rc.20) but encounter errors like this when the projection changes:

TypeError: coordinates must be finite numbers

I tried to strip the map back as far as possible, so it has no layers and a map centre of [0,0], and hosted it here: https://codesandbox.io/s/suspicious-worker-fnh4n?file=/src/App.vue

Changing the projection using the select input should hopefully trigger the errors I'm getting.

I'm assuming that the coordinates that cause these errors relate to the map centre, and that on changing the projection these coordinates are reprojected (to preserve the current map centre?) and that this causes a failure.

I've enabled the VueLayers debug mode and can see a console messages such as:

[VueLayers] VlView.b5648567-757a-4c2a-bc57-dbad4d7fe3f8 projection changed, scheduling recreate...  EPSG:3031  ===>  EPSG:3413
[VueLayers] VlView.b5648567-757a-4c2a-bc57-dbad4d7fe3f8 recreate scheduled

This then leads to a series of errors [1] and then some more debug messages:

[VueLayers] VlView.vl-d8d48758-8bb3-4301-ad31-8ff78f423c9a-default-view ol object created log.js:32:4
[VueLayers] VlView.vl-d8d48758-8bb3-4301-ad31-8ff78f423c9a-default-view ol object mounted log.js:32:4
[VueLayers] VlView.b5648567-757a-4c2a-bc57-dbad4d7fe3f8 ol object created log.js:32:4
[VueLayers] VlView.b5648567-757a-4c2a-bc57-dbad4d7fe3f8 ol object mounted log.js:32:4
[VueLayers] VlView.vl-d8d48758-8bb3-4301-ad31-8ff78f423c9a-default-view ol object unmounted log.js:32:4
[VueLayers] VlView.vl-d8d48758-8bb3-4301-ad31-8ff78f423c9a-default-view ol object destroyed

I'm not clear what this means, other than that presumably this means the errors I'm getting are happening after the projection has been changed. I'm wondering if something needs overriding to reset the centre coordinates or similar?

If relevant, I don't need to preserve any map state between the two projections so things like the zoom, extent etc. could all be reset on a projection change if that would make things easier.

I'm aware what I'm doing is likely an edge case but it would be great to get this working if you have advice on what might be causing this and/or how to fix it.

Thanks for such a useful library, Felix

[1]

[VueLayers] VlSourceVector.vl-14e03d50-25ea-48ac-9bf8-fbfd37d0bac8-default-source format changed, scheduling recreate...  undefined  ===>  
Object { dataProjection: {…}, defaultFeatureProjection: null, geometryName_: undefined, extractGeometryName_: undefined, defaultDecimals: undefined, defaultStyleReader: createStyle(vlStyle), defaultStyleWriter: dumpStyle(olStyle)
 }
log.js:32:4
[VueLayers] VlSourceVector.vl-14e03d50-25ea-48ac-9bf8-fbfd37d0bac8-default-source recreate discarded log.js:32:4
[VueLayers] VlMap.14e03d50-25ea-48ac-9bf8-fbfd37d0bac8 ol object created log.js:32:4
[VueLayers] VlMap.14e03d50-25ea-48ac-9bf8-fbfd37d0bac8 ol object mounted log.js:32:4

You are running Vue in development mode.
Make sure to turn on production mode when deploying for production.
See more tips at https://vuejs.org/guide/deployment.html vue.common.dev.js:9060

vue-devtools  Detected Vue v2.6.12 backend.js:2237:15

[VueLayers] VlView.dde06de4-e6ea-4f97-a971-9ce88e691d1d ol object created log.js:32:4
[VueLayers] VlView.dde06de4-e6ea-4f97-a971-9ce88e691d1d ol object mounted log.js:32:4
[VueLayers] VlView.vl-14e03d50-25ea-48ac-9bf8-fbfd37d0bac8-default-view ol object mount canceled log.js:32:4
[VueLayers] VlView.vl-14e03d50-25ea-48ac-9bf8-fbfd37d0bac8-default-view ol object unmount canceled log.js:32:4
[VueLayers] VlView.vl-14e03d50-25ea-48ac-9bf8-fbfd37d0bac8-default-view ol object create canceled log.js:32:4
[VueLayers] VlView.vl-14e03d50-25ea-48ac-9bf8-fbfd37d0bac8-default-view ol object destroy canceled log.js:32:4
[VueLayers] VlLayerVector.vl-14e03d50-25ea-48ac-9bf8-fbfd37d0bac8-default-layer ol object created log.js:32:4
[VueLayers] VlLayerVector.vl-14e03d50-25ea-48ac-9bf8-fbfd37d0bac8-default-layer ol object mounted log.js:32:4
[VueLayers] VlSourceVector.vl-14e03d50-25ea-48ac-9bf8-fbfd37d0bac8-default-source ol object created log.js:32:4
[VueLayers] VlSourceVector.vl-14e03d50-25ea-48ac-9bf8-fbfd37d0bac8-default-source ol object mounted log.js:32:4

[VueLayers] VlView.dde06de4-e6ea-4f97-a971-9ce88e691d1d projection changed, scheduling recreate...  EPSG:3031  ===>  EPSG:3413 log.js:32:4
[VueLayers] VlView.dde06de4-e6ea-4f97-a971-9ce88e691d1d recreate scheduled log.js:32:4

[Vue warn]: Error in getter for watcher "extentDataProj": "TypeError: coordinates must be finite numbers"

found in

---> <VlSourceVector>
       <VlLayerVector>
         <VlMap>
           <AppMap>
             <Anonymous>
               <Root> vue.common.dev.js:630
TypeError: coordinates must be finite numbers
    checkCoord checkSanity.js:10
    _default checkSanity.js:2
    transform transform.js:17
    transformer core.js:8
    inverse core.js:77
    createSafeCoordinateTransform proj.js:661
    createTransformFromCoordinateTransform proj.js:333
    applyTransform extent.js:826
    transformExtent proj.js:512
    transformExtent proj.js:383
    extentToDataProj proj-transforms.js:94
    getExtent vector-source.js:469
    extentDataProj vector-source.js:154
    VueJS 16
    change app.e31bb0bc.js:187714
    VueJS 3
vue.common.dev.js:1893
[VueLayers] VlView.dde06de4-e6ea-4f97-a971-9ce88e691d1d recreating... log.js:32:4
[VueLayers] VlView.dde06de4-e6ea-4f97-a971-9ce88e691d1d ol object unmounted log.js:32:4
[VueLayers] VlView.dde06de4-e6ea-4f97-a971-9ce88e691d1d ol object destroyed log.js:32:4
[Vue warn]: Error in getter for watcher "currentCenterDataProj": "TypeError: coordinates must be finite numbers"

found in

---> <VlView>
       <VlMap>
         <AppMap>
           <Anonymous>
             <Root> vue.common.dev.js:630
TypeError: coordinates must be finite numbers
    checkCoord checkSanity.js:10
    _default checkSanity.js:2
    transform transform.js:17
    transformer core.js:8
    forward core.js:74
    createSafeCoordinateTransform proj.js:659
    createTransformFromCoordinateTransform proj.js:333
    transform proj.js:495
    transform proj.js:73
    transformPoint proj.js:55
    pointToDataProj proj-transforms.js:57
    currentCenterDataProj view.vue:192
    VueJS 16
    _callee$ wait-for-map.js:35
    tryCatch runtime.js:63
    invoke runtime.js:293
    defineIteratorMethods runtime.js:118
    Babel 6
    beforeInit wait-for-map.js:9
    _callee$ view.vue:472
    tryCatch runtime.js:63
    invoke runtime.js:293
    defineIteratorMethods runtime.js:118
    Babel 4
    beforeInit view.vue:469
    _callee16$ ol-cmp.js:650
    tryCatch runtime.js:63
    invoke runtime.js:293
    defineIteratorMethods runtime.js:118
    Babel 4
    execInit app.e31bb0bc.js:135525
    _callee$ ol-cmp.js:163
    tryCatch runtime.js:63
    invoke runtime.js:293
    defineIteratorMethods runtime.js:118
    Babel 2
vue.common.dev.js:1893
[Vue warn]: Error in callback for watcher "currentCenterDataProj": "TypeError: can't access property "slice", value is undefined"

found in

---> <VlView>
       <VlMap>
         <AppMap>
           <Anonymous>
             <Root> vue.common.dev.js:630
TypeError: can't access property "slice", value is undefined
    handler view.vue:283
    VueJS 11
    _callee$ wait-for-map.js:35
    tryCatch runtime.js:63
    invoke runtime.js:293
    defineIteratorMethods runtime.js:118
    Babel 6
    beforeInit wait-for-map.js:9
    _callee$ view.vue:472
    tryCatch runtime.js:63
    invoke runtime.js:293
    defineIteratorMethods runtime.js:118
    Babel 4
    beforeInit view.vue:469
    _callee16$ ol-cmp.js:650
    tryCatch runtime.js:63
    invoke runtime.js:293
    defineIteratorMethods runtime.js:118
    Babel 4
    execInit app.e31bb0bc.js:135525
    _callee$ ol-cmp.js:163
    tryCatch runtime.js:63
    invoke runtime.js:293
    defineIteratorMethods runtime.js:118
    Babel 2
vue.common.dev.js:1893
[Vue warn]: Error in render: "TypeError: coordinates must be finite numbers"

found in

---> <VlView>
       <VlMap>
         <AppMap>
           <Anonymous>
             <Root> vue.common.dev.js:630
TypeError: coordinates must be finite numbers
    checkCoord checkSanity.js:10
    _default checkSanity.js:2
    transform transform.js:17
    transformer core.js:8
    forward core.js:74
    createSafeCoordinateTransform proj.js:659
    createTransformFromCoordinateTransform proj.js:333
    transform proj.js:495
    transform proj.js:73
    transformPoint proj.js:55
    pointToDataProj proj-transforms.js:57
    currentCenterDataProj view.vue:192
    VueJS 3
    __vue_render__ app.e31bb0bc.js:180942
    VueJS 14
    _callee$ wait-for-map.js:35
    tryCatch runtime.js:63
    invoke runtime.js:293
    defineIteratorMethods runtime.js:118
    Babel 6
    beforeInit wait-for-map.js:9
    _callee$ view.vue:472
    tryCatch runtime.js:63
    invoke runtime.js:293
    defineIteratorMethods runtime.js:118
    Babel 4
    beforeInit view.vue:469
    _callee16$ ol-cmp.js:650
    tryCatch runtime.js:63
    invoke runtime.js:293
    defineIteratorMethods runtime.js:118
    Babel 4
    execInit app.e31bb0bc.js:135525
    _callee$ ol-cmp.js:163
    tryCatch runtime.js:63
    invoke runtime.js:293
    defineIteratorMethods runtime.js:118
    Babel 2
vue.common.dev.js:1893
[Vue warn]: Error in getter for watcher "visibleExtentDataProj": "TypeError: coordinates must be finite numbers"

found in

---> <VlView>
       <VlMap>
         <AppMap>
           <Anonymous>
             <Root> vue.common.dev.js:630
TypeError: coordinates must be finite numbers
    checkCoord checkSanity.js:10
    _default checkSanity.js:2
    transform transform.js:17
    transformer core.js:8
    forward core.js:74
    createSafeCoordinateTransform proj.js:659
    createTransformFromCoordinateTransform proj.js:333
    applyTransform extent.js:826
    transformExtent proj.js:512
    transformExtent proj.js:383
    extentToDataProj proj-transforms.js:94
    getExtent view.vue:673
    visibleExtentDataProj view.vue:206
    VueJS 16
    _callee15$ ol-cmp.js:438
    Babel 8
    _callee5$ ol-cmp.js:193
    Babel 10
    _callee16$ ol-cmp.js:669
    Babel 10
    _callee$ ol-cmp.js:163
    Babel 8
    VueJS 16
vue.common.dev.js:1893

[VueLayers] VlView.vl-14e03d50-25ea-48ac-9bf8-fbfd37d0bac8-default-view ol object created log.js:32:4
[VueLayers] VlView.vl-14e03d50-25ea-48ac-9bf8-fbfd37d0bac8-default-view ol object mounted log.js:32:4
[VueLayers] VlView.dde06de4-e6ea-4f97-a971-9ce88e691d1d ol object created log.js:32:4
[VueLayers] VlView.dde06de4-e6ea-4f97-a971-9ce88e691d1d ol object mounted log.js:32:4
[VueLayers] VlView.vl-14e03d50-25ea-48ac-9bf8-fbfd37d0bac8-default-view ol object unmounted log.js:32:4
[VueLayers] VlView.vl-14e03d50-25ea-48ac-9bf8-fbfd37d0bac8-default-view ol object destroyed
ghettovoice commented 3 years ago

Hello @felnne , thanks for report! You are right, you are found a bug on edge cases. By default vuelayers used ePSG:3857 as data projection, due to async update of the view projection and data projection there is a moment when transform from EPSG:3031 to EPSG:3857 occurs. But obviously not all coordinates can be transformed because EPSG:3857 covers by Y only approx 86, -86 latitudes.

I have just published patched version with @dev tag. Try it with your app pls.

npm install vuelayers@dev

There is my test app https://github.com/ghettovoice/vuelayers/blob/208a8c1d3df200de783689a863b9737fe34ac5fd/tests/app.vue

felnne commented 3 years ago

Hi @ghettovoice,

Thanks for looking into this and thanks for that example app.

I couldn't get the development package to work in my app (it was giving errors about imports) but I was able to run your app and switch between the projections.

As an extra complication, I added another projection for web-mercator (EPSG:3857). Initially I just added that to the dropdown list and could switch from 3031 to 3413 to 3857 fine, but if I went in any other order, the app hangs and the browser eventually kills the script.

If useful this is what I get:

3031 3413 3857
3031 N/A ok no
3413 ok N/A ok
3857 no no N/A

Again, thanks for your help with this 👍

ghettovoice commented 3 years ago

Ok, I need to dig into this more carefully...

ghettovoice commented 3 years ago

it was giving errors about imports

Can you dump error log? I want to check which imports failed?

felnne commented 3 years ago

@ghettovoice sorry the delayed reply.

I think my import errors likely stem from switching from a release to a source installation and I haven't adjusted properly.

If useful, the lines that break in my app are:

import VueLayers from 'vuelayers';
import 'vuelayers/dist/vuelayers.css';

When using "vuelayers": "^0.12.0-rc.20", the top level contents of node_modules/vuelayers/ is:

LICENSE       README.md     dist/          docs/          node_modules/  package.json  src/

Both imports work.

When using "vuelayers": "git+https://github.com/ghettovoice/vuelayers.git#bcca4efa0e10661763068e460d00f06a2342af2c", the top level contents is:

LICENSE        README.md      build          docs           node_modules   package.json   src            tests          vue.config.js

This gives errors when building:

app2_1       | 🚨  /usr/src/app/components/AppMap.vue:45:7: Cannot resolve dependency 'vuelayers/dist/vuelayers.css'
app2_1       |     at Resolver.resolve (/usr/src/app/node_modules/parcel-bundler/src/Resolver.js:71:17)
app2_1       |     at async Bundler.resolveAsset (/usr/src/app/node_modules/parcel-bundler/src/Bundler.js:433:18)
app2_1       |     at async Bundler.resolveDep (/usr/src/app/node_modules/parcel-bundler/src/Bundler.js:484:14)
app2_1       |     at async /usr/src/app/node_modules/parcel-bundler/src/Bundler.js:608:26
app2_1       |     at async Promise.all (index 9)
app2_1       |     at async Bundler.loadAsset (/usr/src/app/node_modules/parcel-bundler/src/Bundler.js:599:21)
app2_1       |     at async /usr/src/app/node_modules/parcel-bundler/src/Bundler.js:610:13
app2_1       |     at async Promise.all (index 4)
app2_1       |     at async Bundler.loadAsset (/usr/src/app/node_modules/parcel-bundler/src/Bundler.js:599:21)
app2_1       |     at async /usr/src/app/node_modules/parcel-bundler/src/Bundler.js:610:13
app2_1       |     at async Promise.all (index 3)
app2_1       |     at async Bundler.loadAsset (/usr/src/app/node_modules/parcel-bundler/src/Bundler.js:599:21)
app2_1       |     at async /usr/src/app/node_modules/parcel-bundler/src/Bundler.js:610:13
app2_1       |     at async Promise.all (index 0)
app2_1       |     at async Bundler.loadAsset (/usr/src/app/node_modules/parcel-bundler/src/Bundler.js:599:21)
app2_1       |     at async Bundler.processAsset (/usr/src/app/node_modules/parcel-bundler/src/Bundler.js:557:5)

If I comment out the call to vuelayers.css, an error is raised for the main VueLayers import:

🚨  /usr/src/app/components/AppMap.vue:44:22: Cannot resolve dependency 'vuelayers'
app2_1       |     at Resolver.resolve (/usr/src/app/node_modules/parcel-bundler/src/Resolver.js:71:17)
app2_1       |     at async Bundler.resolveAsset (/usr/src/app/node_modules/parcel-bundler/src/Bundler.js:433:18)
app2_1       |     at async Bundler.resolveDep (/usr/src/app/node_modules/parcel-bundler/src/Bundler.js:484:14)
app2_1       |     at async /usr/src/app/node_modules/parcel-bundler/src/Bundler.js:608:26
app2_1       |     at async Promise.all (index 8)
app2_1       |     at async Bundler.loadAsset (/usr/src/app/node_modules/parcel-bundler/src/Bundler.js:599:21)
app2_1       |     at async Bundler.processAsset (/usr/src/app/node_modules/parcel-bundler/src/Bundler.js:557:5)
app2_1       |     at async PromiseQueue._runJob (/usr/src/app/node_modules/parcel-bundler/src/utils/PromiseQueue.js:48:7)

For info, from my testing of your latest commit (https://github.com/ghettovoice/vuelayers/commit/bcca4efa0e10661763068e460d00f06a2342af2c), projection switching now work between all those projections, which is fantastic 😃.

I did notice a quirk, when switching from web-mercator to a polar projection, the polar projection will be zoomed in. That's clearly ease to workaround so definitely not a blocker for my use however.

Again if useful,

3031 3413 3857
3031 N/A OK OK
3413 OK N/A OK
3857 OK (Zoom) OK (Zoom) N/A
ghettovoice commented 3 years ago

You can't run from sources because I don't store dist files in the git repo. But I published current master branch version with dev tag on npm.

So you only need to re-install vuelayers with cli cmd npm install vuelayers@dev and import as always:

import VueLayers from 'vuelayers';
import 'vuelayers/dist/vuelayers.css';

So ask you to try install as described above. If it will ok, then I'll publish it as next release.

felnne commented 3 years ago

Hi, thanks, using that tag works, and using OSM I can switch between the three projections.

I do have an issue with switching WMS layers however. I have an array of layers looped through similar to the VueLayers demo. When I change projection I update this array and expect the layers to change accordingly. This doesn't work, or rather it does if I inspect the component in the Vue devtools, but the map itself doesn't change (no network requests are made etc.). This does work (adding array elements add a layer to the map) within a projection however.

I'm wondering if there's something I need to do to 'flush' the changes through to the map?

ghettovoice commented 3 years ago

When I change projection I update this array and expect the layers to change accordingly.

What actually do you change among layer props? Can you dump here a code sample?

felnne commented 3 years ago

Hi, Sorry for the slow reply.

I realised the projection change and layer manipulation were happening asynchronously. Changing this so the layers are only changed after the projection has changed fixes the problem I was having.

ghettovoice commented 3 years ago

Ok. Thanks for info

So I can publish this bugfix under vuelayers@next tag on npm. I will make this soon...

felnne commented 3 years ago

Thanks for your help with this 🙂