背景
上一章我们讲过,当标注平台解析完数据后,会把数据存入Graph,数据格式为osmEntity。为了渲染出osmEntity,我们还需要将osmEntity转换为fabric.Object的格式。本章介绍这一步的具体实现以及一些坑。
转换原理
我们知道,osmEntity具有geometry属性,这个属性是一个标准的Geometry格式。即
{type: 'Point',coordinates: [10, 10]
}
对于fabric.Object而言,geometry是无法直接使用的,需要进行转换。而且不同的Object需要的参数有些许差异。转换的伪代码如下:
class osmEntity {// osmEntity转fabric.ObjecttoFabricObject() {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可写为:
toFabricCoordinate() {const loc = this.geometry.coordinates;return {left: this.loc[0], top: this.loc[1]};
}
线
NPolyline继承自fabric.Polyline,其坐标参数为:
{left: 10,top: 10,points: [{x: 0, y: 0}, {x: 5, y: 0}]
}
这边注意找到线的最小外界矩形的左上角点,所有点都转为以该点为坐标原点。
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,其参数为:
{left: 10,top: 10,width: 100,height: 100
}
同样地,转换函数为:
toFabricCoordinate(){let result;const extent = bbox(this.geometry); // 矩形的geometry存的是polygonreturn {left: extent[0],top: extent[1],width: extent[2] - extent[0],height: extent[3] - extent[1]}
}
多边形
NPolygon继承自fabric.Path,其参数如下:
{path: 'M 10 10 Z',left: 10,top: 10
}
这里我们需要一个方法将geojson转为svg path的方法。这里参考一些开源仓库,写法如下:
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架构。