除第一个画布外,画布未在表内绘制

时间:2019-01-21 16:04:22

标签: javascript vue.js html5-canvas vue-component

我想在表格单元格中放置一些签名板。

但是仅绘制第一个画布,而其他不绘制。 我检查了鼠标/触摸事件。 它被触发(上/下/移动)并调用了draw函数,但未绘制canvas。

我检查了toDataURL,结果只是白色图像。

桌子外面的帆布很好。绘制效果很好。

我找不到与此相关的文档。请帮助我。

这是代码。

// this is draw function
const init = function (el) {
  let context = el.getContext("2d");
  context.strokeStyle = "#df4b26";
  context.lineJoin = "round";
  context.lineWidth = 2;

  let offset = {
    left: el.offsetLeft,
    top: el.offsetTop,
  }

  let down = false
  let points = []

  function draw() {
    context.beginPath();

    for (let i = 0; i < points.length - 1; i++) {
      const p = points[i]
      const pn = points[i + 1]
      if (pn.x === p.x && p.y === pn.y && p.first && pn.last) {
        context.arc(pn.x, pn.y, 1, 0, 2 * Math.PI);
        context.fill()
      } else {
        context.moveTo(p.x, p.y)
        context.lineTo(pn.x, pn.y)
      }
    }

    context.stroke();
    context.closePath();
  }

  function addPoint(ev, setting) {
    setting = setting || {}

    let p = {
      x: event.pageX - offset.left,
      y: event.pageY - offset.top,
      ...setting,
    }
    points.push(p)
  }

  function down_handler(event) {
    down = true
    addPoint(event, {first: true})
    event.preventDefault()
  }

  function move_handler(event) {
    if (!down) {
      return
    }

    addPoint(event, {drag: true})
    draw()
    event.preventDefault()
  }

  function up_handler(event) {
    down = false
    addPoint(event, {last: true})
    draw()
    points.splice(0, points.length)
    event.preventDefault()
  }

  el.addEventListener("pointerdown", down_handler, false);
  el.addEventListener("pointermove", move_handler, false);
  el.addEventListener("pointerup", up_handler, false);
  el.style['touch-action'] = 'none'
}

Vue.component('signature', {
  props: {
    width: {
      type: Number,
      required: true,
    },
    height: {
      type: Number,
      required: true,
    },
    customStyle: {
      type: Object,
      default() {
        return {}
      },
    },
  },
  mounted() {
    init(this.$refs.signaturePadCanvas)
  },
  render(createElement) {
    const {width, height, customStyle} = this;

    return createElement(
      'div',
      {
        style: {
          width: `${width}px`,
          height: `${height}px`,
          ...customStyle,
        },
      },
      [
        createElement('canvas', {
          attrs: {
            width: width,
            height: height,
          },
          style: {
            width: '100%',
            height: '100%',
            'touch-action': 'none',
            'background': 'gray',
          },
          ref: 'signaturePadCanvas',
        }),
      ],
    );
  },
})

new Vue({
  el: '#app',
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
 <div id="app">
    <table>
      <tr>
        <td>
          <signature :width="200" :height="200"></signature>
        </td>
        <td>
          <signature :width="200" :height="200"></signature>
        </td>
        <td>
          <signature :width="200" :height="200"></signature>
        </td>
      </tr>
      <tr>
        <td>
          <signature :width="200" :height="200"></signature>
        </td>
        <td>
          <signature :width="200" :height="200"></signature>
        </td>
        <td>
          <signature :width="200" :height="200"></signature>
        </td>
      </tr>
    </table>
    <signature :width="200" :height="200"></signature>
    <signature :width="200" :height="200"></signature>
  </div>

1 个答案:

答案 0 :(得分:1)

那是抵销问题。

我只是得到画布的偏移坐标,但是describe the border box of an element relative to the offsetParent.

我应该使用Element.getClientRects()

下面是固定代码。

// this is draw function
const init = function (el) {
  let context = el.getContext("2d");
  context.strokeStyle = "#df4b26";
  context.lineJoin = "round";
  context.lineWidth = 2;

  let clientRect = el.getClientRects()

   let offset = {
     left : clientRect[0].left,
     top : clientRect[0].top,
   }

  let down = false
  let points = []

  function draw() {
    context.beginPath();

    for (let i = 0; i < points.length - 1; i++) {
      const p = points[i]
      const pn = points[i + 1]
      if (pn.x === p.x && p.y === pn.y && p.first && pn.last) {
        context.arc(pn.x, pn.y, 1, 0, 2 * Math.PI);
        context.fill()
      } else {
        context.moveTo(p.x, p.y)
        context.lineTo(pn.x, pn.y)
      }
    }

    context.stroke();
    context.closePath();
  }

  function addPoint(ev, setting) {
    setting = setting || {}

    let p = {
      x: ev.clientX - offset.left,
      y: ev.clientY - offset.top,
      ...setting,
    }
    points.push(p)
  }

  function down_handler(event) {
    down = true
    addPoint(event, {first: true})
    event.preventDefault()
  }

  function move_handler(event) {
    if (!down) {
      return
    }

    addPoint(event, {drag: true})
    draw()
    event.preventDefault()
  }

  function up_handler(event) {
    down = false
    addPoint(event, {last: true})
    draw()
    points.splice(0, points.length)
    event.preventDefault()
  }

  el.addEventListener("pointerdown", down_handler, false);
  el.addEventListener("pointermove", move_handler, false);
  el.addEventListener("pointerup", up_handler, false);
  el.style['touch-action'] = 'none'
}

Vue.component('signature', {
  props: {
    width: {
      type: Number,
      required: true,
    },
    height: {
      type: Number,
      required: true,
    },
    customStyle: {
      type: Object,
      default() {
        return {}
      },
    },
  },
  mounted() {
    init(this.$refs.signaturePadCanvas)
  },
  render(createElement) {
    const {width, height, customStyle} = this;

    return createElement(
      'div',
      {
        style: {
          width: `${width}px`,
          height: `${height}px`,
          ...customStyle,
        },
      },
      [
        createElement('canvas', {
          attrs: {
            width: width,
            height: height,
          },
          style: {
            width: '100%',
            height: '100%',
            'touch-action': 'none',
            'background': 'gray',
          },
          ref: 'signaturePadCanvas',
        }),
      ],
    );
  },
})

new Vue({
  el: '#app',
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
 <div id="app">
    <table>
      <tr>
        <td>
          <signature :width="200" :height="200"></signature>
        </td>
        <td>
          <signature :width="200" :height="200"></signature>
        </td>
        <td>
          <signature :width="200" :height="200"></signature>
        </td>
      </tr>
      <tr>
        <td>
          <signature :width="200" :height="200"></signature>
        </td>
        <td>
          <signature :width="200" :height="200"></signature>
        </td>
        <td>
          <signature :width="200" :height="200"></signature>
        </td>
      </tr>
    </table>
    <signature :width="200" :height="200"></signature>
    <signature :width="200" :height="200"></signature>
  </div>