<html>
<head>
  <title>Many Points with  leaflet WebGL</title>
  <meta charset="utf-8">

  <style>
      html, body {
          height: 100%;
          padding: 0;
          margin: 0;
          background: rgb(14, 21, 30);
          height: 100%;
      }

      #map {
          position: absolute;
          height: 100%;
          width: 100%;
          background-color: #333;
      }
  </style>
  
  <!-- vertex shader -->
  <script id="vshader" type="x-shader/x-vertex">
      uniform mat4 u_matrix;
      attribute vec4 a_vertex;
      attribute float a_pointSize;
      attribute vec4 a_color;
      varying vec4 v_color;

      void main() {
        // Set the size of the point
        gl_PointSize = a_pointSize;
  
        // multiply each vertex by a matrix.
        gl_Position = u_matrix * a_vertex;
    
        // pass the color to the fragment shader
        v_color = a_color;
      }
  </script>

  
  <!-- fragment shader -->
  <script id="fshader" type="x-shader/x-fragment">
    
    precision mediump float;
    varying vec4 v_color;

    void main() {

      float border = 0.05;
      float radius = 0.5;
      vec4 color0 = vec4(0.0, 0.0, 0.0, 0.0);
      vec4 color1 = vec4(v_color[0], v_color[1], v_color[2], 0.2);

      vec2 m = gl_PointCoord.xy - vec2(0.5, 0.5);
      float dist = radius - sqrt(m.x * m.x + m.y * m.y);

      float t = 0.0;
      if (dist > border) {
        t = 1.0;
      } else if (dist > 0.0) {
        t = dist / border;
      }
      // float centerDist = length(gl_PointCoord - 0.5);
      // works for overlapping circles if blending is enabled
      gl_FragColor = mix(color0, color1, t);

      /*
      // -- another way for circle
      float centerDist = length(gl_PointCoord - 0.5);
      float radius = 0.5;
    
      // works for overlapping circles if blending is enabled
      gl_FragColor = vec4(v_color[0], v_color[1], v_color[2], 0.2 * step(centerDist, radius));
      */

      /*
      // simple circles
      float d = distance (gl_PointCoord, vec2(0.5,0.5));
      if (d < 0.5) {
        gl_FragColor = vec4(v_color[0], v_color[1], v_color[2], 0.2);
      } else {
        discard;
      }
      */

      ///*
      // -- squares
      gl_FragColor = v_color;
      gl_FragColor = vec4(v_color[0], v_color[1], v_color[2], 0.2); // v_color;
      //*/
    }

  </script>

</head>
<body>
  <div id="map"></div>
  <div id="location"></div>
  <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" />
  <script src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"></script>
  <script src="http://www.sumbera.com/gist/js/leaflet/canvas/L.CanvasOverlay.js"></script>
  <script src="http://www.sumbera.com/gist/86T.json" charset="utf-8"></script>


</body>
</html>

