Giter Site home page Giter Site logo

kartena / proj4leaflet Goto Github PK

View Code? Open in Web Editor NEW
586.0 586.0 172.0 888 KB

Smooth Proj4js integration with Leaflet.

Home Page: http://kartena.github.io/Proj4Leaflet/

License: BSD 2-Clause "Simplified" License

HTML 0.18% JavaScript 97.37% CSS 2.41% Shell 0.04%

proj4leaflet's People

Contributors

akx avatar bennlich avatar brentfraser avatar dpzaba avatar drnextgis avatar emacgillavry avatar fnicollet avatar icetan avatar jleh avatar jmvivo avatar keyjote avatar leplatrem avatar mattiasb avatar mourner avatar nice-min avatar perliedman avatar semone avatar sheppard avatar simon04 avatar stockholmsnovis avatar tablackmore avatar theashyster avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

proj4leaflet's Issues

L.Proj.TileLayer.TMS doesn't work if tms option is set to true

If creating a TMS tile layer and setting the option tms to true, the layer will not work properly.

Settings the tms option will enable Leaflet's own TMS logic, which in versions prior to 0.7 was hardwired against spherical Mercator, defeating the purpose of using L.Proj.TileLayer.TMS.

This is extra unfortunate since it looks sensible to enable the TMS option when using TMS.

Offsets with landscape bbox

I suppose there is something wrong with origin usage for landscape bounding boxes.

With the same array of resolutions in TileCache and Leaflet, Proj4Leaflet works perfectly with portrait bbox, but suffers an offset if bbox is landscape (width>height).

You can find a complete example that demonstrate the problem:
http://mathieu-leplatre.info/media/2013-proj4leaflet/

In the above example, I compute resolutions the same way as TileCache (they are printed out as proof)

Using static resolutions/scale array does not solve the problem.

Problems with 102012 projection reappeared after upgrading to leaflet 0.4

Hi guys!

I had an issue with 102012 proj - solved and closed.
#11

But now I've upgraded to leaflet 0.4 and I'm starting to get messages
"The requested tile is outside the bounding box of the tile map."
from my tile server.

I've added scale to map.options.crs.scale, like in example.
Has anything changed in L.Transformation?

Marker position / map center when using Proj4Leaflet (EPSG:3946)

Hello,
Thanks for this contribution to Leaflet, very useful.
I am using a TMS with this service description:
http://carto3.lyon.fr/cgi-bin/tms/tilemap.pl?SERVICE=TMS&PORT=1300&SERVICE_NAME=vdl
Here is my integration script:

var res = [156543.033928, 78271.516964, 39135.758482, 19567.879241, 9783.939621, 4891.96981, 2445.984905, 1222.992453, 611.496226, 305.748113, 152.874057, 76.437028, 38.218514, 19.109257, 9.554629, 4.777314, 2.388657, 1.194329, 0.5971645, 0.29858225];
var start = new L.LatLng(45.8, 5);
var crs = L.CRS.proj4js('EPSG:3946'
    ,'+proj=lcc +lat_1=45.25 +lat_2=46.75 +lat_0=46 +lon_0=3 +x_0=1700000 +y_0=5200000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs'
    ,new L.Transformation(1, 0, -1, 0));
var map = new L.Map('map', {
  crs: crs,
  scale: function(zoom) {
    return 1 / res[zoom];
  }
  ,continuousWorld: true
});
var mapUrl = 'http://carto3.lyon.fr/tms/1300/vdl/{z}/{x}/{y}.png';
var attrib = 'Aigle map';
var tilelayer = new L.TileLayer(mapUrl, {
  scheme: 'tms'
  ,maxZoom: 19
  ,minZoom: 0
  ,continuousWorld: true
  ,attribution: attrib
});
map.addLayer(tilelayer);
map.setView(start, 6);
var marker = new L.Marker(start);
map.addLayer(marker);

When I open the map, it is completly offset, the map is actually down south, easier to reach if you unzoom a few times. When I add a Marker, it is also completly off.
That's surely because I pass a L.LatLng object to the map and to the marker with unprojected coordinates but I don't know how to do it another way.
Could you give me a hand please?

Thanks a lot,
Fabien

Different CRS instances do not necessarily share same options

L.Proj.CRS.prototype.initialize(code, def, options);

While showing two maps with EPSG:3413, but different resolutions, the second call of above line overwrites the options of the first CRS. Using:

L.setOptions(this, options);

directly afterwards solved it, but I'm not sure whether side effects exists on untested conditions.

Tiles not positioned correctly

Thanks for your effort on integrating Proj4js with Leaflet!

I've tried to use Proj4Leaflet to load a tilset in UTM33 (EPSG:25833):

var map = new L.Map('map', {
  crs:  L.CRS.proj4js('EPSG:25833', '+proj=utm +zone=33 +ellps=GRS80 +units=m +no_defs'),
  scale: function(zoom) {
    return 1 / res[zoom];
  },
  continuousWorld: true
});

The tile URLs generated by Leafet don't correspond to our tileset. Leaflet creates URLs with negative x, y values, while our tileset only have positive x and y values (the tileset origin is upper left).

Does Proj4Leaflet assume a specific tile organization?

Defining projections based on WMS GetCapabilities information

Hi,

When I send a GetCapabilities request to a wms server, I receive for each layer an EPSG code and bounding box. In openlayers they are enough to define a projection, it is really as simple as

var projection = ol.proj.configureProj4jsProjection({
  code: 'EPSG:21781',
  extent: [485869.5728, 76443.1884, 837076.5648, 299941.7864]
});

I have reasons to prefer Leaflet, but I'm a bit at loss why I need to define the projections so explicitly in proj4Leaflet. Does openlayers do a lot of magical mathematics to get from the epsg code and extent to the full crs specification?

