图片标注编辑平台搭建系列教程(8)——osmEntity转为fabric.Object

背景

上一章我们讲过,当标注平台解析完数据后,会把数据存入Graph,数据格式为osmEntity。为了渲染出osmEntity,我们还需要将osmEntity转换为fabric.Object的格式。本章介绍这一步的具体实现以及一些坑。

转换原理

我们知道,osmEntity具有geometry属性,这个属性是一个标准的Geometry格式。即

复制代码
{
    type: 'Point',
    coordinates: [10, 10]
}

对于fabric.Object而言,geometry是无法直接使用的,需要进行转换。而且不同的Object需要的参数有些许差异。转换的伪代码如下:

javascript 复制代码
class osmEntity {
    // osmEntity转fabric.Object
    toFabricObject() {
        let object = null;
        const options = this.toFabricCoordinate();
        switch(type) {
            case 'Point': 
                object = new NPoint(options);
            ;
            case 'Polyline': ;
            case 'Polygon': ;
            case 'Rectangle': ; 
        }
        return object;
    },
    // 坐标转换
    toFabricCoordinate() {
        // ...
    }
}

NPoint继承自fabric.Circle,其坐标参数为:

复制代码
{
    left: 10,
    top: 10
}

因此,其toFabricCoordinate可写为:

javascript 复制代码
toFabricCoordinate() {
    const loc = this.geometry.coordinates;
    return {left: this.loc[0], top: this.loc[1]};
}

线

NPolyline继承自fabric.Polyline,其坐标参数为:

javascript 复制代码
{
    left: 10,
    top: 10,
    points: [{x: 0, y: 0}, {x: 5, y: 0}]
}

这边注意找到线的最小外界矩形的左上角点,所有点都转为以该点为坐标原点。

javascript 复制代码
toFabricCoordinate(){
    let result;
    const coordinates = this.geometry.coordinates;
    const extent = bbox(this.geometry);
    result.left = extent[0];
    result.top = extent[1];
    result.points = coordinates.map((p) => {
        return { x: p[0] - extent[0], y: p[1] - extent[1] };
    });
    return result;
}

矩形

NRectangle继承自fabric.Rect,其参数为:

javascript 复制代码
{
    left: 10,
    top: 10,
    width: 100,
    height: 100
}

同样地,转换函数为:

javascript 复制代码
toFabricCoordinate(){
    let result;
    const extent = bbox(this.geometry); // 矩形的geometry存的是polygon
    return {
        left: extent[0],
        top: extent[1],
        width: extent[2] - extent[0],
        height: extent[3] - extent[1]
    }
}

多边形

NPolygon继承自fabric.Path,其参数如下:

javascript 复制代码
{
    path: 'M 10 10 Z',
    left: 10,
    top: 10
}

这里我们需要一个方法将geojson转为svg path的方法。这里参考一些开源仓库,写法如下:

javascript 复制代码
toFabricCoordinate(){
    const extent = bbox(this.geometry);
    let result;
    result.left = extent[0];
    result.top = extent[1];
    let mainStr, holes;
    // 多边形外环
    mainStr = this.getCoordString(coordinates[0], result.left as number, result.top as number);
    // 多边形孔洞
    if (coordinates.length > 1) {
        holes = coordinates.slice(1, coordinates.length);
    }
    let path = 'M' + mainStr;
    if (holes) {
        for (var i = 0; i < holes.length; i++) {
           path += ' M' + this.getCoordString(holes[i], result.left as number, result.top as number);
        }
    }
    path += 'Z';
    result.path = fabric.util.makePathSimpler(fabric.util.parsePath(path)); // string转数组,参考fabric源码
    return result;
},
getCoordString(coords, left, top) {
    let coordStr = coords.map((coord) => coord[0] - left + ',' + (coord[1] - top));
    return coordStr.join(' ');
}

预告

下一章,我们讲讲编辑器里解决性能问题常用的sketchLayer架构。

相关推荐
卷帘依旧14 分钟前
useImperativeHandle的作用
前端
卷帘依旧21 分钟前
Hooks在Fiber上的存储原理
前端
you458024 分钟前
学成在线--day02 CMS前端开发(含Vue基础知识得回顾)
前端·javascript·vue.js
xiaofeichaichai31 分钟前
虚拟 DOM
前端·javascript·vue.js
2401_8784545335 分钟前
前端高频得手写题
前端
初一初十1 小时前
vue3实现的纯前端护肤品商城网站
前端·javascript·vue.js·前端框架
卷帘依旧1 小时前
React状态管理方案怎么选
前端
zeqinjie1 小时前
Flutter 折叠屏 iPad / 宽屏适配实践
android·前端·flutter
小村儿1 小时前
连载13- 内部Tools,Claude Code 怎么真正"动"你的代码
前端·后端·ai编程
IT_陈寒1 小时前
Python的线程池把我坑惨了,原来异步不是万能的
前端·人工智能·后端