AbdulElahGwaith's picture
Upload folder using huggingface_hub
6202252 verified
// @ts-check
// This script is run within the webview itself
(function () {
// @ts-ignore
const vscode = acquireVsCodeApi();
/**
* A drawn line.
*/
class Stroke {
constructor(/** @type {string} */ color, /** @type {Array<[number, number]> | undefined} */ stroke) {
this.color = color;
/** @type {Array<[number, number]>} */
this.stroke = stroke || [];
}
addPoint(/** @type {number} */ x, /** @type {number} */ y) {
this.stroke.push([x, y])
}
}
/**
* @param {Uint8Array} initialContent
* @return {Promise<HTMLImageElement>}
*/
async function loadImageFromData(initialContent) {
const blob = new Blob([initialContent], { 'type': 'image/png' });
const url = URL.createObjectURL(blob);
try {
const img = document.createElement('img');
img.crossOrigin = 'anonymous';
img.src = url;
await new Promise((resolve, reject) => {
img.onload = resolve;
img.onerror = reject;
});
return img;
} finally {
URL.revokeObjectURL(url);
}
}
class PawDrawEditor {
constructor( /** @type {HTMLElement} */ parent) {
this.ready = false;
this.editable = false;
this.drawingColor = 'black';
/** @type {Array<Stroke>} */
this.strokes = [];
/** @type {Stroke | undefined} */
this.currentStroke = undefined;
this._initElements(parent);
}
addPoint(/** @type {number} */ x, /** @type {number} */ y) {
if (this.currentStroke) {
this.currentStroke.addPoint(x, y)
}
}
beginStoke(/** @type {string} */ color) {
this.currentStroke = new Stroke(color);
this.strokes.push(this.currentStroke);
}
endStroke() {
const previous = this.currentStroke;
this.currentStroke = undefined;
return previous;
}
setEditable(editable) {
this.editable = editable;
const colorButtons = /** @type {NodeListOf<HTMLButtonElement>} */ (document.querySelectorAll('.drawing-controls button'));
for (const colorButton of colorButtons) {
colorButton.disabled = !editable;
}
}
_initElements(/** @type {HTMLElement} */ parent) {
const colorButtons = /** @type {NodeListOf<HTMLButtonElement>} */ (document.querySelectorAll('.drawing-controls button'));
for (const colorButton of colorButtons) {
colorButton.addEventListener('click', e => {
e.stopPropagation();
colorButtons.forEach(button => button.classList.remove('active'));
colorButton.classList.add('active');
this.drawingColor = colorButton.dataset['color'];
});
}
this.wrapper = document.createElement('div');
this.wrapper.style.position = 'relative';
parent.append(this.wrapper);
this.initialCanvas = document.createElement('canvas');
this.initialCtx = this.initialCanvas.getContext('2d');
this.wrapper.append(this.initialCanvas);
this.drawingCanvas = document.createElement('canvas');
this.drawingCanvas.style.position = 'absolute';
this.drawingCanvas.style.top = '0';
this.drawingCanvas.style.left = '0';
this.drawingCtx = this.drawingCanvas.getContext('2d');
this.wrapper.append(this.drawingCanvas);
let isDrawing = false;
parent.addEventListener('mousedown', () => {
if (!this.ready || !this.editable) {
return;
}
this.beginStoke(this.drawingColor);
this.drawingCtx.strokeStyle = this.drawingColor;
isDrawing = true;
document.body.classList.add('isDrawing');
this.drawingCtx.beginPath();
});
document.body.addEventListener('mouseup', async () => {
if (!isDrawing || !this.ready || !this.editable) {
return;
}
isDrawing = false;
document.body.classList.remove('isDrawing');
this.drawingCtx.closePath();
const edit = this.endStroke();
if (edit.stroke.length) {
vscode.postMessage({
type: 'stroke',
color: edit.color,
stroke: edit.stroke,
});
}
});
parent.addEventListener('mousemove', e => {
if (!isDrawing || !this.ready || !this.editable) {
return;
}
const rect = this.wrapper.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
this.drawingCtx.lineTo(x, y);
this.drawingCtx.stroke();
this.addPoint(x, y);
});
}
_redraw() {
this.drawingCtx.clearRect(0, 0, this.drawingCanvas.width, this.drawingCanvas.height);
for (const stroke of this.strokes) {
this.drawingCtx.strokeStyle = stroke.color;
this.drawingCtx.beginPath();
for (const [x, y] of stroke.stroke) {
this.drawingCtx.lineTo(x, y);
}
this.drawingCtx.stroke();
this.drawingCtx.closePath();
}
}
/**
* @param {Uint8Array | undefined} data
* @param {Array<Stroke> | undefined} strokes
*/
async reset(data, strokes = []) {
if (data) {
const img = await loadImageFromData(data);
this.initialCanvas.width = this.drawingCanvas.width = img.naturalWidth;
this.initialCanvas.height = this.drawingCanvas.height = img.naturalHeight;
this.initialCtx.drawImage(img, 0, 0);
this.ready = true;
}
this.strokes = strokes;
this._redraw();
}
/**
* @param {Array<Stroke> | undefined} strokes
*/
async resetUntitled(strokes = []) {
const size = 100;
this.initialCanvas.width = this.drawingCanvas.width = size;
this.initialCanvas.height = this.drawingCanvas.height = size;
this.initialCtx.save();
{
this.initialCtx.fillStyle = 'white';
this.initialCtx.fillRect(0, 0, size, size);
}
this.initialCtx.restore();
this.ready = true;
this.strokes = strokes;
this._redraw();
}
/** @return {Promise<Uint8Array>} */
async getImageData() {
const outCanvas = document.createElement('canvas');
outCanvas.width = this.drawingCanvas.width;
outCanvas.height = this.drawingCanvas.height;
const outCtx = outCanvas.getContext('2d');
outCtx.drawImage(this.initialCanvas, 0, 0);
outCtx.drawImage(this.drawingCanvas, 0, 0);
const blob = await new Promise(resolve => {
outCanvas.toBlob(resolve, 'image/png')
});
return new Uint8Array(await blob.arrayBuffer());
}
}
const editor = new PawDrawEditor(document.querySelector('.drawing-canvas'));
// Handle messages from the extension
window.addEventListener('message', async e => {
const { type, body, requestId } = e.data;
switch (type) {
case 'init':
{
editor.setEditable(body.editable);
if (body.untitled) {
await editor.resetUntitled();
return;
} else {
// Load the initial image into the canvas.
await editor.reset(body.value);
return;
}
}
case 'update':
{
const strokes = body.edits.map(edit => new Stroke(edit.color, edit.stroke));
await editor.reset(body.content, strokes)
return;
}
case 'getFileData':
{
// Get the image data for the canvas and post it back to the extension.
editor.getImageData().then(data => {
vscode.postMessage({ type: 'response', requestId, body: Array.from(data) });
});
return;
}
}
});
// Signal to VS Code that the webview is initialized.
vscode.postMessage({ type: 'ready' });
}());