Грегори Старр

Это обсуждение касается нашего использования листовок по сравнению с другими технологиями и того, как мы можем использовать холст HTML5 для повышения производительности на наших картах, получения возможности использовать обнаружение устройств и лучше планировать наши структуры данных из нашего API. Мы также можем использовать это как возможность для создания сценариев, которые помогут формировать более оптимизированные структуры данных, а также определить, где создавать швы, чтобы помочь нам лучше визуализировать наши данные для наших клиентов.

Что такое Canvas и WebGL?

Холст

Элемент HTMLcanvas› используется для рисования графики на лету с помощью сценариев (обычно JavaScript). Элемент ‹canvas› — это только контейнер для графики. Вы должны использовать сценарий, чтобы на самом деле нарисовать графику. Canvas имеет несколько методов рисования контуров, прямоугольников, кругов, текста и добавления изображений.

Подробнее: здесь

WebGL

На самом базовом уровне WebGL (или библиотека веб-графики) представляет собой библиотеку изображений, которая позволяет создавать интерактивную трехмерную графику в режиме реального времени, используя другую часть «мозга» вашего компьютера. Это означает, что вы можете создавать расширенные трехмерные визуальные эффекты, которые запускаются в веб-браузере без необходимости загрузки пользователем каких-либо плагинов. Технология работает поверх холста и доступна через отдельный API. Привлекательность здесь в том, что мы можем перенести рендеринг в GL на основе устройства во время выполнения. Если клиент может, то мы передаем рендеринг в webGL, в противном случае мы остаемся в холсте. Просто, верно?

Что касается поддержки браузера? Как утверждает Википедия, WebGL широко поддерживается в современных браузерах. Однако его доступность зависит от других факторов, таких как поддерживающий его графический процессор. Официальный сайт WebGL предлагает простую тестовую страницу: [13]. Более подробная информация (например, какой рендерер использует браузер и какие расширения доступны) представлена ​​на сторонних веб-сайтах: [14][15].

Подробнее: здесь

Что такое GeoJSON-VT и почему?

Прямо со страницы git:

«Высокоэффективная библиотека JavaScript для нарезки данных GeoJSON на векторные фрагменты на лету, в первую очередь предназначенная для обеспечения рендеринга и взаимодействия с большими наборами геопространственных данных на стороне браузера (без сервера).

Создан для поддержки GeoJSON в Mapbox GL JS, но может быть полезен в других платформах визуализации, таких как Leaflet и d3, а также в серверных приложениях Node.js.

Результирующие плитки соответствуют JSON-эквиваленту спецификации векторной плитки. Чтобы ускорить рендеринг данных и взаимодействие, плитки упрощаются, сохраняя минимальный уровень детализации, соответствующий каждому уровню масштабирования (упрощение фигур, отфильтровывание крошечных полигонов и ломаных линий)».

Листовка против MapBox

Итак, просто чтобы прояснить некоторую путаницу в отношении того, что есть что:

«Mapbox.js — это плагин Leaflet. Он расширяет функциональные возможности Leaflet дополнительным кодом для интеграции со службами Mapbox и вашими данными в Mapbox.

Файл Mapbox.js по умолчанию включает копию Leaflet, прикрепленную к определенной стабильной версии. ”

Визуализация данных клиента Leaf

Наша цель здесь — получить производительный рендеринг из картографического клиента независимо от используемого устройства. Исторически сложилось так, что мы хотели бы подойти к нашему приложению в первую очередь с точки зрения мобильных устройств, чтобы легче находить и решать наиболее очевидные проблемы.

Визуализация наших данных в производительной, независимой от устройства манере потребует от нас более разумного мышления о том, как мы доставляем данные, которые необходимо визуализировать. Нам также нужно быть умнее в том, как мы отображаем эти данные.

В настоящее время мы делаем наивные запросы на основе устройств, получаем неоднозначные данные сокета, а затем пытаемся отобразить все это прямо сейчас. Понятно, откуда берутся проблемы с производительностью.

Я хотел бы предложить лучший способ. Я думаю, мы можем разработать «сценарии», которые управляют несколькими типами запросов на данные. Эти данные структурированы (GeoJSON) таким образом, что их можно визуализировать для удовлетворения наших потребностей в визуализации за один проход. Введите GeoJSON-VT.

