基于geojson-vt和canvas的高性能出图

概述

本文介绍基于geojson-vtcanvas,实现node端高性能出图。

效果

实现

1. canvas绘图

js 复制代码
import { createCanvas } from 'canvas'

const tileSize = 256;
const canvas = createCanvas(tileSize, tileSize)
const ctx = canvas.getContext('2d')

2. 处理geojson

js 复制代码
const geojson = result.rows[0].geojson;
geojson.features = geojson.features || []
const tileIndex = geojsonvt(geojson, {
    maxZoom: 22,
    tolerance: 3, // simplification tolerance (higher means simpler)
    extent: 4096, // tile extent (both width and height)
    buffer: 64,   // tile buffer on each side
    debug: 0,     // logging level (0 to disable, 1 or 2)
    lineMetrics: false, // whether to enable line metrics tracking for LineString/MultiLineString features
    promoteId: null,    // name of a feature property to promote to feature.id. Cannot be used with `generateId`
    generateId: false,  // whether to generate feature ids. Cannot be used with `promoteId`
    indexMaxZoom: 5,       // max zoom in the initial tile index
    indexMaxPoints: 100000 // max number of points per tile in the index
})
const features = tileIndex.getTile(Number(z), Number(x), Number(y))?.features || [];

3. 绘制features

js 复制代码
function drawTile(features, zoom) {
    ctx.clearRect(0, 0, tileSize, tileSize);
    // 绘制边框
    // ctx.strokeStyle = '#fff'
    // ctx.lineWidth = 1
    // ctx.strokeRect(0, 0, tileSize, tileSize)
    for (let i = 0; i < features.length; i++) {
        const feature = features[i];
        const {adcode, name} = feature.tags
        const type = feature.type;
        ctx.beginPath();
        for (let j = 0; j < feature.geometry.length; j++) {
            const geom = feature.geometry[j];
            if (type === 1) { // 1点
                ctx.save()
                ctx.fillStyle = `rgba(${'255,0,0'}, 1)`;
                ctx.strokeStyle = '#fff'
                ctx.lineWidth = 2;
                ctx.textAlign = "center";
                ctx.textBaseline = "middle"
                ctx.font = "bold 16px 宋体";
                // const len = ctx.measureText(name).width / 2;
                // const offset = 5
                // if(x + len > tileSize) x = tileSize - len - offset
                // if(x - len < 0 ) x = len + offset
                if(name && zoom >= 9) {
                    ctx.strokeText(name, geom[0] / 16.0, geom[1] / 16.0)
                    ctx.fillText(name, geom[0] / 16.0, geom[1] / 16.0)
                }
                // ctx.arc(geom[0] / 16.0, geom[1] / 16.0, 3, 0, 2 * Math.PI, false);
                ctx.restore()
                ctx.fill()
                ctx.stroke()
            } else { // 2线 或 3面
                // const color = colorDict[adcode] || '255,0,0'
                const color = '255,0,0'
                ctx.strokeStyle = `rgba(${color}, 1)`;
                ctx.fillStyle = `rgba(${color}, 0.1)`;
                ctx.lineWidth = 1;
                for (let k = 0; k < geom.length; k++) {
                    const p = geom[k];
                    if (k) ctx.lineTo(p[0] / 16.0, p[1] / 16.0);
                    else ctx.moveTo(p[0] / 16.0, p[1] / 16.0);
                }
                // if (type === 3) ctx.fill();
                ctx.stroke();
            }
        }
    }
}

4. 设置缓存并发送到前端

js 复制代码
app.get('/tile/:z/:x/:y', (req, res) => {
    const {z, x, y} = req.params
    try {
        getFeatures(x, y, z).then(image => {
            res.setHeader('Expires', new Date(Date.now() + 30 * 1000).toUTCString())
            res.writeHead(200, {
                "Content-Type": "image/png",
            });
            res.end(image);
        })
    } catch (err) {
        console.error(err);
    }   
})

5. 数据获取

数据是存在PG数据库中,可通过node连接获取,可通过如下语句直接将结果转换为geojson。

sql 复制代码
SELECT json_build_object(
   'type', 'FeatureCollection',
   'features', json_agg(ST_AsGeoJSON(t.*)::json)
) as geojson FROM (
   select adcode, name, geom from base_county where st_intersects(BBox(101, 52, 7), geom)
) as t(adcode, name, geom);

6. 前端调用

js 复制代码
new ol.layer.Tile({
  source: new ol.source.XYZ({
      url: 'http://127.0.0.1:18089/tile/{z}/{x}/{y}'
  })
}),
相关推荐
胡西风_foxww5 天前
nodejs爬虫系统
爬虫·nodejs·node·系统·express·request·cheerio
你不讲 wood9 天前
预览 PDF 文档
开发语言·前端·javascript·pdf·html·node·文件预览
276695829212 天前
大众点评 web mtgsig 1.2分析
java·python·node·美团·大众点评·mtgsig
mez_Blog17 天前
前端学习笔记(2.0)
前端·笔记·学习·node·nvm
杰哥的技术杂货铺1 个月前
Linux 系统 nvm 管理node无法使用
linux·node·nvm·libstdc++.so.6·libm.so.6
itas1091 个月前
Electron获取nodejs和chrome版本信息
javascript·chrome·electron·nodejs·node
ulimpid1 个月前
ENV | VUE3 的安装使用并跑通第一个项目(高效实操版)
npm·vue·node
佘小麦1 个月前
【nvm管理多版本node】下载安装以及常见问题和解决方案
node·nvm
程序猿看视界2 个月前
node nvm 基础用法
node·nvm
杰哥的技术杂货铺2 个月前
在 macOS 上管理 Node版本
macos·node·nvm