perliedman / reproject

Change, convert, transform, reproject GeoJSON between different projections / CRS

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

proj4js v2.6.1 not working?

hoogw opened this issue · comments

commented

I use browserify to get a reproject.js file, include in html script tag. I get proj4 , I get proj4 not define error.

Does it means, reproject.js does not have 'proj4' object? read the previous issue, it should already include proj4 object, it is 6k line of code, have 204KB size.

How I fix?
I manually include script tag for proj4 v2.6.1
proj4 undefine error is gone, but reproject is not working.

                 proj4.defs('EPSG:2229','+proj=lcc +lat_1=35.46666666666667 +lat_2=34.03333333333333 +lat_0=33.5 +lon_0=-118 +x_0=2000000.0001016 +y_0=500000.0001016001 +ellps=GRS80 +datum=NAD83 +to_meter=0.3048006096012192 +no_defs');

               var from_projection = "+proj=lcc +lat_1=35.46666666666667 +lat_2=34.03333333333333 +lat_0=33.5 +lon_0=-118 +x_0=2000000.0001016 +y_0=500000.0001016001 +ellps=GRS80 +datum=NAD83 +to_meter=0.3048006096012192 +no_defs"
                                                     


                // for reproject.js only
                var crss = {
                    //  'EPSG:2229': proj4.defs('EPSG:2229'),
                   //  "EPSG:4326": proj4.defs('EPSG:4326')
                   };
                                                    


         var ___reprojected_geojson = reproject.reproject(_geometry_, from_projection, proj4.WGS84, ___crss)
commented

Do I need extra include proj4 v2.6.1?
without this extra script tag, I always get proj4 is undefine error.

                       <script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.6.1/proj4.js"></script>

After include this script tag, reproject.reproject(.....) failed working.

Is it because proj4.js v2.6.1 not compatibile? I use browserify.js

Hi!
You can provide proj4 object directly, but usually you don't need to, it's simpler to just provide the proj definition, since reproject already includes proj4.

Here is a small sample similar to yours:

const fromProj = '+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs '
const geojson = {
  type: 'Point',
  coordinates: [319180, 6399862]
}

const reprojected = reproject.toWgs84(geojson, fromProj)

document.getElementById("app").innerHTML = JSON.stringify(reprojected, null, 2);

As you can see, you don't need to bother with crss or Proj4's defs, it is usually simpler to just pass in the proj4 definitions as strings directly.

You can see the sampe above in action here: https://codesandbox.io/s/busy-morse-igpjb?fontsize=14&hidenavigation=1&theme=dark

commented

test your sample on browserified reproject.js file, it works !!!!

For those beginner like me, run into several trouble before it works,
read the steps below will help you avoid the trouble I had.

              1) must use sudo install globally
                sudo npm install -g brwoserify

                 https://github.com/perliedman/reproject
                 sudo npm install reproject    // install locally is fine

                 must manually create 'dist' folder for later output file use

              2) must use --s expose global variable function 'reproject' and or 'toWgs84' you will use later in browser js.
                    without --s , will get 'reproject' undefined error . https://makerlog.org/posts/creating-js-library-builds-with-browserify-and-other-npm-modules
                    browserify --help will list all options.  -o means output file directory

                 browserify node_modules/reproject/index.js --s reproject -o node_modules/reproject/dist/reproject.js


              3) in browser js, NOTE: reproject is a global object, represent the whole module, all sub function must start from it
                  
                    reproject.reproject(....)
                    reproject.toWgs84(...)

Once you had browserify file at :
dist/reproject.js

Run this test code, it works

        function test_reproject(){

          // works 
          const test_fromProj = '+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs '
          const test_geojson = {
            type: 'Point',
            coordinates: [319180, 6399862]
          }
          
          const reprojected = reproject.toWgs84(test_geojson, test_fromProj)

          
          console.log(' test reprojected  ' , reprojected)

          
        }
commented

However, I get error:

                         uncaught exception: Terraformer: invalid input for Terraformer.Point

because I use terraformer.js
I guess reproject.js and terraformer.js shared some same variable, cause variable polluted
I am not sure why,

commented

image

I found the reason, test code working is because test_geometry object prototype is kind of empty.
however, geometry ( this is my real data, get from WKT -> terraformor.WKT.parser -> geometry)
geometry object's prototype constructor is not empty, it has some stuff inheritage from terraformer.point. when I run reproject.reproject(geometry) will get above error.

I guess reproject.js use trigger 'point' constructor, which trigger terraformer.js to work

This is first time I see this kind of error.

the solution is before feed into reproject.js, you must clean the terraformer.js polluted geometry object,

commented

image
prototype is different, test_geojson is good one, geometry 's prototype polluted by terraformer.js
when feed into reproject.js, test_geojson works, while geometry will cause error

this ticket can closed

commented

@perliedman

I recommend if you can provide a browserified reproject.js in source code foder dist/reproject.js

and also we can use:

                  wget https://raw.github.com/perliedman/reproject/master/dist/reproject.js

