skip to Main Content

Get a html div element cloned on canvas with clone node. Is there a way to get it done.

Is there any way to get a html element (a div and a paragraph inside the div with height and width of 100px and background color which makes it look like a square) cloned on canvas element. Is it possible/allowed.

Thanks
Latha

2

Answers


  1. The <canvas>-element is a primitive drawing facility that allows to create images. It’s visible content isn’t based on a DOM and therefor cannot take another <div>-element (or whatsoever) as "content". However, it may be possible to recreate the appearance of the <div>-element via primitive shapes on the <canvas>.

    Below is a (halfway) working example. The line-breaks are a bit off, but it should be enough to lead you in the right direction.

    // === MAIN PROGRAM ===
    function main() {
      const sourceEl = document.querySelector('#source');
      const sourceParagraphEl = sourceEl.querySelector('p');
    
      const canvasEl = document.querySelector('#surface');
      const ctx = canvasEl.getContext('2d');
      
      const styles = getStyle(sourceEl, [
        'width',
        'height',
        'paddingBlockStart',
        'paddingInlineStart',
        'backgroundColor',
        'color',
        'fontFamily',
        'fontSize',
        'lineHeight'
      ]);
      
      drawElement(ctx, styles, sourceParagraphEl);
    }
    
    main();
    
    
    // === UTILITY FUNCTIONS ===
    
    // type StyleKey = String
    // type StyleVal = String | Number
    // type StyleDetails = { [StyleKey]: StyleVal }
    
    // drawElement :: (CanvasContext2D, StyleDetails, String) -> CanvasContext2D
    function drawElement(ctx, styles, textEl) {
      ctx.fillStyle = styles.backgroundColor;
      ctx.fillRect(0, 0, parseFloat(styles.width), parseFloat(styles.height));
      
      ctx.fillStyle = styles.color;
      ctx.font = `${styles.fontSize}/${styles.lineHeight} normal ${styles.fontFamily}`;
      
      const text = getText(textEl, ctx);
      let textX = parseFloat(styles.paddingInlineStart);
      let textY = 2 * parseFloat(styles.paddingBlockStart);
      let textL = parseFloat(styles.lineHeight);
      let i = 0;
      while (i < text.length) {
        let line = text[i].join(' ');
        ctx.fillText(line, textX, textY);
        textY += textL;
        i += 1;
      }
      
      return ctx;
    }
    
    // getText :: (HTMLElement, CanvasContext2D) -> [[String]]
    function getText(el, ctx) {
      const content = el.textContent.trim().split(/s+/g);
      const maxWidth = el.offsetWidth;
      const lines = [];
      
      let line = [];
      let lineW = 0;
      for (let i = 0; i < content.length; i += 1) {
        let word = content[i];
        let dim = ctx.measureText(word);
        
        if (lineW + dim.width > maxWidth) {
          lines.push(line);
          line = [word];
          lineW = 0;
        } else {
          line.push(word);
          lineW += dim.width;
        }
      }
      
      lines.push(line);
      return lines;
    }
    
    // getStyle :: (HTMLElement, [StyleKey]) -> StyleDetails
    function getStyle(el, styleKeys) {
      return styleKeys.reduce(
        (acc, key) => {
          let style = el.style[key];
          if (style === '') {
            style = window.getComputedStyle(el)[key];
          }
          return Object.assign(acc, { [key]: style });
        },
        Object.create(null)
      );
    }
    *, *::before, *::after {
      box-sizing: border-box;
    }
    
    #surface {
      border: 1px dotted black;
    }
    
    
    
    #source {
      width: 100px;
      height: auto;
      padding: 1rem;
      background-color: red;
      color: white;
      font-size: 1rem;
      line-height: 1.5;
    }
    
    #source p {
      margin: 0;
    }
    <canvas id="surface" width="200" height="200"></canvas>
    <div id="source">
      <p>lorem ipsum dolor sit amet...</p>
    </div>
    Login or Signup to reply.
  2. Here is an option to do that. Keep in mind that if the div has a more complicated style it will need to be added also to the data style. It is fairly short and understandable to work with and keeps the exact look of the div element

    const myDiv = document.getElementById("myDiv");
    const divStyle = window.getComputedStyle(myDiv);
    const myCanvas = document.getElementById("myCanvas");
    const myCanvasContext = myCanvas.getContext("2d");
    
    function drawOnCanvas(event) {
      const divWidth = myDiv.clientWidth;
      const divHeight = myDiv.clientHeight;
      const DOMURL = self.URL || self.webkitURL || self;
    
      const data = `
        <svg xmlns='http://www.w3.org/2000/svg' width='${divWidth}px' height='${divHeight}px'>
          <foreignObject width='100%' height='100%'>
            <div
              xmlns='http://www.w3.org/1999/xhtml'
              style='
                font-size: ${divStyle.getPropertyValue("font-size")};
                background-color: ${divStyle.getPropertyValue("background-color")};
                color: ${divStyle.getPropertyValue("color")};
              '
            >${myDiv.innerHTML}</div>
          </foreignObject>
        </svg>
      `
    
      const img = new Image();
      const svg = new Blob([data], {
        type: "image/svg+xml;charset=utf-8"
      });
      const url = DOMURL.createObjectURL(svg);
    
      img.addEventListener("load", () => {
        DOMURL.revokeObjectURL(url);
        myCanvasContext.drawImage(img, 0, 0);
      }, false);
      img.src = url;
    
      myCanvasContext.canvas.width = divWidth;
      myCanvasContext.canvas.height = divHeight;
    }
    #myDiv {
      width: 100px;
      height: 100px;
      font-size: 16px;
      background-color: red;
      color: white;
    }
    
    #myCanvas {
      border: 1px solid black;
    }
    <div id="myDiv">
      Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s
    </div>
    <canvas id="myCanvas" width="200" height="200"></canvas>
    <button onclick="drawOnCanvas(event)">Draw</button>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search