style: added documentation with JSDoc and html comments

This commit is contained in:
Orangerot 2025-01-13 09:37:14 +01:00
parent e33747e7b3
commit 13944b526f
3 changed files with 70 additions and 5 deletions

View file

@ -13,11 +13,16 @@
<title>Imagine - Image Editor</title> <title>Imagine - Image Editor</title>
</head> </head>
<body class="import-active"> <body class="import-active">
<!--
body classes allow for switching between the three views:
import-active, camera-active and editor-active
-->
<div class="navbar columns is-mobile is-fixed-top"> <div class="navbar columns is-mobile is-fixed-top">
<div class="column" id="viewport"> <div class="column" id="viewport">
<div class="hero is-fullheight"> <div class="hero is-fullheight">
<div class="hero-body"> <div class="hero-body">
<div class="container" > <div class="container" >
<!-- viewport that contains canvas/video/import buttons -->
<canvas id="myCanvas" class="is-visible-editor" width="300" height="300"></canvas> <canvas id="myCanvas" class="is-visible-editor" width="300" height="300"></canvas>
<video id="video" class="is-visible-camera" width="300" height="300"></video> <video id="video" class="is-visible-camera" width="300" height="300"></video>
<div class="container has-text-centered mb-6 is-visible-import"> <div class="container has-text-centered mb-6 is-visible-import">
@ -43,7 +48,8 @@
</label> </label>
</div> </div>
</div> </div>
</div><br> </div>
<!-- buttons inside of the viewport -->
<a id="settings-button" href="#settings" class="button is-hidden-desktop is-visible-editor"> <a id="settings-button" href="#settings" class="button is-hidden-desktop is-visible-editor">
<i class="fa-solid fa-sliders mr-2"></i> Settings <i class="fa-solid fa-sliders mr-2"></i> Settings
</a> </a>
@ -56,6 +62,7 @@
</div> </div>
</div> </div>
</div> </div>
<!-- settings menu for desktop use -->
<div class="column is-narrow has-background-black-ter is-hidden-mobile is-hidden-tablet-only is-visible-editor"> <div class="column is-narrow has-background-black-ter is-hidden-mobile is-hidden-tablet-only is-visible-editor">
<aside class="menu mr-3"> <aside class="menu mr-3">
<h1 class="title">Imagine</h1> <h1 class="title">Imagine</h1>
@ -214,6 +221,7 @@
</aside> </aside>
</div> </div>
</div> </div>
<!-- settings menu for mobile use -->
<div id="settings" class="notification is-fullwidth is-hidden-desktop is-visible-editor"> <div id="settings" class="notification is-fullwidth is-hidden-desktop is-visible-editor">
<!-- #settings is an anhor to scroll to when clicked on the settings-button --> <!-- #settings is an anhor to scroll to when clicked on the settings-button -->
<!-- #top is an anchor provided by the browser to go to the top of the page --> <!-- #top is an anchor provided by the browser to go to the top of the page -->

63
main.js
View file

