ghettovoice / vuelayers

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

Error in render: "TypeError: destinationProjection is null" #301

Closed benjaminh closed 4 years ago

benjaminh commented 4 years ago

Hello there,

I'm trying to create a simple map with a source-vector by loading external features. I already did it in a static single html page using cdn js imports. Now I'm trying to port my code in a Vue-cli project so I give vuelayers a try !

I followed this example from vuelayers documentation : https://vuelayers.github.io/#/docs/component/vector-layer

Few specificities about my code :

import proj4 from 'proj4'
proj4.defs("EPSG:2154","+proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs");

Here is my component :

<template>
  <div>
    <vl-map :load-tiles-while-animating="true" :load-tiles-while-interacting="true"
             data-projection="EPSG:2154" style="height: 400px">
      <vl-view :zoom.sync="zoom" :center.sync="center" :rotation.sync="rotation" projection="EPSG:3857"></vl-view>

      <vl-layer-tile id="osm">
        <vl-source-osm></vl-source-osm>
      </vl-layer-tile>

      <vl-layer-vector>
        <vl-source-vector :features.sync="features"></vl-source-vector>

        <vl-style-box>
          <vl-style-stroke color="green" :width="3"></vl-style-stroke>
          <vl-style-fill color="rgba(255,255,255,0.5)"></vl-style-fill>
        </vl-style-box>
      </vl-layer-vector>

    </vl-map>
  </div>

</template>

<script>
import Vue from 'vue'
import VueLayers from 'vuelayers'
import 'vuelayers/lib/style.css' // needs css-loader
import fetchProfileService from '@/services/api/myservice.service.js'

import {Feature} from 'ol'
import {GeoJSON} from 'ol/format'

Vue.use(VueLayers)

export default {
    data () {
        return {
          zoom: 2,
          center: [0, 0],
          rotation: 0,
          features: [],
        }
    },
    mounted () {
      this.loadFeatures().then(features => {
        this.features = features.map(Object.freeze)
        this.loading = false
      })
    },
    methods: {
      // emulates external source
      loadFeatures () {
        let profile = fetchProfileService.fetchDatedProfileData().profile;
        let features = [ new Feature( (new GeoJSON()).readGeometry(profile, {
            dataProjection: 'EPSG:2154',
            featureProjection: 'EPSG:3857',
        })) ]
        return new Promise(resolve => {
          setTimeout(() => {
            // generate GeoJSON random features
            resolve(
              features
            )
          }, 2000)
        });
      }
    }
}
</script>

I end up with console errors when loading my page : Error in render: "TypeError: destinationProjection is null" andTypeError: sourceProjection is null

profile variable used to create features contains the following Json array :

{
  "type": "MultiPoint",
  "coordinates" : [
    [ 307990.482808, 6651285.00402, -0.541960716248],
   ...
   ]
}

Any ideas ?

ghettovoice commented 4 years ago

Hello @benjaminh , you forget to register proj4 in the openlayers lib. Take a look here https://github.com/ghettovoice/vuelayers/issues/150#issuecomment-481547771

ghettovoice commented 4 years ago

As for features appending to the layer: if you remote service returns features in GeoJSON format, you don't need to read them with openlayers format reader. features prop of the vector source component accepts array of GeoJSON encoded features.

And you don't need reproject you loaded features if they are already in projection that defined as data-projection on the vl-map component.

<template>
  ...
  <vl-source-vector :features.sync="features"></vl-source-vector>
  ...
</template>

<script>
export default {
  ...,
  methods: {
    loadFeatures () {
        // if profile is already GeoJSON just append it to the final array
        let profile = fetchProfileService.fetchDatedProfileData().profile;
        let features = [ profile ]
        return new Promise(resolve => {
          setTimeout(() => {
            // generate GeoJSON random features
            resolve(
              features
            )
          }, 2000)
        });
      }
  },
}
</script>
benjaminh commented 4 years ago

Thank you @ghettovoice for your feedback ! Until now, my remote service didn't provide GeoJSON data, that's why I needed to call specific parser. Yet, I'm working on that backend API part too so I'm definitely thinking about returning data in GeoJSON format.

As for the projection part, I have been told that GeoJSON specification didn't recommend using a different CRS than EPSG:4326 so I'm also thinking of reprojecting data on the API side as well. But I'll try to fix my error first just to check it out.

benjaminh commented 4 years ago

Hello @ghettovoice, I spent some time working in the backend (API) part of my project, and I'm now working back on the frontend. I still get the Error in render: "TypeError: destinationProjection is null" andTypeError: sourceProjection is null errors, although I do register my projection in my component as follows (according to the other issue you pointed out) :

