openlayers实现路径导航效果

该篇文章详细描述了如何通过OpenLayers在前端项目中创建动态展示用户轨迹的代码,涉及起点、终点标识和路径上的箭头,以及如何通过styleFunction定制样式参数。
摘要由CSDN通过智能技术生成

最近做项目遇到一个需求,要显示采集的用户的行动轨迹,类似导航软件的规划路径,有起点终点,路径上通过箭头指向到终点位置。前端通过openlayers实现。

具体的实现思路:

  1. 将路径坐标数据组装为MultiLineString
  2. 通过Openlayers的styleFunction为线段添加轨迹的效果
    1. 添加起点,终点的图标
    2. 添加中间路径的箭头

下面是具体代码:

创建路径要素

    const locationList  = new Array()
    // 添加所有的坐标数据到坐标列表中 如:     locationList.push({logitude:113.233,latitude21.4333})
    // 创建多线段
    const multiLineString = new MultiLineString([])
    // 依次添加坐标点,构成路线
    for (let i=0;i<locationList.length-1;i++){
      const p1 = [locationList[i].longitude,locationList[i].latitude]
      const p2 = [locationList[i+1].longitude,locationList[i+1].latitude]
      const lineCoords = [p1,p2]
      const lineString = new LineString(lineCoords)
      multiLineString.appendLineString(lineString)
    }
    //创建要素
    const f = new Feature(multiLineString)
    // 设置样式
    f.setStyle(travelPathStyleFunction(map.getView().getProjection().getMetersPerUnit()))
    //添加要素 到图层中
    layer.getSource().addFeature(f)

路径的styleFunction,可以设定轨迹颜色,轨迹宽度,箭头密度,箭头颜色,箭头大小等参数动态获取styleFunction,满足不同要求。

/**
 *  轨迹样式方法
 *  @param {number} [metersPerUnit] - 地图每单位代表的米数
 *  @param {string} [pathColor] - 轨迹颜色
 *  @param {number } [pathWidth] - 轨迹宽度
 *  @param {number} [arrowDensity] - 箭头密度。间隔多少厘米显示一个箭头
 *  @param {string} [arrowColor] - 箭头颜色
 *  @param {number} [arrowImgSize] - 箭头图片的大小
 *  @param {number} [arrowWidth] - 箭头线宽大小
 * */