@ -1,11 +1,15 @@
let canvas; let canvas;
let video; let video;
let ctx; let ctx;
/*
* theses settings correspond to a css-filter. you can specify an optional
* filter attribute to modify the value from the input element.
*/
let settings = { let settings = {
"brightness": {}, "brightness": {},
"saturate": {}, "saturate": {},
"contrast": {}, "contrast": {},
"hue-rotate": {filter: value => value + "deg"}, "hue-rotate": { filter: value => value + "deg" },
"grayscale": {}, "grayscale": {},
"sepia": {}, "sepia": {},
"invert": {}, "invert": {},
@ -111,6 +115,11 @@ document.addEventListener("DOMContentLoaded", function() {
} }
}); });
/**
* Reset all inputs of a setting back to the default value
*
* @param {string} setting - key of the settings object to reset
*/
function reset_all(setting) { function reset_all(setting) {
console.log("reseting " + setting); console.log("reseting " + setting);
for (let element of settings[setting].elements) { for (let element of settings[setting].elements) {
@ -119,6 +128,10 @@ function reset_all(setting) {
draw(true); draw(true);
} }
/**
* Request camera access and on succhess, show camera feed on video-element and
* switch to camera-active view
*/
function use_camera() { function use_camera() {
navigator.mediaDevices navigator.mediaDevices
.getUserMedia({ video: true, audio: false }) .getUserMedia({ video: true, audio: false })
@ -132,6 +145,10 @@ function use_camera() {
}); });
} }
/**
* Take a still frame of the video-element showing the camera-feed and load it
* to the img to be rendered by canvas and switch to editor-active view
*/
function take_picture() { function take_picture() {
canvas.width = video.width; canvas.width = video.width;
canvas.height = video.height; canvas.height = video.height;
@ -142,6 +159,10 @@ function take_picture() {
document.body.className = "editor-active"; document.body.className = "editor-active";
} }
/**
* Load selected file by input element to img to be rendered by canvas and
* switch to editor-active view
*/
function upload_image() { function upload_image() {
document.body.className = "editor-active"; document.body.className = "editor-active";
@ -151,7 +172,14 @@ function upload_image() {
img.onload = () => draw(true); img.onload = () => draw(true);
} }
// https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/File_drag_and_drop /**
* Get file that is dropped into the website and load it to img to be rendered
* by canvas and switch to editor-active view.
*
* @param {DragEvent} ev -supplier by event listener
*
* https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/File_drag_and_drop
*/
function drop_handler(ev) { function drop_handler(ev) {
ev.preventDefault(); ev.preventDefault();
let file; let file;
@ -170,6 +198,12 @@ function drop_handler(ev) {
img.onload = () => draw(true); img.onload = () => draw(true);
} }
/**
* Creates a download of the edited image in full resolution by creating a link
* and virtually clicking it.
*
* @param {PointerEvent} event - supplied by event listener
*/
function save_image(event) { function save_image(event) {
event.preventDefault(); event.preventDefault();
draw(false); draw(false);
@ -182,6 +216,11 @@ function save_image(event) {
link.click(); link.click();
} }
/**
* Uses the navigator.share API to share the edited image in full reslution.
*
* @param {PointerEvent} event - supplied by event listener
*/
function share_image(event) { function share_image(event) {
event.preventDefault(); event.preventDefault();
if (!navigator.share) { if (!navigator.share) {
@ -201,6 +240,11 @@ function share_image(event) {
}, 'image/png'); }, 'image/png');
} }
/**
* Set all inputs of a setting to the value of the input that changed it.
*
* @param {Event} event - supplied by event listener
*/
function settings_apply(event) { function settings_apply(event) {
const changed_setting = event.target.id; const changed_setting = event.target.id;
const new_value = event.target.value; const new_value = event.target.value;
@ -214,7 +258,13 @@ function settings_apply(event) {
draw(true); draw(true);
} }
// https://www.shadertoy.com/view/ldSXWK /**
* Render a lensflare shader for every pixel on the canvas.
*
* @param {number} pos_x - x position of the lensflare in the range [-0.5,0.5]
* @param {number} pos_y - y position of the lensflare in the range [-0.5,0.5]
* https://www.shadertoy.com/view/ldSXWK
*/
function lensflare(pos_x, pos_y) { function lensflare(pos_x, pos_y) {
const imgdata = ctx.getImageData(0, 0, canvas.width, canvas.height); const imgdata = ctx.getImageData(0, 0, canvas.width, canvas.height);
const pixel_count = imgdata.data.length / 4; const pixel_count = imgdata.data.length / 4;
@ -276,6 +326,13 @@ function lensflare(pos_x, pos_y) {
ctx.putImageData(imgdata, 0, 0); ctx.putImageData(imgdata, 0, 0);
} }
/**
* Amply filters and lensflare to the optionally scaled image, to only
* calculate on pixels the user can see.
*
* @param {bool} viewport_scale - render image scaled to viewport or in full
* resolution
*/
function draw(viewport_scale) { function draw(viewport_scale) {
const filter = Object.entries(settings) const filter = Object.entries(settings)
.map(([setting, { elements, filter }]) => `${setting}(${filter(elements[0].value)})`) .map(([setting, { elements, filter }]) => `${setting}(${filter(elements[0].value)})`)

View file

@ -1,4 +1,4 @@
html, body { body {
margin: 0px; margin: 0px;
scroll-behavior: smooth; scroll-behavior: smooth;
padding-top: 100dvh; padding-top: 100dvh;