UNPKG

googlemaps-v3-utility-library

Version:
213 lines (174 loc) 6.76 kB
<!doctype html> <html> <head> <meta charset="utf-8"> <title>Hello CanvasLayer - WebGL</title> <style> html, body, #map-div { margin: 0; padding: 0; height: 100%; } </style> <script src="http://maps.googleapis.com/maps/api/js?sensor=false"></script> <script src="../src/CanvasLayer.js"></script> <script> var map; var canvasLayer; var gl; var pointProgram; var pointArrayBuffer; var POINT_COUNT = 2000; var MIN_X = 40; var MAX_X = 80; var MIN_Y = 88; var MAX_Y = 109; var pixelsToWebGLMatrix = new Float32Array(16); var mapMatrix = new Float32Array(16); function init() { // initialize the map var mapOptions = { zoom: 4, center: new google.maps.LatLng(39.3, -95.8), mapTypeId: google.maps.MapTypeId.ROADMAP, styles: [ { featureType: 'water', stylers: [{ color: '#c3cfdd'}] }, { featureType: 'poi', stylers: [{visibility: 'off'}] } ] }; var mapDiv = document.getElementById('map-div'); map = new google.maps.Map(mapDiv, mapOptions); // initialize the canvasLayer var canvasLayerOptions = { map: map, resizeHandler: resize, animate: false, updateHandler: update }; canvasLayer = new CanvasLayer(canvasLayerOptions); // initialize WebGL gl = canvasLayer.canvas.getContext('experimental-webgl'); createShaderProgram(); loadData(); } function createShaderProgram() { // create vertex shader var vertexSrc = document.getElementById('pointVertexShader').text; var vertexShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertexShader, vertexSrc); gl.compileShader(vertexShader); // create fragment shader var fragmentSrc = document.getElementById('pointFragmentShader').text; var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragmentShader, fragmentSrc); gl.compileShader(fragmentShader); // link shaders to create our program pointProgram = gl.createProgram(); gl.attachShader(pointProgram, vertexShader); gl.attachShader(pointProgram, fragmentShader); gl.linkProgram(pointProgram); gl.useProgram(pointProgram); } // linear interpolate between a and b function lerp(a, b, t) { return a + t * (b - a); } function loadData() { // this data could be loaded from anywhere, but in this case we'll // generate some random x,y coords in a world coordinate bounding box var rawData = new Float32Array(2 * POINT_COUNT); for (var i = 0; i < rawData.length; i += 2) { rawData[i] = lerp(MIN_X, MAX_X, Math.random()); rawData[i + 1] = lerp(MIN_Y, MAX_Y, Math.random()); } // create webgl buffer, bind it, and load rawData into it pointArrayBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, pointArrayBuffer); gl.bufferData(gl.ARRAY_BUFFER, rawData, gl.STATIC_DRAW); // enable the 'worldCoord' attribute in the shader to receive buffer var attributeLoc = gl.getAttribLocation(pointProgram, 'worldCoord'); gl.enableVertexAttribArray(attributeLoc); // tell webgl how buffer is laid out (pairs of x,y coords) gl.vertexAttribPointer(attributeLoc, 2, gl.FLOAT, false, 0, 0); } function resize() { var width = canvasLayer.canvas.width; var height = canvasLayer.canvas.height; gl.viewport(0, 0, width, height); // matrix which maps pixel coordinates to WebGL coordinates pixelsToWebGLMatrix.set([2/width, 0, 0, 0, 0, -2/height, 0, 0, 0, 0, 0, 0, -1, 1, 0, 1]); } function scaleMatrix(matrix, scaleX, scaleY) { // scaling x and y, which is just scaling first two columns of matrix matrix[0] *= scaleX; matrix[1] *= scaleX; matrix[2] *= scaleX; matrix[3] *= scaleX; matrix[4] *= scaleY; matrix[5] *= scaleY; matrix[6] *= scaleY; matrix[7] *= scaleY; } function translateMatrix(matrix, tx, ty) { // translation is in last column of matrix matrix[12] += matrix[0]*tx + matrix[4]*ty; matrix[13] += matrix[1]*tx + matrix[5]*ty; matrix[14] += matrix[2]*tx + matrix[6]*ty; matrix[15] += matrix[3]*tx + matrix[7]*ty; } function update() { gl.clear(gl.COLOR_BUFFER_BIT); var mapProjection = map.getProjection(); /** * We need to create a transformation that takes world coordinate * points in the pointArrayBuffer to the coodinates WebGL expects. * 1. Start with second half in pixelsToWebGLMatrix, which takes pixel * coordinates to WebGL coordinates. * 2. Scale and translate to take world coordinates to pixel coords * see https://developers.google.com/maps/documentation/javascript/maptypes#MapCoordinate */ // copy pixel->webgl matrix mapMatrix.set(pixelsToWebGLMatrix); // Scale to current zoom (worldCoords * 2^zoom) var scale = Math.pow(2, map.zoom); scaleMatrix(mapMatrix, scale, scale); // translate to current view (vector from topLeft to 0,0) var offset = mapProjection.fromLatLngToPoint(canvasLayer.getTopLeft()); translateMatrix(mapMatrix, -offset.x, -offset.y); // attach matrix value to 'mapMatrix' uniform in shader var matrixLoc = gl.getUniformLocation(pointProgram, 'mapMatrix'); gl.uniformMatrix4fv(matrixLoc, false, mapMatrix); // draw! gl.drawArrays(gl.POINTS, 0, POINT_COUNT); } document.addEventListener('DOMContentLoaded', init, false); </script> <script id="pointVertexShader" type="x-shader/x-vertex"> attribute vec4 worldCoord; uniform mat4 mapMatrix; void main() { // transform world coordinate by matrix uniform variable gl_Position = mapMatrix * worldCoord; // a constant size for points, regardless of zoom level gl_PointSize = 10.; } </script> <script id="pointFragmentShader" type="x-shader/x-fragment"> precision mediump float; void main() { // set pixels in points to green gl_FragColor = vec4(.1, .8, 0.08, 1.); } </script> </head> <body> <div id="map-div"></div> </body> </html>