繁体   English   中英

如何根据我在打开图层的文本框中输入的值添加动画箭头

[英]How to add animated arrow as per the value I have entered in text box in open layers

我试图根据我们在文本框中输入的值在字符串上一个一个地添加动画箭头,但这是不可能的。 可以告诉我如何添加这个。

我想当我们在文本框中输入 4 然后单击添加箭头按钮然后在行字符串中的 2 秒间隙中一个接一个地添加 4 个动画箭头图标。

点击此处查看图片

import Feature from 'ol/Feature';
import LineString from 'ol/geom/LineString';
import Map from 'ol/Map';
import Point from 'ol/geom/Point';
import Polyline from 'ol/format/Polyline';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import OSM from 'ol/source/OSM';
import {Icon, Stroke, Style} from 'ol/style';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import {getVectorContext} from 'ol/render';

const center = [-5639523.95, -3501274.52];
const map = new Map({
  target: document.getElementById('map'),
  view: new View({
    center: center,
    zoom: 10,
    minZoom: 2,
    maxZoom: 19,
  }),
  layers: [
    new TileLayer({
      source: new OSM(),
    }),
  ],
});

// The polyline string is read from a JSON similiar to those returned
// by directions APIs such as Openrouteservice and Mapbox.
fetch('data/polyline/route.json').then(function (response) {
  response.json().then(function (result) {
    const polyline = result.routes[0].geometry;

    const route = new Polyline({
      factor: 1e6,
    }).readGeometry(polyline, {
      dataProjection: 'EPSG:4326',
      featureProjection: 'EPSG:3857',
    });

    const routeFeature = new Feature({
      type: 'route',
      geometry: route,
    });
    const startMarker = new Feature({
      type: 'icon',
      geometry: new Point(route.getFirstCoordinate()),
    });
    const endMarker = new Feature({
      type: 'icon',
      geometry: new Point(route.getLastCoordinate()),
    });
    const position = startMarker.getGeometry().clone();
    const geoMarker = new Feature({
      type: 'geoMarker',
      geometry: position,
    });

    const styles = {
      route: new Style({
        stroke: new Stroke({
          width: 6,
          color: [237, 212, 0, 0.8],
        }),
      }),
      icon: new Style({
        image: new Icon({
          anchor: [0.5, 1],
          src: 'data/icon.png',
        }),
      }),
      geoMarker: new Style({
        image: new Icon({
          src:
            'https://cdn1.iconfinder.com/data/icons/basic-ui-elements-color-round/3/19-32.png',
          rotation: getAngleAt(route, 0) + Math.PI / 2,
        }),
      }),
    };

    const vectorLayer = new VectorLayer({
      source: new VectorSource({
        features: [routeFeature, geoMarker, startMarker, endMarker],
      }),
      style: function (feature) {
        return styles[feature.get('type')];
      },
    });

    map.addLayer(vectorLayer);

    const speedInput = document.getElementById('speed');
    const startButton = document.getElementById('start-animation');
    let animating = false;

    function getAngleAt(lineString, distance) {
      const length = lineString.getLength();
      const coordinates = lineString.getCoordinates();
      for (let i = 1, len = coordinates.length; i <= len; ++i) {
        if (
          new LineString(coordinates.slice(0, i + 1)).getLength() >=
          length * distance
        ) {
          return -Math.atan2(
            coordinates[i][1] - coordinates[i - 1][1],
            coordinates[i][0] - coordinates[i - 1][0]
          );
        }
      }
    }

    const lastTimes = [];
    function moveFeature(event) {
      const speed = Number(speedInput.value);
      const time = event.frameState.time;
      for (let i = 0, ii = lastTimes.length; i < ii; ++i) {
        let {lastTime, distance} = lastTimes[i];
        const elapsedTime = time - lastTime;
        distance = (distance + (speed * elapsedTime) / 1e6) % 2;
        lastTime = time;
        lastTimes[i] = {lastTime, distance};
        const lineDistance = distance > 1 ? 2 - distance : distance;
        const direction = distance > 1 ? -Math.PI / 2 : Math.PI / 2;
        const currentCoordinate = route.getCoordinateAt(lineDistance);
        const angle = getAngleAt(route, lineDistance) + direction;
        styles.geoMarker.getImage().setRotation(angle);
        position.setCoordinates(currentCoordinate);
        const vectorContext = getVectorContext(event);
        vectorContext.setStyle(styles.geoMarker);
        vectorContext.drawGeometry(position);
      }
      // tell OpenLayers to continue the postrender animation
      map.render();
    }

    function startAnimation() {
      lastTimes.push({lastTime: Date.now(), distance: 0});
      if (!animating) {
        animating = true;
        //startButton.textContent = 'Stop Animation';
        vectorLayer.on('postrender', moveFeature);
        // hide geoMarker and trigger map render through change event
        geoMarker.setGeometry(null);
      }
    }

    startButton.addEventListener('click', startAnimation);
  });
});

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Marker Animation</title>
    <link rel="stylesheet" href="node_modules/ol/ol.css">
    <style>
      .map {
        width: 100%;
        height: 400px;
      }
    </style>
  </head>
  <body>
    <div id="map" class="map"></div>
    <label for="speed">
      speed:&nbsp;
      <input id="speed" type="range" min="10" max="999" step="10" value="60">
    </label>
    <button id="start-animation">Start Animation</button>
    <input type="text" id="textValue">
    <button id="btnClick">Add icon</button>
    <!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
    <script src="https://unpkg.com/elm-pep@1.0.6/dist/elm-pep.js"></script>
    <script type="module" src="main.js"></script>
  </body>
