Canvas only draws outside the table, with the exception of the first one

I am facing an issue with placing multiple signature pads inside table cells.

Only the first canvas gets drawn, while the others remain blank. I have checked the mouse/touch events. The events are triggered (up/down/move) and the draw function is called, but the canvas does not get drawn.

On using toDataURL, the result is just a white image.

The canvas outside the table works perfectly fine and gets drawn as expected.

I have searched for documentation on this issue but couldn't find any. Any help would be appreciated.

Here is the code snippet:

// This is the 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 = []

  // Rest of the code for event handlers and Vue component
<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>

Answer №1

There was an issue with the offset.

I mistakenly extracted the offset coordinates of the canvas, but it should refer to the border box of an element relative to the offsetParent.

The correct method to use is Element.getClientRects()

The code below has been adjusted.

// This is the draw function
const initialize = function (element) {
  let context = element.getContext("2d");
  context.strokeStyle = "#df4b26";
  context.lineJoin = "round";
  context.lineWidth = 2;

  let clientRect = element.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 downHandler(event) {
    down = true
    addPoint(event, {first: true})
    event.preventDefault()
  }

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

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

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

  element.addEventListener("pointerdown", downHandler, false);
  element.addEventListener("pointermove", moveHandler, false);
  element.addEventListener("pointerup", upHandler, false);
  element.style['touch-action'] = 'none'
}

Vue.component('signature', {
  props: {
    width: {
      type: Number,
      required: true,
    },
    height: {
      type: Number,
      required: true,
    },
    customStyle: {
      type: Object,
      default() {
        return {}
      },
    },
  },
  mounted() {
    initialize(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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Learn how to access the checkbox event.target.checked and event.target.value properties in Vuetify

How can I retrieve the checked status and value of a Vuetify checkbox using event.target.checked and event.target.value? In my application, I am utilizing Vuetify's checkbox component. When the user interacts with the checkbox by checking or unchecki ...

Problem with flags series in Highcharts/Highstock

Can anyone help me figure out why not all the flags in the withdrawals series are displaying? For reference, you can view the following JS fiddle: https://jsfiddle.net/lucianpurcarea/5zxa0jsm/13/ The snippet of code below is responsible for creating the d ...

Understanding how to break down intricate JSON strings into classes using either VB or C# programming languages

I have a JSON string that needs to be parsed and eventually stored in database tables. My plan is to parse it into VB .NET classes (objects) and then store the data in the tables. I have Newtown imported into my .NET environment, but I'm not very fami ...

Dynamic components enable parental involvement in child communication

My goal is to create a user-friendly form using VUE and LARAVEL where users can build groups of participants dynamically. I have chosen to address this challenge by allowing users to generate a table for each group, where they can add or remove rows. So f ...

Creating a scrolling effect similar to the Nest Thermostat

After researching countless references, I am determined to achieve a scrolling effect similar to the Nest Thermostat. I came across this solution on this JSFiddle, but unfortunately, the parent element has a fixed position that cannot be utilized within my ...

What is the jQuery equivalent for converting this JavaScript code?

Here's a code snippet that I am struggling with: data=>{document.querySelector( "#os11.html-widget.gauge svg text[font-size='10px'] tspan" ).innerHTML = data.text I attempted the following solution: $("#os11.html ...

Display alternative text dynamically

Trying to gain a deeper understanding of state in react, this is a perfect example to me. When I say dynamic, I mean displaying the output below instantly as it is entered in the form. class Demo extends Component { constructor(props) { super ...

What is the best way to sort through this complex array of nested objects in Typescript/Angular?

tableData consists of an array containing PDO objects. Each PDO object may have zero or more advocacy (pdo_advocacies), and each advocacy can contain zero or more programs (pdo_programs). For example: // Array of PDO object [ { id: 1, ...

Looking for an iframe that can adapt to varying content sizes and scale seamlessly with different screen dimensions?

I am new to advanced coding and currently working on my first responsive Wordpress site. I have a "Product Search" database/site that I'm trying to integrate into my website using an iFrame. I want the integration to look seamless without scroll bars ...

Obtain the URL link from Unsplash where the picture is sourced

As I work on a website, I incorporate a link () to display a random photo. However, the photo refreshes periodically and upon loading the site, all that is visible is this default link: . Is there a method to extract the actual source like so: "". Althou ...

Creating fake data on a worldwide scale with Vue testing utilities

I'm currently working on a Vue component that includes an img tag with the src value coming from props. <template> <div> <img src="some url"> </div> </template> However, I have this img tag used in mult ...

Is there a way to use JavaScript to import several custom fonts at once?

Is there a way to import a long list of custom fonts as icons using Javascript? I have been obtaining the font list from an API, but importing them one by one with pure CSS using @font-face is time-consuming and difficult to maintain. @font-face { fon ...

Arrow indicating the correct direction to expand or collapse all items with a single click

I have successfully implemented the "expand/collapse all" function, but I am facing an issue with the arrow direction. The arrows are not pointing in the correct direction as desired. Since I am unsure how to fix this problem, I have left it empty in my co ...

Exploring the incorporation of interfaces into Vue.js/Typescript for variables. Tips?

I have an interface:   export interface TaskInterface{ name: string description1: string time: string } and a component import { TaskInterface } from '@/types/task.interface' data () { return { tasks: [ { name: 'Create ...

Integrate the dForm plugin with a convenient time picker widget

Currently, I am attempting to integrate a time picker widget into a jQuery plugin called dForm. The specific timepicker widget can be found at the following link: https://github.com/jonthornton/jquery-timepicker Despite reviewing the dForm documentation, ...

Vue 3 tutorial: How to implement v-model calculations with Axios in a web application

Currently, I am delving into the world of CRUD with Laravel 9, Vue 3, and axios. My current project involves number calculations using v-model. While the code is working fine, I have encountered a significant issue. I managed to successfully calculate &ap ...

The npm start command is no longer functioning in Angular 5

When attempting to start angular 5 with npm, I encountered an error that reads: TypeError: callbacks[i] is not a function Can anyone shed some light on where this error might be coming from? It seemed to pop up out of the blue and I can't seem to ...

Do all descendants consistently trigger rerenders?

Recently, I was exploring the React new documentation here, where I came across this interesting piece of information: The context value mentioned here is a JavaScript object with two properties, one being a function. Whenever MyApp re-renders (for examp ...

Angular-ui typeahead feature allows users to search through a predefined

I recently developed a typeahead feature using the angular-ui library. Here is the current HTML for my typeahead: <input name="customers" id="customers" type="text" placeholder="enter a customer" ng-model="selectedCustomer" uib-typeahead="customer.fir ...

Shut down the tab or browser window containing information on vue

When attempting to log off a user by closing the page and browser, I encountered difficulty. 1. window.onunload; 2. window.onbeforeunload. window.onunload = function() { differTime = new Date().getTime() - beginTime; if (differTime <= 5) { cle ...