js 使用 canvas 绘制地图路线

使用 canvas 绘制 跟随鼠标自定义路线 或 点使用贝塞尔曲线 自动绘制

示例使用 angular 可自行修改 核心代码不变
在这里插入图片描述

基础 html 参考

<div class="container" id="container" (mousedown)="addEventListen($event)" (mouseup)="removeEventListen()"
  [ngStyle]="{'width': snadTable.width + 'px' , 'height': snadTable.height + 'px'}" id="edit-canvas">
  <img class="bg" id="bgImg" [width]="snadTable.width" [height]="snadTable.height" [src]="snadTable.background.url">

  <!-- 新路径 canvas 模式 -->
  <canvas class="way" (click)="handleNewPosition($event)" (mousedown)="$event.preventDefault()"
    [ngStyle]="{'z-index': canvasZIndex}" #way id="way" [width]="snadTable.width" [height]="snadTable.height"></canvas>

  <!-- 线路上的 关键点 icon -->
  <div *ngFor="let line of snadTable.paths">
    <div class="line" *ngFor="let keyPoint of line.points" [ngClass]="{'activity': currKeyPoint.uid === keyPoint.uid }"
      [ngStyle]="{'left': keyPoint?.position?.x - (keyPoint?.width / 2) + 'px' , 'top': keyPoint?.position?.y - (keyPoint?.height / 2) + 'px', 'transform': 'scale(' + keyPoint.scale + ') rotate(' +keyPoint.rotate + 'deg)'}"
      (click)="onSetKeyPoint(keyPoint)" (click)="$event.preventDefault()" (mousedown)="$event.preventDefault()">
      <img class=" " [src]="keyPoint.url"
        [ngStyle]="{'width': keyPoint.width + 'px', 'height': keyPoint.height + 'px' }">
    </div>
  </div>
  <!-- 新 关键点 -->
  <div class="line" *ngIf="currKeyPoint?.uid"
    [ngStyle]="{'left': currKeyPoint?.position?.x - (currKeyPoint?.width / 2) + 'px' , 'top': currKeyPoint?.position?.y - (currKeyPoint?.height / 2) + 'px', 'transform': 'scale(' + currKeyPoint.scale + ') rotate(' +currKeyPoint.rotate + 'deg)'}"
    (mousedown)="$event.preventDefault()">
    <img class="" [src]="currKeyPoint.url"
      [ngStyle]="{'width': currKeyPoint.width + 'px', 'height': currKeyPoint.height + 'px'}">
  </div>
</div>

css 加一些定位就行

ts 逻辑

  /** 创建画布 配置样式 */
  createdCtx(): void {
    this.ctx = this.way.nativeElement.getContext("2d");
    console.log(this.ctx);

    // this.ctx.strokeStyle = 'rgb(255,221,0)';
    // const that = this;
    // var img = new Image();
    // img.src = 'https://mdn.mozillademos.org/files/222/Canvas_createpattern.png';
    // img.onload = function () {
    //   var pattern = that.ctx.createPattern(img, 'repeat');
    //   that.ctx.strokeStyle = pattern;
    //   // that.ctx.fillRect(0, 0, 400, 400);
    // };
    this.ctx.setLineDash([15, 5]);
    this.ctx.shadowOffsetX = 0;
    this.ctx.shadowOffsetY = 0;
    // this.ctx.shadowBlur = 10;
    // this.ctx.shadowColor = "#55514c";
    this.ctx.lineWidth = 10;
    // this.ctx.lineDashOffset = 3
    // this.ctx.strokeStyle = "red"
  }
/** 监听开始滑动 */
addEventListen(e): void {
   this.canvasZIndex = 99; // 处于最高层级, 使操作跟手
   document.getElementById("way").addEventListener('mousemove', this.handleMapPositin, false);
  }
/** 移除监听事件 */
removeEventListen(): void {
    document.getElementById("way").removeEventListener('mousemove', this.handleMapPositin, false);
    this.canvasZIndex = 0; //
    this.isAddEventListen = false;
  }
  /** 
   * 触摸中处理逻辑函数 自定义
   * 该处 使用 贝塞尔函数辅助划线 
   * 不使用的 可直接进行赋值绘画,则为自定义画
   */
  handleMapPositin = (e) => {
    this.currKeyPoint.position = { x: e.layerX, y: e.layerY };
      this.bzCurve();
      // this.drawWay(e.layerX, e.layerY); // 自定义画
  }

  
 /** 不使用贝塞尔曲线绘制函数 */
 drawWay(x: number, y: number): void {
    if (this.isMoveTo) {
      this.ctx.moveTo(x, y);
      this.isMoveTo = false;
    } else {
      this.ctx.lineTo(x, y);
    }
    this.ctx.stroke();
  }
/** 使用贝塞尔曲线 */
 bzCurve(f: number = .3, t: number = .5) {
    this.ctx.clearRect(0, 0, this.snadTable.width, this.snadTable.height);  // 每次绘制重置画布防残留,配合下面的延时 setTimeout 一起使用
    if (this.snadTable.paths?.length > 0) { // 多条不连续路线循环绘制
      setTimeout(() => {
        for (const line of this.snadTable.paths) {
          if (line.points?.length > 0) {
            const points = line.points.map(val => val.position);
            // console.log(points);
            this.ctx.strokeStyle = line.color;
            this.ctx.beginPath();
            this.ctx.moveTo(points[0].x, points[0].y);
            let m = 0;
            let dx1 = 0;
            let dy1 = 0;
            let preP = points[0];
            let dx2 = 0;
            let dy2 = 0;
            for (var i = 1; i < points.length; i++) {
              let curP = points[i];
              const nexP = points[i + 1];
              if (nexP) {
                m = this.gradient(preP, nexP);
                dx2 = (nexP.x - curP.x) * -f;
                dy2 = (nexP.y - curP.y) * -f; // dx2 * m * t;
              } else {
                dx2 = 0;
                dy2 = 0;
              }
              this.ctx.bezierCurveTo(
                preP.x - dx1, preP.y - dy1,
                curP.x + dx2, curP.y + dy2,
                curP.x, curP.y
              );
              dx1 = dx2;
              dy1 = dy2;
              preP = curP;
            }
            this.ctx.stroke();
          }
        }
      }, 1);
    }
  }
  /** 两点的斜率 */
  gradient(a, b): number {
    return (b.y - a.y) / (b.x - a.x);
  }
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值