</html>

我正在尝试使用此代码根据文本框值添加动画箭头,但没有获得有关如何添加它的任何解决方案。

请查看我的图像以了解我想要的内容。

您需要以 500 毫秒的间隔启动每个 animation,直到启动了所需数量的箭头:

function startAnimations() {
  const arrows = Number(arrowsInput.value);
  if (arrows > 0) {
    let count = 0;
    const id = setInterval(function () {
      startAnimation();
      ++count;
      if (count === arrows) {
        clearInterval(id);
      }
    }, 500);
  }
}
startButton.addEventListener('click', startAnimations);

https://codesandbox.io/s/feature-move-animation-forked-2ckr74

要沿路径移动元素,只需使用方法getPointAtLength

所以想象一下我们有一些像:

div class="wrapper">
  <svg viewBox="-5 -5 173 61" width="173" heigth="61">
    <path
      #path
      d="M153,20.89c0-45.88-74.95,0-74.95,0S.5,66.76.5,20.89s77.54,0,77.54,0S153,66.76,153,20.89Z"
      fill="none"
      stroke="#000"
      vector-effect="non-scaling-stroke"
      class="infinity"
    />
  </svg>
  <div #circle class="element"></div>
</div>
<button (click)="click()">start</button>

.css

.wrapper{
  position:relative
}
.element{
  position:absolute;
  width:10px;
  height:10px;
  background-color:blueviolet;
  border-radius: 5px;
  top:0;
  left:0;
}

代码:

  @ViewChild('path',{static:true}) path:ElementRef
  @ViewChild('circle',{static:true}) circle:ElementRef

  subscription:any
  distance:number
  fps:number=32
  duration:number=2*this.fps
  time:number;
  ngOnInit()
  {
    this.distance=this.path.nativeElement.getTotalLength()
    const pos=this.path.nativeElement.getPointAtLength(0)
    this.circle.nativeElement.style.left=pos.x+'px'
    this.circle.nativeElement.style.top=pos.y+'px'

  }
  ngOnDestroy(){
    this.subscription && this.subscription.unsubscribe()
  }
  click(){
    this.subscription=timer(0,1000/this.fps).pipe(
      take(this.duration+1)
      ).subscribe(x=>{
      const pos=this.path.nativeElement.getPointAtLength(x*this.distance/this.duration)
      this.circle.nativeElement.style.left=pos.x+'px'
      this.circle.nativeElement.style.top=pos.y+'px'
    })

  }

堆栈闪电战

①如果本文未解决您的问题,请点击查看与本文相关的问题
②如果本文未解决您的问题,请向程序员专用AI小助手提问
暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM