react + openlayer测距实现

测距组件:
import { useEffect, useState } from 'react';
import VectorSource from 'ol/source/Vector';
import { Draw, Modify } from 'ol/interaction';
import {
  Stroke,
  Style,
  Fill,
  Circle as CircleStyle,
  RegularShape,
  Text,
} from 'ol/style';
import { useMap } from '&/core/hooks';
import { Vector as VectorLayer } from 'ol/layer';
import { getArea, getLength } from 'ol/sphere';
import { LineString, Point } from 'ol/geom';

const style = new Style({
  fill: new Fill({
    color: '#ffcc33',
  }),
  stroke: new Stroke({
    color: '#ffcc33',
    width: 2,
  }),
  image: new CircleStyle({
    radius: 5,
    stroke: new Stroke({
      color: 'rgba(0, 0, 0, 0.7)',
    }),
    fill: new Fill({
      color: 'rgba(255, 255, 255, 0.2)',
    }),
  }),
});

// 标签样式
const labelStyle = new Style({
  text: new Text({
    font: '14px Calibri,sans-serif',
    fill: new Fill({
      color: '#ffcc33',
    }),
    backgroundFill: new Fill({
      color: 'red',
    }),
    padding: [3, 3, 3, 3],
    textBaseline: 'bottom',
    offsetY: -15,
  }),
  image: new RegularShape({
    radius: 8,
    points: 3,
    angle: Math.PI,
    displacement: [0, 10],
    fill: new Fill({
      color: 'rgba(0, 0, 0, 0.7)',
    }),
  }),
});

const tipStyle = new Style({
  text: new Text({
    font: '12px Calibri,sans-serif',
    fill: new Fill({
      color: 'green',
    }),
    backgroundFill: new Fill({
      color: '#fff',
    }),
    padding: [2, 2, 2, 2],
    textAlign: 'left',
    offsetX: 15,
  }),
});

const modifyStyle = new Style({
  image: new CircleStyle({
    radius: 5,
    stroke: new Stroke({
      color: 'blue',
    }),
    fill: new Fill({
      color: 'blue',
    }),
  }),
  text: new Text({
    text: 'Drag to modify',
    font: '12px Calibri,sans-serif',
    fill: new Fill({
      color: 'rgba(255, 255, 255, 1)',
    }),
    backgroundFill: new Fill({
      color: 'rgba(0, 0, 0, 0.7)',
    }),
    padding: [2, 2, 2, 2],
    textAlign: 'left',
    offsetX: 15,
  }),
});

const segmentStyle = new Style({
  text: new Text({
    font: '12px Calibri,sans-serif',
    fill: new Fill({
      color: 'purple',
    }),
    backgroundFill: new Fill({
      color: '#fff',
    }),
    padding: [2, 2, 2, 2],
    textBaseline: 'bottom',
    offsetY: -12,
  }),
  image: new RegularShape({
    radius: 6,
    points: 3,
    angle: Math.PI,
    displacement: [0, 8],
    fill: new Fill({
      color: 'rgba(0, 0, 0, 0.4)',
    }),
  }),
});

const formatLength = function (line) {
  const length = getLength(line);
  let output;
  if (length > 100) {
    output = Math.round((length / 1000) * 100) / 100 + ' km';
  } else {
    output = Math.round(length * 100) / 100 + ' m';
  }
  return output;
};

const formatArea = function (polygon) {
  const area = getArea(polygon);
  let output;
  if (area > 10000) {
    output = Math.round((area / 1000000) * 100) / 100 + ' km\xB2';
  } else {
    output = Math.round(area * 100) / 100 + ' m\xB2';
  }
  return output;
};

const source = new VectorSource();

const modify = new Modify({ source: source, style: modifyStyle });

let tipPoint;

function styleFunction(feature, segments, drawType, tip) {
  const styles = [style];
  const geometry = feature.getGeometry();
  const type = geometry.getType();
  let point, label, line;
  if (!drawType || drawType === type) {
    if (type === 'Polygon') {
      point = geometry.getInteriorPoint();
      label = formatArea(geometry);
      line = new LineString(geometry.getCoordinates()[0]);
    } else if (type === 'LineString') {
      point = new Point(geometry.getLastCoordinate());
      label = formatLength(geometry);
      line = geometry;
    }
  }
  if (segments && line) {
    let count = 0;
    line.forEachSegment(function (a, b) {
      const segment = new LineString([a, b]);
      const label = formatLength(segment);
      if (segmentStyles.length - 1 < count) {
        segmentStyles.push(segmentStyle.clone());
      }
      const segmentPoint = new Point(segment.getCoordinateAt(0.5));
      segmentStyles[count].setGeometry(segmentPoint);
      segmentStyles[count].getText().setText(label);
      styles.push(segmentStyles[count]);
      count++;
    });
  }
  if (label) {
    labelStyle.setGeometry(point);
    labelStyle.getText().setText(label);
    styles.push(labelStyle);
  }
  if (
    tip &&
    type === 'Point' &&
    !modify.getOverlay().getSource().getFeatures().length
  ) {
    tipPoint = geometry;
    tipStyle.getText() && tipStyle.getText().setText(tip);
    styles.push(tipStyle);
  }
  return styles;
}

const vector = new VectorLayer({
  source: source,
  style: function (feature) {
    return styleFunction(feature, true);
  },
});

function addInteraction(map, setDraw) {
  const drawType = 'LineString';
  const activeTip = '点击开始绘制线';
  const idleTip = '点击开始测量';
  let tip = idleTip;
  const draw = new Draw({
    source: source,
    type: drawType,
    style: function (feature) {
      return styleFunction(feature, true, drawType, tip);
    },
  });
  setDraw(draw);
  draw.on('drawstart', function () {
    // 每次先清除
    source.clear();
    modify.setActive(false);
    tip = activeTip;
  });
  draw.on('drawend', function () {
    modifyStyle.setGeometry(tipPoint);
    modify.setActive(true);
    map.once('pointermove', function () {
      modifyStyle.setGeometry();
    });
    tip = idleTip;
  });
  modify.setActive(true);
  map.addInteraction(draw);
}

const segmentStyles = [segmentStyle];

const useDrawLine = (visible) => {
  const [draw, setDraw] = useState(null);
  const map = useMap();

  useEffect(() => {
    if (visible) {
      map.addLayer(vector);
      map.addInteraction(modify);
      addInteraction(map, setDraw);
    } else {
      map.removeInteraction(draw);
      map.removeLayer(vector);
      source.clear();
    }
  }, [visible]);
};

export default useDrawLine;

DrawLine:通过visible来控制开始测量或者结束测量

import React, { useEffect, useState } from 'react';
import useDrawLine from './useDrawLine';

export default (props) => {
  const [visible, setVisible] = useState(false);
  useDrawLine(visible);

  return (
    <div className="drawLine_btn">
      <span role="button" tabIndex={0} onClick={() => setVisible(!visible)}>
        {!visible ? '开始测量' : '结束测量'}
      </span>
    </div>
  );
};
把组件引入<Map><DrawLine /></Map>即可实现

效果图:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
React TS是一个用于构建用户界面的JavaScript库,而VR看房可以通过使用WebVR技术来实现。在React TS中实现VR看房需要以下步骤: 1. 了解WebVR技术:WebVR是一种使Web应用程序能够在虚拟现实设备上运行的技术,它提供了一种在虚拟现实设备上渲染内容的方式。 2. 导入WebVR库:在React TS项目中,需要导入与WebVR相关的库,例如A-Frame或React 360等,这些库提供了一些用于构建VR界面的组件和功能。 3. 创建VR场景:使用React TS的组件化开发方式,可以通过在项目中创建VR场景组件来构建VR看房的界面。可以使用库中提供的组件来构建3D场景、添加虚拟现实设备的交互等。 4. 加载房屋模型:在VR场景中加载房屋模型,可以使用库中提供的加载器将3D房屋模型导入到场景中,并设置适当的位置和缩放。 5. 添加交互功能:为了实现VR看房的功能,需要添加一些交互功能,例如移动、旋转和缩放房屋模型,点击房间以获取更多信息等。可以使用库中提供的交互组件或自定义事件处理程序来实现这些功能。 6. 兼容不同的设备:考虑到不同的虚拟现实设备,需要在React TS项目中进行一些适配工作,以确保VR看房界面在不同设备上的兼容性。 总的来说,使用React TS实现VR看房需要对WebVR技术有一定的了解,并结合具体的库和组件来构建VR场景、加载房屋模型,并添加交互功能。不同设备的兼容性也是一个需要考虑的因素。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值