CanvasEdit

Create a new drawing canvasEdit

// Create a canvas almost the entire visible area
var xw = window.innerWidth;
var yw = window.innerHeight
var canvas = document.createElement('canvas');
canvas.id = "canvas";
canvas.width = (xw - 20);
canvas.height = (yw - 20);
canvas.style.zIndex = 8;
canvas.style.position = "absolute";
canvas.style.border = "1px solid";
var body = document.getElementsByTagName("body")[0];
body.appendChild(canvas);
cursorLayer = document.getElementById("CursorLayer");
// ------->

Setup 2D drawing for the canvasEdit

// Get canvas related references
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var BB=canvas.getBoundingClientRect();
var offsetX=BB.left;
var offsetY=BB.top;
var WIDTH = canvas.width;
var HEIGHT = canvas.height;

Code listing for canvas program. This is in an iframe in index.htmlEdit

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<style>
body{ background-color: ivory; }
#canvas{border:1px solid red;}
</style>

<script>
// setup canvas
var xw = window.innerWidth;
var yw = window.innerHeight
var canvas = document.createElement('canvas');
canvas.id = "canvas";
canvas.width = (xw - 20);
canvas.height = (yw - 20);
canvas.style.zIndex = 8;
canvas.style.position = "absolute";
canvas.style.border = "1px solid";
var body = document.getElementsByTagName("body")[0];
body.appendChild(canvas);
cursorLayer = document.getElementById("CursorLayer");
// get canvas related references
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var BB=canvas.getBoundingClientRect();
var offsetX=BB.left;
var offsetY=BB.top;
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
// drag related variables
var dragok = false;
var startX;
var startY;
// an array of objects that define different shapes
var shapes=[];
// load the array from the server
load();
// add new text from button
function addText(){
 shapes.push({x:40,y:200,ts:"text box"});
 draw();
};
// add new rectangle from button
function addRect(){
 shapes.push({x:10,y:10,width:30,height:30,fill:"#444444",isDragging:false});
 draw();
};
// add new circle from button
function addCircle(){
 shapes.push({x:150,y:100,r:10,fill:"#800080",isDragging:false});
 draw();
};
// listen for mouse events
canvas.onmousedown = myDown;
canvas.onmouseup = myUp;
canvas.onmousemove = myMove;
// generic alert for debugging
function alertme(){
  alert('yes');
};
// draw a single text
function txt(t) {
  ctx.font = "16px Arial";
  ctx.fillText(t.ts,t.x, t.y);
}
// draw a single rect
function rect(r) {
  ctx.fillStyle=r.fill;
  ctx.fillRect(r.x,r.y,r.width,r.height);
}
// draw a single rect
function circle(c) {
  ctx.fillStyle=c.fill;
  ctx.beginPath();
  ctx.arc(c.x,c.y,c.r,0,Math.PI*2);
  ctx.closePath();
  ctx.fill();
}
// clear the canvas
function clear() {
  ctx.clearRect(0, 0, WIDTH, HEIGHT);
}
// redraw the scene
function draw() {
  clear();
  // redraw each shape in the shapes[] array
  for(var i=0;i<shapes.length;i++){
    // decide item type
    if(shapes[i].width){
      rect(shapes[i]);
    }else if (shapes[i].ts) {
      txt(shapes[i]);
    }else{
      circle(shapes[i]);
    };
  }
}
// handle mousedown events
function myDown(e){
  // tell the browser we're handling this mouse event
  e.preventDefault();
  e.stopPropagation();
  // get the current mouse position
  var mx=parseInt(e.clientX-offsetX);
  var my=parseInt(e.clientY-offsetY);
  // test each shape to see if mouse is inside
  dragok=false;
  for(var i=0;i<shapes.length;i++){
    var s=shapes[i];
    // decide if the shape is a rect or circle               
    if(s.width){
      // test if the mouse is inside this rect
      if(mx>s.x && mx<s.x+s.width && my>s.y && my<s.y+s.height){
        // if yes, set that rects isDragging=true
        dragok=true;
        s.isDragging=true;
      }
    } else if (s.ts) {
      // text move
      if(mx>s.x-10 && mx<s.x+10 && my>s.y-10 && my<s.y+10){
        dragok=true;
        s.isDragging=true;
      }  
    }else {
      var dx=s.x-mx;
      var dy=s.y-my;
      // test if the mouse is inside this circle
      if(dx*dx+dy*dy<s.r*s.r){
        dragok=true;
        s.isDragging=true;
      }
    }
  }
  // save the current mouse position
  startX=mx;
  startY=my;
}

