)
}
}
)
(
}
{
)
)
(
)
(
(
{
}
)
(
)
}
)
)
{
(
(
)
)
}
)
(
}

SVG Drawing Program

  1. <!DOCTYPE html>
  2. <html lang="en">
  3.   <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  6.  
  7.     <title>Drawing</title>
  8.     <style>
  9.       body,
  10.       html {
  11.         user-select: none;
  12.         height: 100%;
  13.         margin: 0;
  14.         font-family: sans-serif;
  15.         background: white;
  16.       }
  17.  
  18.       body {
  19.         position: fixed;
  20.         top: 0;
  21.       }
  22.  
  23.       .ui {
  24.         position: fixed;
  25.         display: flex;
  26.         bottom: 0;
  27.         width: 100%;
  28.         margin-bottom: .2em;
  29.       }
  30.  
  31.       .ui .tool {
  32.         font-size: 2em;
  33.         flex: 1;
  34.         text-align: center;
  35.       }
  36.  
  37.       .tool span {
  38.         cursor: pointer;
  39.         display: inline-block;
  40.         transform: scale(0.7);
  41.         transition: transform 250ms ease-out;
  42.       }
  43.  
  44.       .tool span.selected {
  45.         transform: scale(1);
  46.       }
  47.  
  48.       svg {
  49.         overflow: visible;
  50.         height: 100%;
  51.         width: 100%;
  52.         margin: 0;
  53.         padding: 0;
  54.       }
  55.  
  56.       input[type=color] {
  57.         position: absolute;
  58.         left: 0;
  59.         top: 0;
  60.         height: 100%;
  61.         opacity: 0;
  62.         cursor: pointer;
  63.       }
  64.  
  65.       .message {
  66.         position: fixed;
  67.         left: 0;
  68.         top: 0;
  69.         padding: 1em;
  70.         width: 100%;
  71.         text-align: center;
  72.         font-size: 1.2em;
  73.         transition: opacity 250ms ease-out;
  74.         pointer-events: none;
  75.       }
  76.  
  77.       .message.hide {
  78.         opacity: 0;
  79.       }
  80.     </style>
  81.   </head>
  82.   <body>
  83.  
  84.     <svg class="paper" width="100%" height="100%">
  85.       <style>
  86.         path {
  87.           stroke-linecap: round;
  88.           stroke-linejoin: round;
  89.           fill: none;
  90.         }
  91.       </style>
  92.     </svg>
  93.     <div class="ui">
  94.       <div class="tool"><span class="pencil" class="pencil icon selected">&#9999;&#65039;</span></div>
  95.       <div class="tool"><span class="brush icon">&#128396;&#65039;</span></div>
  96.       <div class="tool"><span class="colors icon">&#x1f3a8;
  97.         <input class="color" type="color"></span></div>
  98.     </div>
  99.     <div class="message">
  100.       click/tap and drag to draw
  101.     </div>
  102.  
  103.     <script>
  104.       (() => { 
  105.         // no scrolling on mobile
  106.         document.addEventListener('touchmove', e => e.preventDefault(), {
  107.           passive: false
  108.         });
  109.  
  110.         function touchify(e) {
  111.           const touch = [];
  112.           touch.x = touch.y = 0;
  113.  
  114.           if (e.touches != null && e.touches.length > 0) {
  115.             touch.x = e.touches[0].clientX;
  116.             touch.y = e.touches[0].clientY;
  117.             for (let i = 0; i < e.touches.length; i++) {
  118.               touch[i] = e.touches[i];
  119.             }
  120.           } else {
  121.             touch.x = e.clientX;
  122.             touch.y = e.clientY;
  123.             touch[0] = { clientX: e.clientX, clientY: e.clientY };
  124.           }
  125.           return touch;
  126.         }
  127.  
  128.         const els = {};
  129.  
  130.         [...document.querySelectorAll('[class]')].forEach(el => {
  131.           els[el.classList[0]] = el;
  132.         });
  133.  
  134.         const { paper, pencil, color, brush, message } = els;
  135.  
  136.         let lastSelected = pencil;
  137.         let strokeWidth = 1;
  138.         let downCount;
  139.         let down;
  140.         let currPath;
  141.         let pathPoints;
  142.  
  143.         const onDown = e => {
  144.           down = true;
  145.           downCount = 0;
  146.           pathPoints = [];
  147.         };
  148.  
  149.         const onMove = e => {
  150.           const touch = touchify(e);
  151.  
  152.           if (down) {
  153.             downCount++;
  154.  
  155.             if (downCount === 1) {
  156.               currPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
  157.               currPath.setAttribute('stroke', color.value);
  158.               currPath.setAttribute('stroke-width', strokeWidth);
  159.               currPath.setAttribute('d', `M ${touch.x} ${touch.y}`);
  160.               pathPoints.push([touch.x, touch.y]);
  161.               paper.appendChild(currPath);
  162.             } else {
  163.               let path = `M ${pathPoints[0][0]} ${pathPoints[0][1]} L `;
  164.               pathPoints.push([touch.x, touch.y]);
  165.               for (let i = 1; i < pathPoints.length; i++) {
  166.                 path += `${pathPoints[i][0]} ${pathPoints[i][1]} `;
  167.               }
  168.               currPath.setAttribute('d', path);
  169.             }
  170.  
  171.             if (downCount === 10) {
  172.               message.classList.add('hide');
  173.             }
  174.           }
  175.         };
  176.  
  177.         const onUp = e => {
  178.           down = false;
  179.         };
  180.  
  181.         const onClick = e => {
  182.           if (e.target.classList.contains('pencil')) {
  183.             strokeWidth = 1;
  184.           } else if (e.target.classList.contains('brush')) {
  185.             strokeWidth = 10;
  186.           }
  187.           if (e.target.classList.contains('icon')) {
  188.             if (lastSelected) lastSelected.classList.remove('selected');
  189.             e.target.classList.add('selected');
  190.             lastSelected = e.target;
  191.           }
  192.         };
  193.  
  194.         document.addEventListener('mousedown', onDown);
  195.         document.addEventListener('touchstart', onDown);
  196.  
  197.         document.addEventListener('mousemove', onMove);
  198.         document.addEventListener('touchmove', onMove);
  199.  
  200.         document.addEventListener('mouseup', onUp);
  201.         document.addEventListener('touchend', onUp);
  202.  
  203.         document.addEventListener('click', onClick);
  204.         document.addEventListener('touchend', onClick);
  205.       })();
  206.     </script>
  207.   </body>
  208. </html>

SVG based drawing program.

// css // javascript // svg // ui
snippet.zone ~ 2021-24 /// {s/z}