Canvas не рисует внутри таблицы, кроме первой - PullRequest
0 голосов
/ 21 января 2019

Я хочу поместить подпись в ячейки таблицы.

Но только первый холст будет нарисован, а другие нет. Я проверил событие мыши / касания. Он запускается (вверх / вниз / двигаться) и вызывается функция рисования, но холст не рисуется.

Я проверил с 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 голосов
/ 21 января 2019

Это была проблема смещения.

Я просто получаю координаты смещения холста, но он описывает границу рамки элемента относительно 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>
...