export function travelPathStyleFunction(metersPerUnit=1,pathColor=DEFAULT_PATH_COLOR,pathWidth=DEFAULT_PATH_WIDTH,arrowDensity = DEFAULT_PATH_ARROW_DENSITY,
                        arrowColor=DEFAULT_ARROW_COLOR,arrowImgSize=DEFAULT_ARROW_IMG_SIZE,arrowWidth=DEFAULT_ARROW_WIDTH) {
  //画向右的箭头。水平向右则旋转的角度刚好为0,方便箭头旋转时的角度计算
  const arrowCanvas = document.createElement('canvas')
  arrowCanvas.width = arrowImgSize
  arrowCanvas.height = arrowImgSize
  const ctx = arrowCanvas.getContext('2d')
  ctx.strokeStyle = arrowColor
  ctx.lineWidth = arrowWidth;
  // 箭头底边
  ctx.moveTo(0, 0);
  ctx.lineTo(arrowImgSize * 0.7, arrowImgSize * 0.5);
  ctx.lineTo(0, arrowImgSize);
  ctx.stroke();
  // 返回真实的 styleFunction
  return (feature,resolution)=>{
    const styleArr = [
      new Style({
        fill:new Fill({
          color:pathColor,
        }),
        stroke:new Stroke({
          color:pathColor,
          width:pathWidth
        })
      })
    ]
    //resolution 代表每像素的单位距离
    //由轨迹的指向标,每个的角度不同,需要单独生成
    const lines = feature.getGeometry().getLineStrings()
    //每英寸像素值
    const dpi = window.devicePixelRatio * 96;
    //1英寸 = 2.54 厘米。1厘米=0.39370079 英寸
    // metersPerUnit * resolution 即为每像素代表多少米   * dpi 代表每英寸多少米 /2.54 代表屏幕每厘米多少米
    const arrowDistance = arrowDensity * (resolution * metersPerUnit * dpi / 2.54)
    let lastLineRetainLen = 0 //上条线结余长度。每个线都会判断是否添加箭头,最后肯定有一小部分长度是在上一个箭头之后。下条线判断时加上此长度,才能保证箭头按设置的长度均匀分布
    for (let line of lines){
      let lineLen = line.getLength() * metersPerUnit
      if (lineLen + lastLineRetainLen>=arrowDistance) {
        let coords = line.getCoordinates();
        let start = coords[0];
        let end = coords[1];
        let dx = end[0] - start[0];
        let dy = end[1] - start[1];
        let rotation = Math.atan2(dy, dx);

        let offset = 0;
        let tempLen = lastLineRetainLen + lineLen;
        while (tempLen > arrowDistance) {
          let curLen = arrowDistance - lastLineRetainLen;
          let rate = (curLen + offset) / lineLen;
          let ddx = dx * rate;
          let ddy = dy * rate;
          let arrowCoord = [start[0] + ddx, start[1] + ddy];
          //箭头坐标
          styleArr.push(new Style({
            geometry: new Point(arrowCoord),
            image:new Icon({
              img: arrowCanvas,
              crossOrigin: 'anonymous',
              imgSize:[arrowImgSize,arrowImgSize],
              anchor: [0.75, 0.5],
              rotateWithView: true,
              rotation: -rotation
            })
          }));
          lastLineRetainLen = 0;
          offset = offset + curLen;
          tempLen = tempLen - arrowDistance;
        }
        lastLineRetainLen = lineLen - offset
      }else{
        lastLineRetainLen += lineLen
      }
    }
    //添加起始终止点标记
    styleArr.push(
      new Style({
        image:new Icon({src:startPointImage}),
        geometry:new Point(feature.getGeometry().getFirstCoordinate())
      })
    )
    styleArr.push(
      new Style({
        image:new Icon({src:endPointImage}),
        geometry:new Point(feature.getGeometry().getLastCoordinate())
      })
    )
    return styleArr
  }
}

最终效果图:

cb240839dbe3406bd8c396f187dfb8eb.jpeg

 

Vue是一种流行的JavaScript框架,用于构建用户界面。OpenLayers是一个开源的JavaScript库,用于在web浏览器中显示交互式地图。结合Vue和OpenLayers,我们可以实现台风轨迹的可视化。 首先,我们需要获取台风的相关数据。可以从台风数据的API或其他数据源中获取实时或历史台风数据。数据通常包含台风的经纬度坐标和其他相关信息,如风力、风速等。 在Vue组件中,我们可以使用OpenLayers来显示地图。首先,在Vue组件中引入OpenLayers库,并在Vue的生命周期钩子中初始化地图。可以使用OpenLayers的地图视图类(MapView)来设置地图的中心坐标和缩放级别。 接下来,我们需要将台风的轨迹数据添加到地图上。可以使用OpenLayers的矢量图层(Vector Layer)来添加台风轨迹。将每个台风点的经纬度坐标转换为OpenLayers的几何对象,并将其添加到矢量图层中。 为了使台风轨迹更具交互性,可以在每个台风点上添加弹出窗口,显示该点的详细信息。可以使用OpenLayers的弹出窗口类(Overlay)和交互类(Interaction)来实现这一功能。 最后,根据需求,可以添加其他地图元素,如底图切换、比例尺、图例等,以增强用户体验。 总之,使用Vue和OpenLayers,我们可以方便地将台风轨迹可视化,并提供交互功能。这种方式可以帮助用户更直观地了解台风的路径和特征,从而提高对台风的认知和应对能力。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ThinkLess404

有问题可以私信交流

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值