I guess my main question is: can someone estimate how difficult it would be to make projection definitions so easy in leaflet that one could define the crs based on the response of GetCapabilities?

Error: Projected bounds does not match grid at zoom 0

Greetings! The following code gives the error:
"Error: Projected bounds does not match grid at zoom 0"
What could be wrong with the code?

var crs = new L.Proj.CRS.TMS('EPSG:25832',
'+proj=utm +zone=32 +ellps=GRS80 +units=m +no_defs',
[265948.8191, 6421521.2254, 677786.3629, 7288831.7014],
{
resolutions: [
132.2919312505292,
79.37515875031751,
39.687579375158755,
26.458386250105836,
13.229193125052918,
5.291677250021167,
2.6458386250105836,
1.3229193125052918,
0.6614596562526459,
0.5291677250021167,
0.26458386250105836,
0.13229193125052918,
0.06614596562526459
]
});

var map = new L.Map('map', {
crs: crs,
continuousWorld: true,
worldCopyJump: false
});

var tileUrl = 'http://kart.fredrikstad.kommune.no/arcgis/rest/services/Felles/GrunnkartFarge/MapServer/tile/{z}/{y}/{x}', attrib = 'kjghgj', tilelayer = new L.Proj.TileLayer.TMS(tileUrl, crs, { maxZoom: 12 ,minZoom: 0 ,continuousWorld: true ,attribution: attrib }); map.addLayer(tilelayer); map.setView([59.08009, 11.73615], 0);

Question: EPSG:3031, no "stere" in proj4.js

I've noticed that the proj4.js provided with Proj4Leaflet does not have "stere" included which is used in the definition of EPSG:3031 (Antarctic Polar Stereographic). It does have "sterea" but it does not appear to be a drop-in replacement. While I don't completely understand the differences between the two, EPSG:3031 was not working for me when using "sterea" and would give an NaN value when getting the view extent. I hacked the "stere" support back into the provided proj4.js and everything seemed to work fine.

I'm not sure what the origin of the distributed proj4.js is in this project. Is it just a require.js-ified version of the NPM? Is there anyway "stere" could be included back in?

Problem with TMS tiled EPSG:3067 map

Hello!

..this is actually more like a support request than an issue.