class uLayer
  
  leafletMap = undefined
  gl = undefined
  canvas = undefined
  pixelsToWebGLMatrix = new Float32Array(16)
  mapMatrix = new Float32Array(16)
  numPoints = 0
  u_matLoc = undefined

  ###
  # Returns a random integer from 0 to range - 1.
  randomInt = (range) ->
    Math.floor Math.random() * range
  ###
    
  ###
  latlonToPixels = (lat, lon) ->
    initialResolution = 2 * Math.PI * 6378137 / 256 # at zoomlevel 0
    originShift = 2 * Math.PI * 6378137 / 2
  
    
    # -- to meters
    mx = lon * originShift / 180
    my = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180)
    my = my * originShift / 180
    
    # -- to pixels at zoom level 0
    res = initialResolution
    x = (mx + originShift) / res
    y = (my + originShift) / res
  
    x: x
    y: 256 - y
  ###
  
  # -- converts latlon to pixels at zoom level 0 (for 256x256 tile size) , inverts y coord )
  # -- source : http://build-failed.blogspot.cz/2013/02/displaying-webgl-data-on-google-maps.html
  LatLongToPixelXY = (latitude, longitude) ->
    pi_180      = Math.PI / 180.0
    pi_4        = Math.PI * 4
    sinLatitude = Math.sin(latitude * pi_180)
    pixelY      = (0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (pi_4)) * 256
    pixelX      = ((longitude + 180) / 360) * 256
    pixel       = { x: pixelX, y: pixelY }
    pixel
  
    
  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
    return
  
  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
    return
  
  drawingOnCanvas = (canvasOverlay, params) ->
    return unless gl?
    gl.clear gl.COLOR_BUFFER_BIT
    pixelsToWebGLMatrix.set [2 / canvas.width, 0, 0, 0, 0, -2 / canvas.height, 0, 0, 0, 0, 0, 0, -1, 1, 0, 1]
    gl.viewport 0, 0, canvas.width, canvas.height
    pointSize = Math.max(leafletMap.getZoom() - 4.0, 1.0)
    gl.vertexAttrib1f gl.aPointSize, pointSize
    
    # -- set base matrix to translate canvas pixel coordinates -> webgl coordinates
    mapMatrix.set pixelsToWebGLMatrix
    bounds  = leafletMap.getBounds()
    topLeft = new L.LatLng(bounds.getNorth(), bounds.getWest())
    offset  = LatLongToPixelXY(topLeft.lat, topLeft.lng)
    
    # -- Scale to current zoom
    scale = Math.pow(2, leafletMap.getZoom())
    scaleMatrix mapMatrix, scale, scale
    translateMatrix mapMatrix, -offset.x, -offset.y
    
    # -- attach matrix value to 'mapMatrix' uniform in shader
    gl.uniformMatrix4fv u_matLoc, false, mapMatrix
    gl.drawArrays gl.POINTS, 0, numPoints
    return
  
  # -- WebGl setup
  initVertexShader = ->
    vertexShader = gl.createShader(gl.VERTEX_SHADER)
    gl.shaderSource vertexShader, document.getElementById("vshader").text
    gl.compileShader vertexShader
    vertexShader
    
  initFragmentShader = ->  
    fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
    gl.shaderSource fragmentShader, document.getElementById("fshader").text
    gl.compileShader fragmentShader
    fragmentShader

  # link shaders to create our program
  linkShaders = ->
    program = gl.createProgram()
    for s in arguments
      gl.attachShader program, s
    gl.linkProgram program
    gl.useProgram program
    program

  #==============================
  constructor: ->
    leafletMap = L.map("map").setView([50.00, 14.44], 8)
    
    #L.tileLayer("http://{s}.sm.mapstack.stamen.com/(toner-background,$fff[difference],$fff[@23],$fff[hsl-saturation@20],toner-lines[destination-in])/{z}/{x}/{y}.png").addTo leafletMap
    L.tileLayer("http://{s}.sm.mapstack.stamen.com/(toner-lite,$fff[difference],$fff[@23],$fff[hsl-saturation@20])/{z}/{x}/{y}.png").addTo leafletMap
    
    
    glLayer               = L.canvasOverlay().drawing(drawingOnCanvas).addTo(leafletMap)
    canvas                = glLayer.canvas()
    glLayer.canvas.width  = canvas.clientWidth
    glLayer.canvas.height = canvas.clientHeight
    gl                    = canvas.getContext("experimental-webgl", antialias: true)
    pixelsToWebGLMatrix   = new Float32Array(16)
    mapMatrix             = new Float32Array(16)
    
    # link shaders to create our program
    program = linkShaders(initVertexShader(), initFragmentShader())
    
    # blending
    # gl.blendFunc gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA
    # gl.enable gl.BLEND
    # gl.disable(gl.DEPTH_TEST);
    
    # ----------------------------
    # look up the locations for the inputs to our shaders.
    u_matLoc      = gl.getUniformLocation(program, "u_matrix")
    colorLoc      = gl.getAttribLocation(program, "a_color")
    vertLoc       = gl.getAttribLocation(program, "a_vertex")
    gl.aPointSize = gl.getAttribLocation(program, "a_pointSize")
    
    # Set the matrix to some that makes 1 unit 1 pixel.
    pixelsToWebGLMatrix.set [2 / canvas.width, 0, 0, 0, 0, -2 / canvas.height, 0, 0, 0, 0, 0, 0, -1, 1, 0, 1]
    gl.viewport 0, 0, canvas.width, canvas.height
    gl.uniformMatrix4fv u_matLoc, false, pixelsToWebGLMatrix
    
    vertBuffer = gl.createBuffer()
    # バッファオブジェクトをバインド
    gl.bindBuffer gl.ARRAY_BUFFER, vertBuffer
    
    # -- data
    verts = []
    data.map (d, i) ->
      pixel = LatLongToPixelXY(d[0], d[1])
      #-- 2 coord, 3 rgb colors interleaved buffer
      verts.push pixel.x, pixel.y, Math.random(), Math.random(), Math.random()
      return
    
    numPoints  = data.length
    
    vertArray = new Float32Array(verts)
    # バッファオブジェクトの初期化
    gl.bufferData gl.ARRAY_BUFFER, vertArray, gl.STATIC_DRAW
    
    fsize = vertArray.BYTES_PER_ELEMENT
    gl.vertexAttribPointer vertLoc, 2, gl.FLOAT, false, fsize * 5, 0
    gl.enableVertexAttribArray vertLoc
    
    # -- offset for color buffer
    gl.vertexAttribPointer colorLoc, 3, gl.FLOAT, false, fsize * 5, fsize * 2
    gl.enableVertexAttribArray colorLoc
    
    glLayer.redraw()



new uLayer()

btn = document.createElement("div")
btn.id = "con"
btn.style.height = "20px"
btn.style.width = "20px"
btn.style.position = "absolute"
btn.style.top = "20px"
btn.style.left = "20px"

document.body.appendChild btn
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.