<template>
...
        <vl-map :load-tiles-while-animating="true" :load-tiles-while-interacting="true" data-projection="EPSG:2154" style="height: 400px">
          <vl-view :zoom.sync="zoom" :center.sync="center" :rotation.sync="rotation"></vl-view>

          <vl-layer-tile id="osm">
            <vl-source-osm></vl-source-osm>
          </vl-layer-tile>

          <vl-layer-vector>
            <vl-source-vector :features.sync="ol_features"></vl-source-vector>
            ...
          </vl-layer-vector>

        </vl-map>
...
</template>

<script>
import Vue from 'vue'
import VueLayers from 'vuelayers'
import 'vuelayers/lib/style.css' // needs css-loader
import {register} from 'ol/proj/proj4'
import proj4 from 'proj4'

proj4.defs('EPSG:2154','+proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ')
register(proj4)

Vue.use(VueLayers)

export default {
  ...
}
</script>

I'm using "vuelayers": "^0.11.22", "ol": "^6.3.1", and "proj4": "^2.6.1"

Btw, I followed your advice related to GeoJSON features and now directly try to load them without using reader nor reprojection.

ghettovoice commented 4 years ago

You should use ol: ^5.3.0 with vuelayers v0.11.x. Seems like this is problem, you actually have in 2 versions of ol, one when you directly import it, and another that is used by vuelayers. Try to change ol version in package.json, drop node_modules (or at least node_modules/vuelayers) and re-install.

benjaminh commented 4 years ago

OK I'll downgrade ol version and post the result. What about directly using vuelayers' ol module if it is already shipped with the package ? Is it possible ? Like importing the vuelayers ol module in my vue component instead of importing it from ol root module.

ghettovoice commented 4 years ago

There is no prob to use ol directly, and it's not shipped with vuelayers, it is a dependency of vuelayers. There is only one restriction, if you install ol package manually, then you need to use ol v5 version. (support for ol v6 is coming soon)

benjaminh commented 4 years ago

I dropped node_modules, downgrade ol package to ^5.3.0 and reinstall packages, but I still get the same error. In package-lock.json, it tells me ol version is 5.3.3.

My package.json:

{
  "name": "test",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "axios": "^0.19.2",
    "core-js": "^3.6.4",
    "d3": "^5.16.0",
    "material-design-icons-iconfont": "^5.0.1",
    "proj4": "^2.6.1",
    "qs": "^6.9.4",
    "vue": "^2.6.11",
    "vue-plotly": "^1.1.0",
    "vue-router": "^3.1.5",
    "vuelayers": "^0.11.22",
    "vuetify": "^2.2.11",
    "vuex": "^3.1.3"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "~4.2.0",
    "@vue/cli-plugin-eslint": "~4.2.0",
    "@vue/cli-plugin-router": "^4.3.1",
    "@vue/cli-plugin-vuex": "^4.3.1",
    "@vue/cli-service": "~4.2.0",
    "babel-eslint": "^10.0.3",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^6.1.2",
    "ol": "^5.3.0",
    "sass": "^1.19.0",
    "sass-loader": "^8.0.0",
    "vue-cli-plugin-vuetify": "~2.0.5",
    "vue-template-compiler": "^2.6.11",
    "vuetify-loader": "^1.3.0"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential",
      "eslint:recommended"
    ],
    "parserOptions": {
      "parser": "babel-eslint"
    },
    "rules": {}
  },
  "browserslist": [
    "> 1%",
    "last 2 versions"
  ]
}

Maybe my install of ol in the first place was wrong: what about removing ol package from the devdependencies section ? Vuelayers should install the correct dependency anyway, right ?

ghettovoice commented 4 years ago

Vuelayers should install the correct dependency anyway, right ?

Yes, it should.

Do you have this dir ./node_modules/vuelayers/node_modules ? If yes, drop it

benjaminh commented 4 years ago

I do have this directory indeed which is created every time I reinstall vuelayers package. I dropped it but I still get the same issue.

Also, I tried to completely remove ol from the root package.json, dropped node_modules directory again and see if it works only using vuelayers (no manual installation of openlayers package). But it looks like it searches for some ol package anyway : dependencies not found, To install them, you can run: npm install --save ol/proj/proj4 ol/tilegrid

ghettovoice commented 4 years ago

Very strange, something wrong with your current setup. Do you try to drop package-lock.json too before full re-install with npm install?

benjaminh commented 4 years ago

No I didn't because I thought package-lock.json was recreated at each re-install. Thanks for the tip, the problem is solved, so here is what I did precisely:

Now, there is no node_modules directory within ./node_modules/vuelayers and everything looks fine, no more complaints about my projection, and ol package version is 5.3.3 (coming from vuelayers dependency).

Thank you for your help !