Anyway, I'm trying to get a TMS tiled map of a local area working with Proj4Leaflet. I used gdal2tiles to create tiles from 6 tif -maps with EPSG:3067 coordinate system.
(National Land Survey of Finland provides pretty extensive maps of Finland for free, http://www.maanmittauslaitos.fi/en)

The problem is that I cannot get the map to display at all with it's proj4 projection in leaflet. I started to experiment with Proj4Leaflet provided tms-tiled example and modified it so that it would get the job done with EPSG:3067 and my custom maps:

var crs = new L.Proj.CRS.TMS('EPSG:3067',
    '+proj=utm +zone=35 +ellps=GRS80 +towgs84=0,0,0,-0,-0,-0,0 +units=m +no_defs',
    [6810000, 308000, 6834000, 344000],
    {
        resolutions: [
                256,
                128,
                64,
                32,
                16,
                8,
                4,
                2,
                1
        ]
    });

var map = new L.Map('map', {
    crs: crs,
    continuousWorld: true,
    worldCopyJump: false
});


var tileUrl = '{z}/{x}/{y}.png',
    attrib = '© Testi',
    tilelayer = new L.Proj.TileLayer.TMS(tileUrl, crs, {
        maxZoom: 8
        ,minZoom: 0
        ,continuousWorld: true
        ,attribution: attrib
    });

map.addLayer(tilelayer);
map.setView([61.46875, 23.56964], 4);

This only seems to get me a grey leaflet template with no map. I have made the modifications on the example based on tilemapresource.xml -file generated by gdal2tiles and gdalinfo output for my map.

proj4 from gdalinfo -proj4 Temp2.vrt: (same as in http://www.spatialreference.org/ref/epsg/3067/ ?)

PROJ.4 string is:
'+proj=utm +zone=35 +ellps=GRS80 +towgs84=0,0,0,-0,-0,-0,0 +units=m +no_defs '

Tilemapresource.xml:

<?xml version="1.0" encoding="utf-8"?>
    <TileMap version="1.0.0" tilemapservice="http://tms.osgeo.org/1.0.0">
      <Title>Temp2.vrt</Title>
      <Abstract></Abstract>
      <SRS>PROJCS["unnamed",GEOGCS["unnamed",DATUM["Euref_98",SPHEROID["GRS 80",6378137,298.257222101],TOWGS84[0,0,0,-0,-0,-0,0]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",27],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["Meter",1]]</SRS>
      <BoundingBox minx="6810000.00000000000000" miny="308000.00000000000000" maxx="6834000.00000000000000" maxy="344000.00000000000000"/>
      <Origin x="6810000.00000000000000" y="308000.00000000000000"/>
      <TileFormat width="256" height="256" mime-type="image/png" extension="png"/>
      <TileSets profile="raster">
        <TileSet href="0" units-per-pixel="256.00000000000000" order="0"/>
        <TileSet href="1" units-per-pixel="128.00000000000000" order="1"/>
        <TileSet href="2" units-per-pixel="64.00000000000000" order="2"/>
        <TileSet href="3" units-per-pixel="32.00000000000000" order="3"/>
        <TileSet href="4" units-per-pixel="16.00000000000000" order="4"/>
        <TileSet href="5" units-per-pixel="8.00000000000000" order="5"/>
        <TileSet href="6" units-per-pixel="4.00000000000000" order="6"/>
        <TileSet href="7" units-per-pixel="2.00000000000000" order="7"/>
        <TileSet href="8" units-per-pixel="1.00000000000000" order="8"/>
      </TileSets>
    </TileMap>

Am I missing something? I don't really understand all the things regarding map projections, but shouldn't this be enough to define the map for Proj4Leaflet?

I managed to get the map to show with plain Leaflet with tms : true, but obviously the coordinate system got all messed up since the real map projection is on a different continent.

Example is broken

After I fixed the issue with the incorrect reference that's waiting in pull request #21 , I found that the map was broken anyway. It seems the map tiles are being placed incorrectly. In Firefox they're placed incorrectly with a number of blank areas between, while Chrome and IE manage to fill the screen but with all tiles in the wrong positions relative to each other.

EPSG:25832 problem.

Hello everybody.
Can anybody help me setup up the projection for the ETRS89 / UTM zone 32N (EPSG:25832) I can't find anything on it.
Best Regard Morten Starck

"Walking" map with custom projection

I have made two very simple map setups (based on "https://github.com/bartvde/PDOK-Leaflet". Both maps show more or less the same area. Panning is bounded by "setMaxBounds". One map uses default Leaflet projection, the other map uses the RD projection (EPSG 28992).

Data can be found here: https://dl.dropboxusercontent.com/u/8713747/walking_maps.zip

When zooming in and/or panning through the map, I notice strange behaviour on the map with RD-projection. It looks like it's related to browser size and map zoomlevel, but effects are different in different browsers and differend window sizes.

In case setMaxBounds is not called (so the user can pan to anywhere), 'walking' does not occur either.

It does not occur for the map with default projection, so I assume it has to do with Proj4Leaflet.

Cheers, Koen

Trouble with EPSG:2154

Hi,

I have troubles using the following code

map = new L.Map('map', {
  crs: L.CRS.proj4js('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'
    ,new L.Transformation(1, 0, -1, 0))
  });

I just add a Canvas layer such as :

canvasTiles.drawTile = function(canvas, tilePoint, zoom) {
var ctx = canvas.getContext('2d');
ctx.rect(0,0, 256,256);
ctx.stroke();
ctx.fillText('(' + tilePoint.x + ', ' + tilePoint.y + ')',5,10);

            });

Such layer draw a grid with tile coord on vanilla Leaflet. But with the map on EPSG:2154, nothing happen. I try to play with transformation parameters without success.

Is there something wrong with my map declaration ?

Thanks in advance for your support

Leaflet 0.4 compability

In Leaflet 0.4, the scale method is moved from L.Map to L.CRS.

This don't work:

var map = new L.Map('map', {
crs: L.CRS.proj4js('EPSG:32632', '+proj=utm +zone=32 +ellps=WGS84 +datum=WGS84 +units=m +no_defs', new L.Transformation(1, -432000, -1, 6850000)),
scale: function(zoom) {
return 1 / (234.375 / Math.pow(2, zoom));
}
});

This works:

var crs = L.CRS.proj4js('EPSG:32632', '+proj=utm +zone=32 +ellps=WGS84 +datum=WGS84 +units=m +no_defs', new L.Transformation(1, -432000, -1, 6850000));

crs.scale = function(zoom) {
return 1 / (234.375 / Math.pow(2, zoom));
};

var map = new L.Map('map', {
crs: crs
});

Maybe the scale function could be added as a parameter to L.CRS.proj4js?

Bjรธrn

Provide easy way to get grid transformation matrix

Since it is the tricky part of Proj4Leaflet usage, I guess it could be possible to provide a couple of transformation matrices by default, depending on spatial reference system specified and providing bbox (xmin,ymin,xmax,ymax) and tms (boolean) arguments.

If projection is unknown, current behaviour would be fine.

Your article suggests that a default rule can be applied :

if (tms) 
    return (1, NW.lng, -1, NW.lat)
else
    return (1, SW.lng, 1, SW.lat)

Missing semi-colon

Hi,

In the file proj4leaflet.js, there are missing ";" add the end of the function L.Proj._isProj4Proj and at the the end of the file.

Confused on how CRS with TMS works

Hi,

Recently I started developing a Leaflet mapviewer for use in a mobile application. I am using my company's own tileserver and custom projection, so I tried implementing Proj4Leaflet's CRS with TMS.

However, I can't seem to get my projection working properly. I'm a bit confused as to which type of coordinate I need to pass for the projection settings. We have our own type of coordinates that are roughly 1 meter per coordinate, which we can convert to WGS84 and back via a complicated js method. I am a pretty big GIS newbie, so I don't immediately know if I should use my own coordinates or WGS84 in for example the 'center' property.

Could you maybe help me understand what I am doing wrong? If this is the wrong place to ask these questions, please say so and I'll try it on Stackoverflow or similar. Here is a redacted version of my code:

var bbox = [0, 0, 5000000, 5000000]; // Bounding box in our own coordinates
var sp2Proj = new L.Proj.CRS.TMS('EPSG:x',
      'ourOwnProj4Def',
      bbox,
      {         
        scales: [0.8,1.6,3.2,6.4,12.8,25.6,51.2,102.4,204.8,409.8], // Scales we use 
        origin: [0,0] // Origin is at 0,0 our coordinates
      });
var map = L.map('map', {            
    zoom: 7,
    center: [1550000, 1920000], // These are our coordinates we would like to center on
    crs: sp2Proj,
    continuousWorld: false,
    worldCopyJump: false,
    inertia: true
});

map.addLayer(new L.Proj.TileLayer.TMS('http://ourtileserver.com/ts?&x={x}&y={y}&z={z}', sp2Proj, {
    maxZoom: 10,
    minZoom: 1,
    tileSize: 250,
    attribution : 'Copyrighted by x',
    noWrap : true,
    zoomReverse: true 
}));

[Help] Migrate Openlayers project to Leaflet

Hi guys,

  • This is not an issue, just an ask for support *

I am transcribing my problem posted here: https://groups.google.com/forum/#!topic/leaflet-js/rhmfMdfzruc

Hi All,

I am trying to migrate an old application using OpenLayers as viewer to Leaflet.
That application uses custom tiles in the form z,x,y where z is zoom level and x/y as...

0,0 1,0, 2,0
0,1 1,1 2,1
0,2 1,2 2,2

I've been using TMS layers, EPSG:26912 projection and a custom getUrl function that
compute the url of the tile.

Can you give me some advice how I can implement the same with Leaflet?

Thanks in advance!

Projections based on zoom level

Hi,

I would like to connect IGN WMS server (a French institute) to Leaflet. The problem is they define two projections based on zoom level :

Before Zoom level 3 they use :

Proj4js.defs['EPSG:310642901']= '+title=Geoportail - Monde +proj=mill +towgs84=0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.000000 +a=6378137.0000 +rf=298.2572221010000 +lon_0=0.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs';

And after zoom level 3 :

Proj4js.defs['EPSG:310024802']= '+title=Geoportail - France metropolitaine +proj=eqc +nadgrids=null +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=46.500000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs';

As you can see I was using Proj4JS when I read an issue on Leaflet GIThub, linking your project.
Your example show me how to use one projection, allthought I don't understand transformation matrix parameter.

So the question is maybe more a Leaflet question than Proj4Leaflet, but If I set these 2 projections, how can I tell to Leaflet to switch the projections ?

Thanks in advance.

Sweref and WMS problems..

Hi,

I have som problem getting a wms up and running with leaflet/proj4leaflet using sweref99..

This is my code, any ideas on how to get this running whould be much appreciated:


var map;
Proj4js.defs["EPSG:3006"] = "+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs";
var res = [4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 0.5];
    
    var topo = new L.TileLayer.WMS("http://localhost:8080/wms", {
        layers: 'topo',
        format: 'image/jpg',
        continuousWorld: true
    });

    map = new L.Map('map', {
        crs: L.CRS.proj4js('EPSG:3006', '+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs',
                new L.Transformation(1, -200000, -1, 6100000)),
        center: new L.LatLng(60,15),
        zoom: 5,
        layers: [topo],
        continuousWorld: true,
        scale: function(zoom) {
            return 1 / res[zoom];
          }
    });

This works nicely using WGS84:


    var topo = new L.TileLayer.WMS("http://localhost:8080/wms", {
        layers: 'topo',
        format: 'image/png',
        transparent: true
    });
        
    map = new L.Map('map', {
        crs: L.CRS.EPSG4326,
        center: new L.LatLng(60, 15), 
        zoom: 5,
        layers: [topo],
        zoomControl: true
    });

Support for EPSG7128 projection and WMS layer

Hi, first of all, thankyou for this. It's a mayor lifesaver for me if I can make this work.

I'm trying to fit my map into the example I downloaded from you guys and I can't seem to make it work, below you'll find the script.js file with my data.
Also I have to examples of my map working in openlayers in case you want to take a peek:
http://mapa.buenosaires.gov.ar/
http://usig.buenosaires.gov.ar/m/ (mobile version, still under development, but a much simpler code)

I just want to know if there's something I might me doing wrong, but I can't seem to find anything

var res = [90, 50, 30, 15, 7.5, 4, 2, 1, 0.5, 0.2]
,start = new L.LatLng(-34.629243, -58.463196)
,map = new L.Map('map', {
crs: L.CRS.proj4js('EPSG:7128'
,'+lon_0=-58.463196 +lat_0=-34.629243 +k=0.999998 +x_0=100000.0 +y_0=100000.0 +proj=tmerc +ellps=intl +units=m +no_defs'
,new L.Transformation(1, 0, -1, 0))
,scale: function(zoom) {
return 1 / res[zoom];
}
,continuousWorld: false
})
,mapUrl = 'http://tiles1.mapa.buenosaires.gob.ar/tilecache/'
,attrib = 'Map data ยฉ 2011 USIG, Imagery ยฉ 2011 USIG'
,tilelayer = new L.TileLayer.WMS(mapUrl, {
scheme: 'tms'
,maxZoom: 18
,minZoom: 1
,continuousWorld: false
,format: 'image/png'
,transparent: true
,attribution: attrib
,layers: 'mapabsas_default'
});
map.addLayer(tilelayer);
map.setView(start, 5);

Projection (offset) issue with ImageOverlay (esri-leaflet)

We've been struggling for a while with an offset in an ImageOverlay.
The ImageOverlay comes from a dynamic layer from the esri leaflet plugin.

A correctly working example without proj4leaflet can be found here:
http://jsfiddle.net/_Tom_/L9Ax8/

The example with the issue is here:
http://jsfiddle.net/_Tom_/ueRa8/

You will notice that while zooming out the dynamic layer gets an offset to the East.

We've been able to trace this down to a function in leaflets ImageOverlay where the position of the image is calculated based on a latLngToLayerPoints (see below). Apparently this is where the projection goes wrong but we can't see how.

_reset: function () {
        var image   = this._image,
            topLeft = this._map.latLngToLayerPoint(this._bounds.getNorthWest()),
            size = this._map.latLngToLayerPoint(this._bounds.getSouthEast())._subtract(topLeft);

        L.DomUtil.setPosition(image, topLeft);

        image.style.width  = size.x + 'px';
        image.style.height = size.y + 'px';
    }

Proj4Leaflet doc detail/examples

Should the proj4leaflet docs be a little more detailed regarding uses of the lib? Someone asked a seemingly straightforward question on gis exchange: http://gis.stackexchange.com/questions/55043/reprojecting-coordinates-and-geojson-in-leaflet. It apparently isn't obvious to him/her after reading the Proj4Leaflet docs whether Proj4Leaflet can be used to project a vector layer onto tiles in a different coordinate system. Is this the sort of thing that should be covered in the docs? (It's not obvious to me either, actually. Maybe it's more obvious to someone more experienced with projection in slippymap clients?)

Leaflet custom projection transform issue with leaflet 0.7.3

In L.Proj.CRS.TMS there are options that does not work at all. For example:

  • scales
  • transformation
  • origin

here is code i use:

var crs = new L.Proj.CRS.TMS(
            'EPSG:3006',
            '+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs',
            [-1171937.8799031, 5258558.13502446, 2298450.72267515, 8270258.08008982],
            {
                //origin: [-5682840.1442831, 10997760.6947701],
                transformation: new L.Transformation(1, 10997760.6947701, -1, 5682840.1442831),
                resolutions: [
                    1984.37896875794,
                    926.043518753704,
                    264.583862501058,
                    132.291931250529,
                    52.9167725002117,
                    26.4583862501058,
                    13.2291931250529,
                    5.29167725002117,
                    2.64583862501058
                ],
            }
        );

        var map = L.map('mapDivTest', {
            crs: crs,
        });

        map.on('click', function(e) {
            console.log(e.latlng);
        });


        var basemap = L.tileLayer("http://geoservices.lst.se/ArcGIS/rest/services/bakgrundskartor_vektor/MapServer/tile/{z}/{y}/{x}.png",
        {
            minZoom: 0,
            maxZoom: 8,
            continuousWorld: true,
        }).addTo(map);

Previously working EPSG:27700 not working with 0.7

Hi, I have been using Proj4Leaflet for a while and just updated to Leaflet 0.7 and also updated Proj4Leaflet and proj4js to the latest recommended versions. After updating, my xyz layers are not working and I can't quite figure out what is going on.

My code looked something like this:

var crs = new L.Proj.CRS('EPSG:27700',
  '+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs', {
  resolutions: [
    5078.125,
    2539.0625,
    1269.53125,
    634.765625,
    317.3828125,
    158.69140625,
    79.345703125,
    39.6728515625,
    19.8364257813,
    9.9182128906,
    4.9591064453
  ],
  transformation: new L.Transformation(1,300000,-1,1300000)
});

var map = L.map('map', {crs: crs}).setView([51.507222,-0.1275], 4);

var layer = L.tileLayer('https://my,server/{z}/{x}/{y}', {
  maxZoom: 10,
  minZoom: 0
});

   map.addLayer(layer);

This would produce a map that is centered on London, England. After updating, the same code does not load any tiles.

As far as I can tell from tracing what happens to the tiles, when it gets into _tileShouldBeLoaded(), the value of limit returned by this.getWrapTileNum() ends up being an exceedingly small number (e^-7) and thus tilePoint.x >= limit.x fails and only the top left tile (0,0 in tile coordinates) ever gets added to the DOM in any given zoom level.

When zooming out to level 0, it seems like London is centered in the map viewport so I think the location is correct - it just doesn't load tiles other than the top left one.

Any insight would be welcome.

Strange moving markers and non moving ImageLayers during pinch zoom action

In my Leaflet project I'm using Proj4Leaflet with EPSG:28992 (RD_NEW) http://spatialreference.org/ref/epsg/28992/ which works pretty nice but I found some issues with markers and ImageLayers when zooming in and out using pinch zoom.

While pinch zooming on the map you can see the markers moving but don't stick to their exact place but animate back to their right position again after the zoom action is finished. ImageLayers also have this behaviour but instead of moving while pinch zooming they stay at the exact spot but animate to the right location again when you are finished zooming. The problem does not occur when using the scrollwheel.

If I use Leaflet 0.7.1 build in CRS for instance: 4326 it all works fine but in case of 28992 I get this behaviour. Any idea?

JSFiddle: http://jsfiddle.net/3TTqd/4/

L.Proj.GeoJSON doesn't add all featuers when the geoJson has a more than 1 features

I am trying to use L.Proj.GeoJSON with a geoJson which contains multiple features (polygon, points and a multiPolygon).
Anyway, it ends up that only the first feature is shown in the map and the rest do not.

Investigating a bit, I found out that the addData is called recursibly from L.GeoJSON which after the first feature is added, the finally part is called and this is runned:
delete this._inBaseAddData;
What that means, is that the next time addData is called (so, for the next feature), the following line will be called in L.Proj.GeoJSON.addData
delete this.options.coordsToLatLng;
and with that, the rest of the features will not get a reprojection and that is why it seems that only one feature is added.

I have solved the problem by renaming the method L.Proj.GeoJSON.addData to L.Proj.GeoJSON._addData, so it is only called from L.Proj.GeoJSON and not from L.GeoJSON.

This change seems to fix that problem and when running the tests for this project all tests pass.

Is this a correct solution or is there something that I am missing?

projected bounds and nonexistent tiles

Hello.

I have problems with setting map bounds in projected coordinates.

My map is in oblique stereographic projection: '+proj=sterea +lat_0=50 +lon_0=100 +k_0=1.0 +x_0=0 +y_0=0'. Its extent is [minx, miny, maxx, maxy]: [-6e6, -4e6, 4e6, 6e6].

If I don't set any bounds, I get lots of requests to nonexistent tiles. See map_without_bounds.

Setting L.Proj.CRS constructor bounds option does not prevent requests. See map_with_crs_bounds.

To deal with it L.TileLayer constructor accepts bounds option, but in latlng coordinates. If I set bounds like that ...

var map = L.map('map', {
    crs: new L.Proj.CRS('EPSG:9809',
        '+proj=sterea +lat_0=50 +lon_0=100 +k_0=1.0 +x_0=0 +y_0=0',
        {
            resolutions: [39062.5, 19531.25, 9765.625, 4882.8125, 2441.40625, 1220.703125],
            origin: [-6e6, 6e6]
        }
    ),
    center: L.latLng(68, 90),
    zoom: 3,
    layers: [
        new L.TileLayer(
            'http://81.5.88.53/russia_tiles/{z}/{x}/{y}.png',
            {
                maxZoom: 5,
                minZoom: 2,
                continuousWorld: true,
                bounds: L.latLngBounds(L.latLng(70, 30), L.latLng(40, 150))
            }
        )
    ]
});

Leaflet requests map tiles from nonrectangular area. See map_with_layer_latlng_bounds.

Is there a way to set layer bounds in projected coordinates.

mixing projections

I realize that it in general, it is poor practice to mix projections (LL84, and WebMercator) in one map. But I might have special case where at high level zooms (14+) the world is flat enough that if you align the corners of tile, it should be similar.

Is there a way that I could test my "foolishness" out with Proj4Leaflet. Here is what I have so far. The BlueMarbleMap() is a EPSG4326 NASA Blue Marble tile map of the world (non-tms),

and CloudMade is hosting the non-TMS OSM map (I want to add the L.Proj.CRS.TMS() projection for EPSG3857, but the API only lets me do that for new L.Proj.TileLayer.TMS()

var MAP = null;
var BaseLayers = {};
var OverLayers = {};

// executed when all js and css is loaded (i.e. document ready event)
$(function () {
setup();
});

function setup() {
initMap();
BlueMarbleMap();
OSMmap();
//KartenaMap();
PolandMap();
addControls();
}

function initMap() {
var krakow = new L.LatLng(50.056, 19.937);
var mapOptions = {
center: krakow,
zoom: 8,
crs: L.CRS.EPSG4326,
attributionControl: false,
};
MAP = L.map('map', mapOptions);
}

function BlueMarbleMap() {
var label = {};
var layer = L.tileLayer("http://ysg4206.draper.com/WorldLL84Tiles/{z}-{x}-{y}.jpg", {
attribution: 'NASA'
});
MAP.addLayer(layer);
label["BlueMarble"] = layer;
$.extend(BaseLayers, label);
}

function PolandMap() {
var label = {};
var layer = L.tileLayer("http://ysg4206.draper.com/PolandQuad4326/{z}-{x}-{y}.png", {
attribution: 'Poland'
});
MAP.addLayer(layer);
label["Poland LL84"] = layer;
$.extend(OverLayers, label);
}

function OSMmap() {
var label = {};
//var url = "http://{s}.tile.cloudmade.com/9c844409f5b845ae93ac38388077f90a/997/256/{z}/{x}/{y}.png";
var url = "http://tilecache.osgeo.org/wms-c/tilecache.py/1.0.0/basic/{z}/{x}/{y}.png";
var layer = L.tileLayer(url, {
attribution: 'CloudMade OSM',
tms: false,
opacity: 0.5
});
MAP.addLayer(layer);
label["OSM"] = layer;
$.extend(OverLayers, label);
}

function addControls() {
var layersControl = new L.Control.Layers(BaseLayers, OverLayers);
MAP.addControl(layersControl);
}

Troubles with GeoJSON

Hi,

First of all, thanks for your cool plugin :)
I have a GeoJSON with points using EPSG:2154 and I'm a bit confused on how to display them.

I think that, even if I configured my map in EPSG:2154, it still expects 4326.

Is there a way around it ?

Thank you.

TMS layer with custom resolutions not giving the proper coordinates

This is not a bug report. It's more of a cry for help

Sorry about posting this here but since I'm dealing with a custom projection I figured out this didn't belong in the LeafletJS forum.

I was a given set of tiles and an OpenLayers map. I wanted to migrate that to LeafletJS.

Although it's a simple TMS layer with the tiles generated in EPSG:900913, I figured that I have a custom set of resolutions. That's why I ended up using the Proj4Leaflet plugin.

I can see the map but zooming in/out doesn't take me to the place where the zoom was made. Also, clicking on the map doesn't return the correct coordinates.

I have set up a demo here: http://queixinhas.com/map_test/

The code is all in this file: http://queixinhas.com/map_test/app2.js

You can see the LeafletJS map and the OpenLayers map.

I thought it was a matter os providing the resolutions array and tile origin but apparently I'm missing something.

Btw, I had to comment line 116 on proj4leaflet.js file because I was getting the "Projected bounds does not match grid at zoom 0" error. This might be the cause of the problem...

Again, sorry for posting this help request here, I'm happy to move it to another place if you wish of course.

Any help would be appreciated, thanks!

L.Proj.TileLayer.TMS has unnecessary constraints on bounds

L.Proj.TileLayer.TMS currently uses the max y of the projected bounds to calculate the origin used by Leaflet (the CRS transform) to place markers etc. The origin must align with the tile grid, although the bounds often does not.

The origin should be calculated by rounding upwards to align with the grid, instead of using the bounds directly. Doing so, the validation check performed in the constructor can be removed.

Custom Projection not working

I've been trying to get EPSG:2263 working with Proj4Leaflet and haven't had any luck so far. All I get is a gray map area. I have an aerial tif image that I broke into tiles using MapTiler (http://www.maptiler.org/). The options in the tool allowed me to georeference the image and select my spatial reference system.

I tried following what was suggested here #28 (comment) and adjusting the values for my projection, but nothing seems to work. I don't get any errors and I tried to step through the source on both calls into leaflet and it seemed like the no tiles were being added to the queue in _addTilesFromCenterOut, but now I can't even get into that call and can't figure out what change I made caused that.

I used the bounding extents defined in an xml file that I got with the tif to create the bounds array. Looks like it came from esri or arcgis

<westBL Sync="TRUE">1030000.000000</westBL>
<eastBL Sync="TRUE">1055600.000000</eastBL>
<southBL Sync="TRUE">164500.000000</southBL>
<northBL Sync="TRUE">182500.000000</northBL>

My tiles are local right now, working on transferring them to an example setup. I'll update with a link to it once they are done transferring. For now here's the code I'm working with.

<script>
var resolutions = [256, 128, 64, 32, 16, 8, 4, 2, 1];
// these values were generated by maptiler so I tried to use them with no luck
//var resolutions = [127.99999999999942, 63.99999999999971,  31.99999999999985, 
//15.99999999999993, 7.99999999999996, 3.99999999999998, 1.99999999999999, 
//0.50000000000000,  0.25000000000000]; 

var crs = new L.Proj.CRS.TMS('EPSG:2263', '+proj=lcc +lat_1=41.03333333333333 
+lat_2=40.66666666666666 +lat_0=40.16666666666666 +lon_0=-74 ' + 
'+x_0=300000.0000000001 +y_0=0 +ellps=GRS80 +datum=NAD83 
+to_meter=0.3048006096012192 +no_defs ',
           [1030000, 182500, 1055600, 164500],
            {
                resolutions: resolutions
            }
        );

        var map = new L.Map('map', {
            crs: crs,
            continuousWorld: true,
            worldCopyJump: false
        });

        var tileUrl = 'Tiles/{z}/{x}/{y}.png',
            tilelayer = new L.Proj.TileLayer.TMS(tileUrl, crs, {
                maxZoom: 8
                , minZoom: 0
                , continuousWorld: true
            });
    </script>

tms requests for projection 102012 generate incorrect tile paths

I'm trying to setup my map in Asia Lambert Conformal Conic 102012 projection (http://spatialreference.org/ref/esri/102012/).

I've modified the example code to be:

var res = [
       140000.0000000000,
        70000.0000000000,
        35000.0000000000,
        17500.0000000000,
         8750.0000000000,
         4375.0000000000,
         2187.5000000000,
         1093.7500000000,
          546.8750000000,
          273.4375000000,
          136.7187500000,
           68.3593750000,
           34.1796875000,
           17.0898437500,
            8.5449218750,
            4.2724609375,
            2.1362304688,
            1.0681152344],
start = new L.LatLng(55.727, 37.639), 
map = new L.Map('map', {
  crs: L.CRS.proj4js('EPSG:102012',
    '+proj=lcc +lat_1=30 +lat_2=62 +lat_0=0 +lon_0=105 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs',
    new L.Transformation(1, 4558997.24908565, -1, 5368033.51782977)),
   scale: function(zoom) {
    return 1 / res[zoom];
  },
  continuousWorld: true
}),
mapUrl = 'http://localhost:10000/tiles/1.0.0/adm_conic_EPSG102012/{z}/{x}/{y}.png',
attrib = 'Map data &copy; 2012 OpenStreetMap contributors',
tilelayer = new L.TileLayer(mapUrl, {
  scheme: 'tms',
   maxZoom: 18,
   minZoom: 0,
   continuousWorld: true,
   attribution: attrib
});
map.addLayer(tilelayer);
map.setView(start, 3);

Tiles don't load, because the path is generated incorrectly, i.e:

http://localhost:10000/tiles/1.0.0/adm_conic_EPSG102012/0/925681/2775207.png
http://localhost:10000/tiles/1.0.0/adm_conic_EPSG102012/6/59243476/177613393.png
when it should be:

http://localhost:10000/tiles/1.0.0/adm_conic_EPSG102112/0/0/0.png
http://localhost:10000/tiles/1.0.0/adm_conic_EPSG102112/6/5/5.png
(according to OpenLayers requests)

So {x} and {y} in the tile paths are calculated incorrect
I've tried putting different extent coordinates to L.Transformation, but no luck.
Can anyone please help me with this error?

Leaflet custom projection transform issue with leaflet 0.7.2

Example http://test0.127.ru worked fine with leaflet 0.6.* and fails to work correctly with 0.7.2
Looks like the latest proj4leaflet version fails to transform coords correctly. The example I've written, should be centered by Moscow center and now it is set much more southward.

Custom projection I use is

var PGCRS = new L.Proj.CRS.TMS(
    'EPSG:3395',
    '+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs', 
    [-20037508.343, -19930481.933, 20037508.343, 20144534.753], 
    {
        resolutions: [
            null, 
            78271.51696484375,
            39135.758482421875,
            19567.8792412109375,
            9783.93962060546875,
            4891.969810302734375,
            2445.9849051513671875,
            1222.99245257568359375,
            611.496226287841796875,
            305.7481131439208984375,
            152.87405657196044921875,
            76.437028285980224609375,
            38.2185141429901123046875,
            19.10925707149505615234375,
            9.554628535747528076171875,
            4.7773142678737640380859375,
            2.388657133934688201904296875,
            1.194328566968441009521484375
        ]
    }
);

map init

map = L.map( $('.b-map')[0], {crs: PGCRS, minZoom: 1, maxZoom: 17}).setView([55.75, 37.67], 9),

tiles are set up like that

function balance (tile) {
    var h = 9, s;
    if (tile.s == 'a') s = 1;
    if (tile.s == 'b') s = 2;
    if (tile.s == 'c') s = 3;
    return s;
}

function tile (tile){
    return (tile.z +'00'+ (1000000000 + tile.x).toString().substr(1)
           + (1000000000 + tile.y).toString().substr(1)).
           replace(/^(\d{1,2})00(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})/, '$1/00/$2/$3/$4/$5/$6/$7');
}

L.tileLayer('http://h0{front}.tiles.tmcrussia.com/map/lv{path}.png', {
    front: balance,
    path: tile,
    attribution: '&copy; <a href="http://cdcom.ru" target="_progorod">CDCOM</a>',
    tms: true
}).addTo(map);

An Example is needed for plain WMS

I have a simple WMS in EPSG:32643 (UTM 43N), which is served by GeoServer. I'm trying to use Leaflet (with and without this plugin) and am failing. The map does not show my data, and no request is made to the service. This WMS is not tiled.

  • When I use this Plugin, I don't know what parameters to provide for origins.
  • I know that instead of the origins, we can use the Transformation parameter, but I could not figure out what 4 parameters to pass to the L.Transformation() constructor.

Technically it should be possible to use non-tiled WMS services, since I could successfully use a simple WMS Service in EPSG:4326, by using the the following crs constructor:

var crs = new L.Proj.CRS('EPSG:4326',
        '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs',
    {
        transformation:new L.Transformation(1 / 360, 0.5, -1 / 360, 0.5),
        resolutions: [
             0.703125, 0.3515625, 0.17578125, 0.087890625, 0.0439453125, 0.02197265625, 
             0.010986328125,  0.0054931640625, 0.00274658203125, 0.001373291015625
        ]
    });

So to summarize, it would be helpful to provide a sample which shows how to use the plugin when one does not have a tiling scheme; or how to select the parameters for the L.Transformation() constructor.

L.Proj.geoJson (null ...

Trying to not have to wait for my data to load I was attempting to do the following ...

var geoLayer = L.Proj.geoJson(null, {
pointToLayer: function (feature, latlng) {

});

$.getJSON("data.geojson", function (data) {
geoLayer.addData(data);
});

But it fails to work.

The only way I can get the Projection to work is to load the geojson in a variable and do an asych:false call.

var geojson
$.ajax({
    url: 'data.geojson',
    async: false,
    dataType: 'json',
    success: function (response) {
        geojson = response;
        $("#loading").hide();
}
});

Then this works wonderfully:
var geoLayer = L.Proj.geoJson(geojson, {
pointToLayer: function (feature, latlng) { ......

});

Any work around?

How to avoid using getTileUrl

I am trying to use a TMS from a Korean provider.
With Per Liedman's comments I could get correct coordinates without shifts by using L.Proj.CRS.TMS and L.Proj.TileLayer.TMS. However, I had to use getTileUrl to get the correct coordinates.

I had to use getTileUrl to admend y value and z value like below.
y: tilePoint.y + Math.pow(2, tilePoint.z
z: 14-tilePoint.z

Is there a way to get correct tiles without using getTileUrl?
Here are my full codes. Thanks in advance, guys.

    var crs = new L.Proj.CRS.TMS(
        'EPSG:5181',
        '+proj=tmerc +lat_0=38 +lon_0=127 +k=1 +x_0=200000 +y_0=500000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs',
        [-30000, -60000, 494288, 988576],
        {
            resolutions: [2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 0.5, 0.25]
        }
    );


    var tileUrl = "http://i{s}.maps.daum-img.net/map/image/G03/i/1.20/L{z}/{y}/{x}.png";
    var attrib = 'โ“’ 2012 Daum';
    var tilelayer1 = new L.Proj.TileLayer.TMS(tileUrl, crs, {

            maxZoom: 14, //res.length,
            minZoom: 0,
            //zoomReverse: true,
            subdomains: '0123',
            continuousWorld: true,
            attribution: attrib
    }
    );

    tilelayer1.getTileUrl = function (tilePoint) {

        var toRet;
        console.log( this._getSubdomain(tilePoint) + " : " + tilePoint.x + ", " + tilePoint.y + ", " + tilePoint.z + " vs " + tilePoint.x + ", " + tilePoint.y + Math.pow(2, tilePoint.z) + ", " + (14 - tilePoint.z) + " || " + (1<<tilePoint.z) + " || " +  Math.pow(2, tilePoint.z));

        toRet = L.Util.template(this._url, L.extend({
          s: this._getSubdomain(tilePoint),
          x: tilePoint.x,
          y: tilePoint.y + Math.pow(2, tilePoint.z),
          z: 14-tilePoint.z
    }, this.options));

        return toRet;
      }


    var map = L.map('map', {
        crs: crs,
        //scale: scale,
        continuousWorld: true,
        worldCopyJump: false,
        zoomControl: true
    });
    map.addLayer(tilelayer1);


    map.setView([40.0, 127.0], 0);


    var latlng2 = new L.LatLng(38., 127.0);
    var xy2 = crs.project(latlng2);
    L.marker(latlng2).addTo(map)
             .bindPopup("latlng: " + latlng2 + ", xy: " + xy2.toString())
             .openPopup();

Sensitivity to very small floating point calculation errors

The code in _calculateSizes() lines 161 - 164 are very sensitive to extremely small differences. I ultimately discovered a very small rounding error in the calculation of one of my resolutions and was able to fix my problem without changing any code in Proj4Leaflet.

However, JavaScript rounding errors are well known (try 0.1 + 0.2) and it seems to me that this block of could would be quite sensitive to these small differences in the probably case that some combination of floating point numbers triggers a small floating point math error.

From what I understand of the code, the resulting values in this._sizes are expected to be exact multiples of the this.options.tileSize and perhaps Line 163-164 could be changed to round the values to nearest multiple of this.options.tileSize

EPSG:3413 Stereographic North Pole

I'm trying to get daily NASA tiles into Leaflet and got as far as tiles were loaded and zooming worked.

http://noiv.pythonanywhere.com/gibs/

However, the projection doesn't seem to work, at least by using setView(). Trying to isolate the problem I continued at jsfiddle:

http://jsfiddle.net/noiv/NqAcP/

LInking there to recent versions I adapted the proj string from 'stere' to 'sterea', but now the interface doesn't load any tiles at all.

I'm not even sure if this is right approach, would it be better to use the L.Proj.CRS.TMS tilelayers? How would one prepare the parameter arrays for this projection, then?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.