SOURCE

console 命令行工具 X clear

                    
>
console
  var ctx = null
  var IMAGE_WIDTH = 0
  var IMAGE_HEIGHT = 0
  var CANVAS_WIDTH = 800
  var CANVAS_HEIGHT = 800
  var arcRadius = 15
  var originPoints, newPoints, splitPoints = [], splitH = 0, splitV = 0
  var originSplitPoints
  var newSplitPoints

  var imgLeft, imgTop
  var img = new Image()
  img.src = 'https://gaisama.gitee.io/js-demos/img/test.jpg'
  img.onload = function () {

    var canvas = document.getElementById('cas')
    var pageWidth = document.documentElement.clientWidth
    var pageHeight = document.documentElement.clientHeight
    var canvasLeft = (pageWidth - CANVAS_WIDTH) / 2
    var canvasTop = 80
    var targetPoint, mouseX, mouseY

    ctx = canvas.getContext('2d')

    IMAGE_WIDTH = img.width / 2
    IMAGE_HEIGHT = img.height / 2

    canvas.width = CANVAS_WIDTH
    canvas.height = CANVAS_HEIGHT
    imgLeft = (canvas.width - IMAGE_WIDTH) / 2
    imgTop = (canvas.height - IMAGE_HEIGHT) / 2

    img.width = IMAGE_WIDTH
    img.height = IMAGE_HEIGHT

    splitH = 20
    splitV = 20

    originPoints = [
      {
        x: imgLeft, y: imgTop
      },
      {
        x: imgLeft + IMAGE_WIDTH, y: imgTop
      },
      {
        x: imgLeft + IMAGE_WIDTH, y: imgTop + IMAGE_HEIGHT
      },
      {
        x: imgLeft, y: imgTop + IMAGE_HEIGHT
      },
    ]

    originSplitPoints = generatePoints(originPoints, splitH, splitV)

    // newPoints = [
    //   {
    //     x: 100, y: 50
    //   },
    //   {
    //     x: 500, y: 200
    //   },
    //   {
    //     x: 700, y: 500
    //   },
    //   {
    //     x: 100, y: 600
    //   }
    // ]
    newPoints = JSON.parse(JSON.stringify(originPoints))

    window.onresize = function () {
      pageWidth = document.documentElement.clientWidth
      pageHeight = document.documentElement.clientHeight
      canvasLeft = (pageWidth - CANVAS_WIDTH) / 2
      canvasTop = 80
    }
    var dragging = false
    document.body.onmousedown = function (e) {
      dragging = true
      mouseX = e.clientX - canvasLeft
      mouseY = e.clientY - canvasTop
      for (var i = 0; i < 4; i++) {
        if (mouseX > newPoints[i].x - arcRadius && mouseX < newPoints[i].x + arcRadius && mouseY > newPoints[i].y - arcRadius && mouseY < newPoints[i].y + arcRadius) {
          targetPoint = newPoints[i]
          console.log('targetPoint:', targetPoint)
          break
        }
      }
    }
    document.body.onmousemove = function (e) {
      if (dragging && targetPoint) {
        targetPoint.x = e.clientX - canvasLeft
        targetPoint.y = e.clientY - canvasTop
        update()
      }
    }
    document.body.onmouseup = function (e) {
      dragging = false
    }

    update()
  }

  function update () {

    newSplitPoints = generatePoints(newPoints, splitH, splitV)

    ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT)
    ctx.save()
    ctx.fillStyle = 'rgba(255,255,255,0.2)'
    ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT)

    for (var i = 0; i < newSplitPoints.length; i++) {
      if (i < newSplitPoints.length - splitH - 2 && (i + 1) % (splitH + 1) !== 0) {
        drawTriangleImage(
          originSplitPoints[i + 1], originSplitPoints[i + 1 + splitH + 1], originSplitPoints[i + splitH + 1],
          newSplitPoints[i + 1], newSplitPoints[i + 1 + splitH + 1], newSplitPoints[i + splitH + 1]
        ) // 先画下三角
        drawTriangleImage(
          originSplitPoints[i], originSplitPoints[i + 1], originSplitPoints[i + splitH + 1],
          newSplitPoints[i], newSplitPoints[i + 1], newSplitPoints[i + splitH + 1]
        )  // 再画上三角
      }
      // 四个角
      if (i === 0 || i === splitH || i === (splitH + 1) * splitV || i === (splitH + 1) * (splitV + 1) - 1) {
        drawArc(newSplitPoints[i])
      }
    }
    ctx.restore()
  }

  /**
   * 生成分割点
   * @param points 四边形四个点
   * @param splitH “水平”方向被等分数
   * @param splitV “竖直”方向被等分数
   */
  function generatePoints (points, splitH, splitV) {
    splitPoints = []
    var vLeft = {
      x: (points[3].x - points[0].x) / splitV,
      y: (points[3].y - points[0].y) / splitV
    }
    var vRight = {
      x: (points[2].x - points[1].x) / splitV,
      y: (points[2].y - points[1].y) / splitV
    }
    var x1, y1, x2, y2
    var i, j
    for (i = 0; i <= splitV; i++) {
      x1 = points[0].x + vLeft.x * i
      y1 = points[0].y + vLeft.y * i
      x2 = points[1].x + vRight.x * i
      y2 = points[1].y + vRight.y * i
      for (j = 0; j <= splitH; j++) {
        splitPoints.push({
          x: x1 + (x2 - x1) / splitH * j,
          y: y1 + (y2 - y1) / splitH * j
        })
      }
    }
    return splitPoints
  }

  /**
   * 画三角形图片
   */
  function drawTriangleImage (p1, p2, p3, newP1, newP2, newP3) {
    var result = mathUtil.Matrix.get2DTransformMatrix(p1, p2, p3, newP1, newP2, newP3)
    ctx.save()
    //根据变换后的坐标创建剪切区域
    ctx.beginPath()
    ctx.moveTo(newP1.x, newP1.y)
    ctx.lineTo(newP2.x, newP2.y)
    ctx.lineTo(newP3.x, newP3.y)
    ctx.closePath()
    ctx.lineWidth = 1
    ctx.strokeStyle = 'red'
    ctx.stroke()
    ctx.clip()
    //绘制图片
    ctx.transform(result.a, result.b, result.c, result.d, result.e, result.f)
    ctx.drawImage(img, imgLeft, imgTop, IMAGE_WIDTH, IMAGE_HEIGHT)
    ctx.restore()
  }

  /**
   * 画四边形的四个点
   */
  function drawArc (point) {
    ctx.save()
    ctx.beginPath()
    ctx.arc(point.x, point.y, arcRadius, 0, 2 * Math.PI)
    ctx.strokeWidth = 3
    ctx.strokeStyle = '#fff'
    ctx.stroke()
    ctx.restore()
  }
<div>
    <canvas id='cas' width="500" height="500" style="background-color:#000">浏览器不支持canvas</canvas>
</div>
 body {
    padding: 0;
    margin: 0;
    overflow: hidden;
}

#cas {
    display: block;
    margin: 80px auto;
}

本项目引用的自定义外部资源