directly download, and directly use script tag include in html and directly use it as:

                   reproject.toWgs84()
                    and 
                    reproject.reproject()

This will save 4 hours frustration that other beginner could had.
specially when use browserify, you must use --s reproject

               browserify node_modules/reproject/index.js --s reproject -o node_modules/reproject/dist/reproject.js

without --s reproject, you will get reproject undefine error

I already have one, but can't upload here, best if you provide one here

commented

wellknown.js will not pollute geometry, use reproject.js will not cause error.

So wellknownText string -> wellknown.js -> geometry object -> reproject.js works fine

                              // use terraformer wkt parser(both works 1)
                                  //var ___geometry = Terraformer.WKT.parse(___wkt_string);


                                  // use wellknown.js (both works 2)
                                  var ___geometry = wellknown.parse(___wkt_string);

However,
wellknownText string -> terraformer.WKT.parser.js -> geometry object(polluted, must clean) -> reproject.js

                    // terraformer.js polluted geometry object, its prototype have constructor as terraformer.Point when feed into reproject.js, will trigger constructor call, then invalide point error.
                     
                      var _cleaned_geometry = {}
                          _cleaned_geometry.type = _geometry_.type
                          _cleaned_geometry.coordinates = _geometry_.coordinates

                    var ___reprojected_geometry = reproject.toWgs84(_cleaned_geometry , from_projection)
          */  
          

          // wellknown.js  not need to clean (only terraformer.js WKT parser need to)
          var ___reprojected_geometry = reproject.toWgs84(_geometry_ , from_projection)
commented

other wise, if you want you can write your own re-project funtion
when I can't get reproject to work, I wrote my own, now, I just use reproject.js,
unless if you want to speed up the performance, remove the overhead, wrote your own function.

         function reproject_coordinate(_geometry_){
           
           // not finish yet, only support point so far.  
           
           // alternative to reproject.js

           // manually re-project each long-lat pair by proj4js based on type(point, line, polygon etc.)
           

           /*

                    EPSG: 4326 uses a coordinate system on the surface of a sphere or ellipsoid of reference.
                    EPSG: 3857 uses a coordinate system PROJECTED from the surface of the sphere or ellipsoid to a flat surface.
                    Think of it as this way:
                    EPSG 4326 uses a coordinate system the same as a GLOBE (curved surface). EPSG 3857 uses a coordinate system the same as a MAP (flat surface).

                    Google Earth is in a Geographic coordinate system with the wgs84 datum. (EPSG: 4326)
                    Google Maps is in a projected coordinate system that is based on the wgs84 datum. (EPSG 3857)
                    The data in Open Street Map database is stored in a gcs with units decimal degrees & datum of wgs84. (EPSG: 4326)
                    The Open Street Map tiles and the WMS webservice, are in the projected coordinate system that is based on the wgs84 datum. (EPSG 3857)
                    So if you are making a web map, which uses the tiles from Google Maps or tiles from the Open Street Map webservice, they will be in Sperical Mercator (EPSG 3857 or srid: 900913) and hence your map has to have the same projection.

                    
                    All of this further confused by that fact that often even though the map is in Web Mercator(EPSG: 3857), the actual coordinates used are in lat-long (EPSG: 4326). This convention is used in many places, such as:
                    In Most Mapping API,s You can give the coordinates in Lat-long, and the API automatically transforms it to the appropriate Web Mercator coordinates.
                    While Making a KML, you will always give the coordinates in geographic Lat-long, even though it might be showed on top of a web Mercator map.
                    Most mobile mapping Libraries use lat-long for position, while the map is in web Mercator.

                    EPSG:3857 calls its units metres, but they are not real metres. The more to the north you come, the more squeezed they are
                    Google uses Google Mercator (EPSG:3857 or EPSG:900913) for displaying, but I think you/the Javascript API want lat/lon coordinates for input. see here https://spatialreference.org/ref/sr-org/google-projection/
                    OpenLayers is capable of dealing with most projections. If you do not explicitly set one, your map is going to use our default which is the Web Mercator projection (EPSG:3857). 
                    The same projection is used e.g. for the maps of the OpenStreetMap-project and commercial products such as Bing Maps or Google Maps.


           */


          var ___unproj_coordinate = _geometry_.coordinates

          var _geometry_type_ = _geometry_.type

          var ___reproj_coordinate;

          
          switch(_geometry_type_.toLowerCase()){

            case 'point':
              // code block
              ___reproj_coordinate = proj4(from_projection_EPSG,  to_projection_EPSG, ___unproj_coordinate);


              break;



            case 'polygon':
              // code block

              break;


            case 'line':
                // code block

                break;



            case 'multipolygon':
                  // code block

                  break;



            default:
              // code block





          } // case 


                            
         





          _geometry_.coordinates = ___reproj_coordinate


           return _geometry_

         }

It looks like your main issue here is your build setup and various tools you are integrating with. Not sure there is really an issue related to reproject itself?