First you need some files for JavaScript to munch on. Quantum GIS can help you generate GeoJSON. Just add your shapefiles to your project, right click on the layer in the table of contents and select 'Save As. ' From the format dropdown select GeoJSON.
The code to create the image above is here. I start off by loading the JSON, getting the bounding box of the data, setting the scale of the drawing, and finally drawing the shapes. The canvas element has to be present in your HTML page already
var canvas, ctx, xMin, xMax, yMin, yMax, drawScale; function loadJson(){ canvas = document.getElementById('map'); ctx = canvas.getContext('2d'); ctx.strokeStyle = "#000000"; ctx.fillStyle = "#FFA500"; var geojson= {"type":"FeatureCollection","features":[{"type":"Feature","properties":{"ROM_DIST_I":1.000000,"ID":"RO-01","NAME":"Alba","AREA":6260.95},"geometry":{"type":"Polygon","coordinates":[[[22.67,46.51],[22.69,46.56],[22.73,46.57],[22.79,46.57], ///..... load the rest of your GeoJSON here or better yet, get it asynchronously //traverse the features to get the bounding box traverseFeatures(geojson.features,'bbox'); //calculate width and height of data. divide canvas by data dimensions to get a suitable scale xScale = canvas.width/Math.abs(xMax-xMin); yScale = canvas.height/Math.abs(yMax-yMin); //calculate a vertical and horiz scale to fit the data to the canvas. //pick the smaller scale of the two for the rendering drawScale = xScale<yScale ? xScale : yScale; //traverse the features again to draw traverseFeatures(geojson.features,'draw'); } function traverseFeatures(features,action){ for(var i=0; i<features.length; i++){ var coords = features[i].geometry.coordinates; var geomtype = features[i].geometry.type; if(geomtype=="Polygon"){ //Polygons have just one array of coordinates traverseCoordinates(coords[0],action); } else if(geomtype=="MultiPolygon"){ //Multipolygons have several arrays of coordinates, so loop through those for(var k=0; k<coords.length; k++){ traverseCoordinates(coords[k][0],action); } } } } function traverseCoordinates(coordinates,action){ for(var j=0; j<coordinates.length; j++){ var x = coordinates[j][0]; var y = coordinates[j][1]; if(action == 'bbox'){ xMin = xMin<x?xMin:x; xMax = xMax>x?xMax:x; yMin = yMin<y?yMin:y; yMax = yMax>y?yMax:y; }else if(action == 'draw'){ x = (x-xMin)*drawScale; y = (yMax-y)*drawScale; if(j==0){ //begin drawing on the first point ctx.beginPath(); ctx.moveTo(x,y); }else{ //continue drawing ctx.lineTo(x,y); } } } if(action == 'draw'){ //close the fill and the stroke ctx.stroke(); ctx.fill(); } }
Shortcomings with this approach:
- the canvas element is static. Once the shapes are drawn there's not much you can do with them. In Flash any shape could have user interactions associated with it, but with the canvas you have to be really creative if you want to develop something as basic as a mouse-over highlight. Might want to use SVG for that. Some impressive work in this field has already been done by sites like GIS Cloud using Leaflet vectors. I'm glad they acknowledge that we were able to do this all with Flash years ago and with very good performance, but alas, everything in software has to be reinvented so we can all have jobs.
- a 30 MB file GeoJSON will crash the browser