Во-первых, конечно, вам нужен набор данных GeoJSON. Предполагая, что вы это сделаете, вы можете продолжить что-то вроде следующего:

if(this.props.geojson.features){
  // Generate the tileset. This is for the entire world BTW
  // It gets generated only once. So make sure you have your dataset complete.
  // Otherwise you will need to re-generate it when you update your data
  const tileIndex = geojsonvt(this.props.geojson, this.geoVectorTileOptions);
  
  // Create your canvas layer
  this.canvasLayer = L.tileLayer.canvas();
  
  // The drawTile property is a callback that you set to a function that will get
  // called everytime we need to draw a new tile (zooming, new tile entering the viewport, etc)
  this.canvasLayer.drawTile = (canvas, tilePoint, zoom) => {
    drawVectorTile(canvas, tilePoint, zoom, tileIndex);
  };
  
  // Add the layer to leaflet
  if(!this.map.hasLayer(this.canvasLayer)){
    this.map.addLayer(this.canvasLayer);
  }
}

Вот функция, которая вызывается каждый раз, когда холсту требуется отрисовать данные тайла (масштабирование или каждый раз, когда новый тайл карты входит в окно просмотра).

export function drawVectorTile (canvas, tilePoint, zoom, tileIndex) {
  // Use the performance API to start gathering drawing perf metrics
  const begin = performance.now();
  const  params ={zoom:zoom,tilePoint:tilePoint, canvas:canvas}
  params.tilePoint.z = params.zoom;

  const bounds = params.bounds;
  const ratio = 1;
  const pad = 0;

  // get a reference to the 2d canvas context to draw with
  // In a web gl implementation you would need to reference the 'experimental-webgl' 
  // or 'experimental-webgl2' contexts.
  const ctx = canvas.getContext('2d');
  ctx.globalCompositeOperation = 'source-over';

  // grab a tile from the geojson-vt lib based on the params 
  // sent in from the leaf draw event. Based on tile and zoom
  // If there is something to draw geojson-vt pass it into this tile
  const tile = tileIndex.getTile(params.tilePoint.z, params.tilePoint.x, params.tilePoint.y);
  
  // Only continue if we have a tile to draw...
  if (!tile) {
    console.log('tile empty');
    return;
  }
  
  // Clear the canvas for a new drawing
  ctx.clearRect(0, 0, params.canvas.width, params.canvas.height);

  // Get the tile features from the new tile that was generated from geojson-vt
  const features = tile.features;

  // Define the path styles

  ctx.lineWidth = 3;

  // Enter the feature loop and draw based on features...
  for (let i = 0; i < features.length; i++) {
    const feature = features[i],
      type = feature.type;
    
    
    // Set the line style to draw
    ctx.strokeStyle = 'red'; //`hsla(${(Math.random() * 360)}, 100%, 50%, 1)`; //'red'
    ctx.beginPath();

    // Begin looping through geometry
    for (let j = 0; j < feature.geometry.length; j++) {
      const geom = feature.geometry[j];

      // handle drawing a circles
      if (type === 1) {
        ctx.arc(geom[0] * ratio + pad, geom[1] * ratio + pad, 2, 0, 2 * Math.PI, false);
        continue;
      }

      // more looping
      for (let k = 0; k < geom.length; k++) {
        // calculate positioning based on geojson extent settings, these are defaults I'm using
        const p = geom[k];
        const extent = 4096;
        const x = p[0] / extent * 256;
        const y = p[1] / extent * 256;

        // Store position as we will need to do collision testing later for mouse interaction.
        // By default interacting with cnvas does not happen out of the box
        // we will need to set that up down the line if we need to work with the location trails
        geom.x = x;
        geom.y = y;
        
        // Perform the move commands for each point of a stoke
        if (k) ctx.lineTo(x  + pad, y   + pad);
        else ctx.moveTo(x  + pad, y  + pad);
      }
    }

    // If we encounter a shape, fill it
    if (type === 3 || type === 1) ctx.fill('evenodd');
    
    // finally draw the strokes
    ctx.stroke();
  }

  // I like to use the performance API for perf metrics 
  var end = performance.now();
  
  // Log out the perf
  console.log("Call to DrawTile took " + (end - begin) + " milliseconds.")
}

Нравится эта статья? Нажмите на маленькое зеленое сердечко ниже и покажите свою любовь Agrarian Labs!