let pixel_per_cm = 1, img, monitors = []; let canvas = document.getElementById("canvas"), global_width_cm = document.getElementById("global_width_cm"), global_height_cm = document.getElementById("global_height_cm"), img_width_cm = document.getElementById("img_width_cm"), img_height_cm = document.getElementById("img_height_cm"), img_offset_top = document.getElementById("img_offset_top"), img_offset_left = document.getElementById("img_offset_left"), img_upload = document.getElementById("img_upload"); canvas.getContext("2d").fillRect(0, 0, canvas.width, canvas.height); const update_hash = () => { location.hash = global_width_cm.value + "x" + global_height_cm.value; for (let monitor of monitors) { location.hash += "," + monitor.aspect_ratio.value + "/" + monitor.diagonal_cm.value + "/" + monitor.offset_top_cm.value + "/" + monitor.offset_left_cm.value } }; const redraw = () => { canvas.width = global_width_cm.value * pixel_per_cm; canvas.height = global_height_cm.value * pixel_per_cm; let ctx = canvas.getContext("2d"); ctx.fillRect(0, 0, canvas.width, canvas.height); if (img) { ctx.drawImage( img, img_offset_left.value * pixel_per_cm, img_offset_top.value * pixel_per_cm, img_width_cm.value * pixel_per_cm, img_height_cm.value * pixel_per_cm ); } for (let monitor of monitors) monitor.redraw(); }; const round_to_float = (x) => { return Math.round(x * 10) / 10; }; const upload_image = (e) => { let reader = new FileReader(), f = e.target.files.item(0); reader.onload = (e) => { let new_img = new Image(); new_img.setAttribute("src", e.target.result.toString()); new_img.addEventListener("load", () => { img = new_img; if ((img.width / img.height < global_width_cm.value / global_height_cm.value)) { // image is wider img_width_cm.value = global_width_cm.value; img_height_cm.value = round_to_float(img.height / img.width * img_width_cm.value); img_offset_left.value = 0; img_offset_top.value = round_to_float((global_height_cm.value - img_height_cm.value) / 2); } else { // canvas is wider img_height_cm.value = global_height_cm.value; img_width_cm.value = round_to_float(img.width / img.height * img_height_cm.value); img_offset_top.value = 0; img_offset_left.value = round_to_float((global_width_cm.value - img_width_cm.value) / 2); } pixel_per_cm = new_img.width / img_width_cm.value; redraw(); }); }; reader.readAsDataURL(f); }; img_upload.addEventListener("change", upload_image); global_width_cm.addEventListener("input", () => { redraw(); update_hash(); }); global_height_cm.addEventListener("input", () => { redraw(); update_hash(); }); img_width_cm.addEventListener("input", () => { img_height_cm.value = round_to_float(img.height / img.width * img_width_cm.value); redraw(); }); img_height_cm.addEventListener("input", () => { img_width_cm.value = round_to_float(img.width / img.height * img_height_cm.value); redraw(); }); img_offset_top.addEventListener("input", redraw); img_offset_left.addEventListener("input", redraw); let add_monitor_button = document.getElementById("add_monitor_button"), monitor_setings_template = document.getElementById("monitor_settings_template"), monitors_column = document.getElementById("monitors_column"), monitor_images = document.getElementById("monitor_images"); const add_monitor = () => { let monitor_id = monitors.length + 1; let settings_clone = document.importNode(monitor_setings_template.content, true); let monitor_canvas = document.createElement("canvas"); monitor_canvas.style.position = "absolute"; monitor_canvas.style.top = "0"; monitor_canvas.style.left = "0"; monitor_canvas.draggable = true; monitor_canvas.style.outline = "2px solid grey"; let aspect_ratio = settings_clone.querySelector('[name="aspect_ratio"]'), diagonal_cm = settings_clone.querySelector('[name="diagonal_cm"]'), offset_top_cm = settings_clone.querySelector('[name="offset_top_cm"]'), offset_left_cm = settings_clone.querySelector('[name="offset_left_cm"]'), get_image_button = settings_clone.querySelector('[name="get_image_button"]'); settings_clone.querySelector('h2').innerText += ' ' + monitor_id; let redraw_monitor = () => { let [width, height] = aspect_ratio.value.split(":"); let alpha = Math.atan2(height, width); let width_cm = diagonal_cm.value * Math.cos(alpha), height_cm = diagonal_cm.value * Math.sin(alpha); let width_percent = round_to_float(100 * width_cm / global_width_cm.value), height_percent = round_to_float(100 * height_cm / global_height_cm.value), offset_top_percent = round_to_float(100 * offset_top_cm.value / global_height_cm.value), offset_left_percent = round_to_float(100 * offset_left_cm.value / global_width_cm.value); monitor_canvas.width = width_cm * pixel_per_cm; monitor_canvas.height = height_cm * pixel_per_cm; monitor_canvas.getContext("2d").drawImage( canvas, offset_left_cm.value * pixel_per_cm, offset_top_cm.value * pixel_per_cm, width_cm * pixel_per_cm, height_cm * pixel_per_cm, 0, 0, monitor_canvas.width, monitor_canvas.height ); monitor_canvas.style.width = width_percent + "%"; monitor_canvas.style.height = height_percent + "%"; monitor_canvas.style.top = offset_top_percent + "%"; monitor_canvas.style.left = offset_left_percent + "%"; }; redraw_monitor(); const input_handler = () => { redraw_monitor(); update_hash(); }; aspect_ratio.addEventListener('change', input_handler); diagonal_cm.addEventListener('input', input_handler); offset_top_cm.addEventListener('input', input_handler); offset_left_cm.addEventListener('input', input_handler); get_image_button.addEventListener('click', () => { console.log(monitor_canvas.toDataURL()); let temp_a = document.createElement('a'); temp_a.setAttribute('href', monitor_canvas.toDataURL()); temp_a.setAttribute('download', 'monitor_' + monitor_id + '.png'); temp_a.style.display = 'none'; document.body.appendChild(temp_a); temp_a.click(); document.body.removeChild(temp_a); }); let current_monitor = { aspect_ratio: aspect_ratio, diagonal_cm: diagonal_cm, offset_top_cm: offset_top_cm, offset_left_cm: offset_left_cm, canvas: monitor_canvas, redraw: redraw_monitor, }; monitors.push(current_monitor); monitors_column.appendChild(settings_clone); monitor_images.appendChild(monitor_canvas); return current_monitor; }; add_monitor_button.addEventListener("click", add_monitor); if (location.hash !== "") { let [global_hash, ...monitor_hashes] = location.hash.substr(1).split(","); [global_width_cm.value, global_height_cm.value] = global_hash.split("x"); for (let monitor_hash of monitor_hashes) { let monitor = add_monitor(); [monitor.aspect_ratio.value, monitor.diagonal_cm.value, monitor.offset_top_cm.value, monitor.offset_left_cm.value] = monitor_hash.split("/"); } redraw(); }