diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..496ee2c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store \ No newline at end of file diff --git a/assets/ico/download.svg b/assets/ico/download.svg new file mode 100644 index 0000000..175ef3b --- /dev/null +++ b/assets/ico/download.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/index.html b/index.html index ce2da4f..dcc4e70 100644 --- a/index.html +++ b/index.html @@ -17,14 +17,16 @@
- -
- -
- +
+ + +
+ diff --git a/script.js b/script.js index 407e8a5..410153f 100644 --- a/script.js +++ b/script.js @@ -1,3 +1,144 @@ +const buttonDownload = document.getElementById("download"); +buttonDownload.addEventListener("click", downloadOptions); + +function download(name, format) { + // get width and height and background color - original draw + const canvas = document.getElementById("black-board"); + const width = canvas.width; + const height = canvas.height; + + let boardBackground; + + const background = canvas.style.backgroundColor; + boardBackground = background; + + if (!background) { + boardBackground = "rgba(255,255,255)"; + } + + // generate a new canvas with background + const backgroundCanvasGenerate = document.createElement("canvas"); + backgroundCanvasGenerate.width = width; + backgroundCanvasGenerate.height = height; + const ctx2 = backgroundCanvasGenerate.getContext("2d"); + ctx2.fillStyle = boardBackground; + ctx2.fillRect(0, 0, width, height); + + // merge background with draw + const canvas3 = document.createElement("canvas"); + canvas3.width = width; + canvas3.height = height; + const ctx3 = canvas3.getContext("2d"); + + ctx3.drawImage(backgroundCanvasGenerate, 0, 0); + ctx3.drawImage(canvas, 0, 0); + + const newCanvas = canvas3.toDataURL(); + + fetch(newCanvas) + .then((resp) => resp.blob()) + .then((blobobject) => { + const blob = window.URL.createObjectURL(blobobject); + const anchor = document.createElement("a"); + anchor.style.display = "none"; + anchor.href = blob; + anchor.download = `${name}.${format}`; + document.body.appendChild(anchor); + anchor.click(); + window.URL.revokeObjectURL(blob); + + document.getElementById("modal").remove(); + }); +} + +function downloadOptions() { + const modal = document.createElement("div"); + modal.classList.add("modal"); + modal.setAttribute("id", "modal"); + + const content = document.createElement("div"); + content.classList.add("modal-content"); + modal.appendChild(content); + + const labelInput = document.createElement("div"); + + labelInput.classList.add("label-input"); + + const label = document.createElement("label"); + label.appendChild(document.createTextNode("File Name")); + labelInput.appendChild(label); + + const inputName = document.createElement("input"); + inputName.addEventListener("keydown", () => { + const error = inputName.classList.contains("error"); + if (error) { + inputName.classList.remove("error"); + } + }); + inputName.classList.add("input-name"); + labelInput.appendChild(inputName); + + content.appendChild(labelInput); + + const formats = ["png", "jpeg"]; + + const listFormats = document.createElement("div"); + listFormats.classList.add("download-list-formats"); + content.appendChild(listFormats); + + formats.map((format) => { + const label = document.createElement("label"); + label.classList.add("download-format-control"); + + const input = document.createElement("input"); + if (format == "png") { + input.checked = true; + } + input.setAttribute("type", "radio"); + input.setAttribute("name", "radio"); + input.setAttribute("value", format); + label.appendChild(document.createTextNode(format)); + label.appendChild(input); + + listFormats.appendChild(label); + }); + + const downloadCancel = document.createElement("div"); + downloadCancel.classList.add("download-cancel"); + + const btnDownload = document.createElement("button"); + btnDownload.addEventListener("click", () => { + let nameFile = inputName.value; + + if (!nameFile) { + inputName.classList.add("error"); + return; + } + + nameFile = nameFile.replace(/\s+/g, "-").toLowerCase(); + + const format = document.querySelector('input[name="radio"]:checked').value; + + download(nameFile, format); + }); + + btnDownload.classList.add("btn-download"); + btnDownload.appendChild(document.createTextNode("Download")); + downloadCancel.appendChild(btnDownload); + + const btnCancelClose = document.createElement("button"); + btnCancelClose.classList.add("btn-cancel"); + btnCancelClose.addEventListener("click", () => { + modal.remove(); + }); + btnCancelClose.appendChild(document.createTextNode("Cancel")); + downloadCancel.appendChild(btnCancelClose); + + content.appendChild(downloadCancel); + + document.body.appendChild(modal); +} + function blackBoard() { const canvas = document.getElementById("black-board"); const ctx = canvas.getContext("2d"); diff --git a/styles.css b/styles.css index c6e5eb5..b173a18 100644 --- a/styles.css +++ b/styles.css @@ -100,9 +100,216 @@ canvas:active { height: 78vh; cursor: grabbing; } - button { + + .canvas-container button { position: relative; right: -90px; bottom: -180px; } } + +.clear-download-button button { + background: unset; + border: unset; + cursor: pointer; +} + +.clear-download-button .clear { + border: none; + color: white; + padding: 15px 30px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 20px; + background: linear-gradient(to left, purple, rgb(187, 62, 187)); + border-radius: 15px; + width: 100%; +} + +.modal { + position: fixed; + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgb(0, 0, 0); + background-color: rgba(0, 0, 0, 0.4); +} + +.modal-content { + background-color: #fefefe; + padding: 20px; + border: 1px solid #888; + width: 80%; + max-width: 450px; + display: grid; + gap: 2rem; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); +} + +.modal-content .input-name { + padding: 1rem; + border: 2px solid #2c3131; + font-size: 1rem; + font-weight: bold; +} + +.modal-content .input-name:focus { + border: 2px solid #bb3ebb; + outline: none; +} + + +.clear-download-button { + display: flex; + gap: 1rem; + margin-bottom: 2rem; + /* Temporary workaround for responsive issue to be fixed */ +} + +.label-input { + display: grid; + gap: 10px; + font-size: 1.4rem; + font-weight: bold; + line-height: 1.1; + margin-top: 1rem; +} + +.download-list-formats { + display: flex; + align-items: center; + gap: 50px; + +} + +.download-format-control { + font-size: 1.4rem; + font-weight: bold; + line-height: 1.1; + display: flex; + grid-template-columns: 1em auto; + gap: 0.5em; + cursor: pointer; +} + +.download-format-control:focus-within { + color: #bb3ebb; +} + +.download-format-control input[type=radio] { + cursor: pointer; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + margin: 0; + font: inherit; + color: currentColor; + width: 1.15em; + height: 1.15em; + border: 0.15em solid currentColor; + border-radius: 50%; + transform: translateY(-0.075em); + display: grid; + place-content: center; +} + +.download-format-control input[type=radio]::before { + content: ""; + width: 0.65em; + height: 0.65em; + border-radius: 50%; + transform: scale(0); + transition: 120ms transform ease-in-out; + box-shadow: inset 1em 1em #bb3ebb; + background-color: CanvasText; +} + +.download-format-control input[type=radio]:checked::before { + transform: scale(1); +} + +.download-cancel { + display: flex; + margin-top: 1rem; + gap: 2rem; + justify-items: center; + align-items: center; +} + +.download-cancel button { + cursor: pointer; + border: none; + font-size: 20px; + height: fit-content; +} + +.btn-cancel { + padding: 0; + color: #2c3131; + text-align: center; + display: inline-block; + font-size: 20px; + border-radius: 15px; + background: unset; +} + +.btn-download { + border: none; + color: white; + padding: 15px 30px; + text-align: center; + font-size: 20px; + background: linear-gradient(to left, purple, rgb(187, 62, 187)); + border-radius: 15px; +} + + +.error { + -webkit-animation: shake 0.2s ease-in-out 0s 2; + animation: shake 0.2s ease-in-out 0s 2; + border: 2px solid red !important; +} + +@-webkit-keyframes shake { + 0% { + margin: 0; + } + + 25% { + margin: 0 0.5rem; + } + + + 75% { + margin: 0 -0.5rem; + } + + 100% { + margin: 0; + } +} + +@keyframes shake { + 0% { + margin: 0; + } + + 25% { + margin: 0 0.5rem; + } + + 75% { + margin: 0 -0.5rem; + } + + 100% { + margin: 0; + } +} \ No newline at end of file