// handle mouseup events
function myUp(e){
  // tell the browser we're handling this mouse event
  e.preventDefault();
  e.stopPropagation();
  // clear all the dragging flags
  dragok = false;
  for(var i=0;i<shapes.length;i++){
    shapes[i].isDragging=false;
  }
  // save the new positions
  save();
}

// handle mouse moves
function myMove(e){
  // if we're dragging anything...
  if (dragok){
    // tell the browser we're handling this mouse event
    e.preventDefault();
    e.stopPropagation();
    // get the current mouse position
    var mx=parseInt(e.clientX-offsetX);
    var my=parseInt(e.clientY-offsetY);
    // calculate the distance the mouse has moved since the last mousemove
    var dx=mx-startX;
    var dy=my-startY;
    // move each rect that isDragging by the distance the mouse has moved since the last mousemove
    for(var i=0;i<shapes.length;i++){
      var s=shapes[i];
      if(s.isDragging){
        s.x+=dx;
        s.y+=dy;
      }
    }
    // redraw the scene with the new rect positions
    draw();
    // reset the starting mouse position for the next mousemove
    startX=mx;
    startY=my;
  }
}

function save(){
  var shapes_serialized = JSON.stringify(shapes);
  // then write it to disk
  var data = new FormData();
  data.append("data" , shapes_serialized);
  var xhr = (window.XMLHttpRequest) ? new XMLHttpRequest() : new activeXObject("Microsoft.XMLHTTP");
  xhr.open( 'post', './upload.php', true );
  xhr.send(data);
};

function load(){
  // get the file from the disk
  var url = "./upload/marker.txt";
  var jsonFile = new XMLHttpRequest();
  jsonFile.open("GET",url,true);
  jsonFile.send();
  jsonFile.onreadystatechange = function() {
    if (jsonFile.readyState== 4 && jsonFile.status == 200) {
      var shapes_serialized = jsonFile.responseText;
      console.log(shapes_serialized);
      shapes = JSON.parse(shapes_serialized);
      draw();
      }
  }
};
</script> 
</body>
</html>

PHP helper function for load/save (should be in same directory as above). There should be a subdirectory 'upload' also in the same directory.Edit

<?php
  if(!empty($_POST['data'])){
  $data = $_POST['data'];
  $fname = "marker.txt";
  $file = fopen("./upload/" .$fname, 'w');
  fwrite($file, $data);
  fclose($file);
  }
?>

index.html with iframe of size and buttonsEdit

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    html, body {
      height: 100%;
    }
    #heading {
      height: 25px;
    }
    #canvas {
      height: calc(100vh - 50px);
    }
    iframe {
      height: 99%;
      width:99%;
    }
  </style>
</head>
<body>
  <div class="container">
    <div id="heading">
    <script>
      const button = document.createElement('button');
      button.innerText = 'Add rectangle';
      button.id = 'addRectButton';
      // Attach the "click" event to your button
      button.addEventListener('click', () => {
        document.getElementById('canvasFrame').contentWindow.addRect();
      });
      heading.appendChild(button);

      const circleButton = document.createElement('button');
      circleButton.innerText = 'Add circle';
      circleButton.id = 'addCircleButton';
      // Attach the "click" event to your button
      circleButton.addEventListener('click', () => {
        document.getElementById('canvasFrame').contentWindow.addCircle();
      });
      heading.appendChild(circleButton);

      const textButton = document.createElement('button');
      textButton.innerText = 'Add text';
      textButton.id = 'addTextButton';
      // Attach the "click" event to your button
      textButton.addEventListener('click', () => {
        document.getElementById('canvasFrame').contentWindow.addText();
      });
      heading.appendChild(textButton);
    </script>
  </div>
  <div id="canvas">
      <iframe src="./j2.html" id="canvasFrame"></iframe>
    </div>
  </div>
</body>
</html>