Working tree changes 2024-07-30 01:00
All checks were successful
Test project build / Build (push) Successful in 1m10s
All checks were successful
Test project build / Build (push) Successful in 1m10s
This commit is contained in:
parent
17364b48be
commit
319a33084e
112
niimblue/src/image_editor_utils.ts
Normal file
112
niimblue/src/image_editor_utils.ts
Normal file
@ -0,0 +1,112 @@
|
||||
import { fabric } from "fabric";
|
||||
|
||||
export class ImageEditorUtils {
|
||||
static readonly SIZE_DEFAULT: number = 64;
|
||||
static readonly OBJECT_DEFAULTS = {
|
||||
fill: "black",
|
||||
snapAngle: 10,
|
||||
top: 10,
|
||||
left: 10,
|
||||
// objectCaching: false
|
||||
strokeUniform: true,
|
||||
// noScaleCache: true,
|
||||
};
|
||||
|
||||
public static addSvg(canvas: fabric.Canvas, svgCode: string): void {
|
||||
fabric.loadSVGFromString(svgCode, (objects, options) => {
|
||||
const obj = fabric.util.groupSVGElements(objects, options);
|
||||
|
||||
obj.scaleToWidth(this.SIZE_DEFAULT).scaleToHeight(this.SIZE_DEFAULT);
|
||||
obj.set({ ...this.OBJECT_DEFAULTS, top: 0, left: 0 });
|
||||
|
||||
canvas.add(obj).renderAll();
|
||||
canvas.renderAll();
|
||||
});
|
||||
}
|
||||
|
||||
public static addImageFile(canvas: fabric.Canvas, file: File) {
|
||||
const reader = new FileReader();
|
||||
|
||||
if (file.type.startsWith("image/svg")) {
|
||||
reader.readAsText(file, "UTF-8");
|
||||
reader.onload = (readerEvt: ProgressEvent<FileReader>) => {
|
||||
if (readerEvt?.target?.result) {
|
||||
this.addSvg(canvas, readerEvt.target.result as string);
|
||||
}
|
||||
};
|
||||
reader.onerror = (readerEvt: ProgressEvent<FileReader>) => {
|
||||
console.error(readerEvt);
|
||||
};
|
||||
} else if (file.type === "image/png" || file.type === "image/jpeg") {
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = (readerEvt: ProgressEvent<FileReader>) => {
|
||||
if (readerEvt?.target?.result) {
|
||||
fabric.Image.fromURL(readerEvt.target.result as string, (img: fabric.Image) => {
|
||||
img.set({ left: 0, top: 0, snapAngle: 10 });
|
||||
img.scaleToHeight(this.SIZE_DEFAULT).scaleToHeight(this.SIZE_DEFAULT);
|
||||
canvas.add(img);
|
||||
});
|
||||
}
|
||||
};
|
||||
reader.onerror = (readerEvt: ProgressEvent<FileReader>) => {
|
||||
console.error(readerEvt);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static addText(canvas: fabric.Canvas, text?: string): void {
|
||||
const obj = new fabric.IText(text ?? "Text", {
|
||||
...this.OBJECT_DEFAULTS,
|
||||
fontFamily: "Arial",
|
||||
textAlign: "center",
|
||||
originX: "center", //added
|
||||
originY: "center",
|
||||
lineHeight: 1,
|
||||
});
|
||||
canvas.add(obj);
|
||||
obj.center();
|
||||
}
|
||||
|
||||
public static addHLine(canvas: fabric.Canvas): void {
|
||||
const obj = new fabric.Line([10, 10, 10 + this.SIZE_DEFAULT, 10], {
|
||||
...this.OBJECT_DEFAULTS,
|
||||
stroke: "#000",
|
||||
strokeWidth: 3,
|
||||
});
|
||||
obj.setControlsVisibility({
|
||||
tl: false,
|
||||
bl: false,
|
||||
tr: false,
|
||||
br: false,
|
||||
mt: false,
|
||||
mb: false,
|
||||
});
|
||||
canvas.add(obj);
|
||||
obj.centerV();
|
||||
}
|
||||
|
||||
public static addCircle(canvas: fabric.Canvas): void {
|
||||
const obj = new fabric.Circle({
|
||||
...this.OBJECT_DEFAULTS,
|
||||
radius: this.SIZE_DEFAULT / 2,
|
||||
fill: "transparent",
|
||||
stroke: "black",
|
||||
strokeWidth: 3,
|
||||
});
|
||||
canvas.add(obj);
|
||||
obj.centerV();
|
||||
}
|
||||
|
||||
public static addRect(canvas: fabric.Canvas): void {
|
||||
const obj = new fabric.Rect({
|
||||
...this.OBJECT_DEFAULTS,
|
||||
width: this.SIZE_DEFAULT,
|
||||
height: this.SIZE_DEFAULT,
|
||||
fill: "transparent",
|
||||
stroke: "black",
|
||||
strokeWidth: 3,
|
||||
});
|
||||
canvas.add(obj);
|
||||
obj.centerV();
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@
|
||||
import PrintPreview from "./PrintPreview.svelte";
|
||||
import TextParamsPanel from "./TextParamsControls.svelte";
|
||||
import GenericObjectParamsControls from "./GenericObjectParamsControls.svelte";
|
||||
import { ImageEditorUtils } from "../image_editor_utils";
|
||||
|
||||
let htmlCanvas: HTMLCanvasElement;
|
||||
let fabricCanvas: fabric.Canvas;
|
||||
@ -18,18 +19,6 @@
|
||||
let selectedObject: fabric.Object | undefined = undefined;
|
||||
let selectedCount: number = 0;
|
||||
|
||||
const defaultSize = 64;
|
||||
|
||||
const fabricObjectDefaults = {
|
||||
fill: "black",
|
||||
snapAngle: 10,
|
||||
top: 10,
|
||||
left: 10,
|
||||
// objectCaching: false
|
||||
strokeUniform: true,
|
||||
// noScaleCache: true,
|
||||
};
|
||||
|
||||
const deleteSelected = () => {
|
||||
fabricCanvas.getActiveObjects().forEach((obj) => {
|
||||
fabricCanvas.remove(obj);
|
||||
@ -93,64 +82,16 @@
|
||||
|
||||
const onObjectPicked = (name: OjectType) => {
|
||||
if (name === "text") {
|
||||
const obj = new fabric.IText("Text", {
|
||||
...fabricObjectDefaults,
|
||||
fontFamily: "Arial"
|
||||
});
|
||||
fabricCanvas.add(obj);
|
||||
obj.center();
|
||||
ImageEditorUtils.addText(fabricCanvas);
|
||||
} else if (name === "line") {
|
||||
const obj = new fabric.Line([10, 10, 10 + defaultSize, 10], {
|
||||
...fabricObjectDefaults,
|
||||
stroke: "#000",
|
||||
strokeWidth: 3,
|
||||
});
|
||||
obj.setControlsVisibility({
|
||||
tl: false,
|
||||
bl: false,
|
||||
tr: false,
|
||||
br: false,
|
||||
mt: false,
|
||||
mb: false,
|
||||
});
|
||||
fabricCanvas.add(obj);
|
||||
obj.centerV();
|
||||
ImageEditorUtils.addHLine(fabricCanvas);
|
||||
} else if (name === "circle") {
|
||||
const obj = new fabric.Circle({
|
||||
...fabricObjectDefaults,
|
||||
radius: 25,
|
||||
fill: "transparent",
|
||||
stroke: "black",
|
||||
strokeWidth: 3,
|
||||
});
|
||||
fabricCanvas.add(obj);
|
||||
obj.centerV();
|
||||
ImageEditorUtils.addCircle(fabricCanvas);
|
||||
} else if (name === "rectangle") {
|
||||
const obj = new fabric.Rect({
|
||||
...fabricObjectDefaults,
|
||||
width: defaultSize,
|
||||
height: defaultSize,
|
||||
fill: "transparent",
|
||||
stroke: "black",
|
||||
strokeWidth: 3,
|
||||
});
|
||||
fabricCanvas.add(obj);
|
||||
obj.centerV();
|
||||
ImageEditorUtils.addRect(fabricCanvas);
|
||||
}
|
||||
};
|
||||
|
||||
const addSvgXmlToCanvas = (data: string) => {
|
||||
fabric.loadSVGFromString(data, (objects, options) => {
|
||||
const obj = fabric.util.groupSVGElements(objects, options);
|
||||
fabric.Text;
|
||||
obj.scaleToWidth(defaultSize).scaleToHeight(defaultSize);
|
||||
obj.set({ ...fabricObjectDefaults, top: 0, left: 0 });
|
||||
|
||||
fabricCanvas.add(obj).renderAll();
|
||||
fabricCanvas.renderAll();
|
||||
});
|
||||
};
|
||||
|
||||
const onIconPicked = (i: IconName) => {
|
||||
const lookup = faParse.icon(i);
|
||||
const iconData = faIcon(lookup);
|
||||
@ -159,8 +100,7 @@
|
||||
console.error(`Icon ${i} not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
addSvgXmlToCanvas(iconData.html.toString());
|
||||
ImageEditorUtils.addSvg(fabricCanvas, iconData.html.toString());
|
||||
};
|
||||
|
||||
const onPreviewClosed = () => {
|
||||
@ -182,6 +122,9 @@
|
||||
backgroundColor: "#fff",
|
||||
});
|
||||
|
||||
ImageEditorUtils.addText(fabricCanvas);
|
||||
|
||||
|
||||
fabricCanvas.on("object:moving", (e: fabric.IEvent<MouseEvent>) => {
|
||||
const grid = 5;
|
||||
if (e.target && e.target.left !== undefined && e.target.top !== undefined) {
|
||||
@ -213,33 +156,7 @@
|
||||
|
||||
if (dragEvt.dataTransfer?.files) {
|
||||
[...dragEvt.dataTransfer.files].forEach((file: File, idx: number) => {
|
||||
const reader = new FileReader();
|
||||
console.log(file.type);
|
||||
if (file.type.startsWith("image/svg")) {
|
||||
reader.readAsText(file, "UTF-8");
|
||||
reader.onload = (readerEvt: ProgressEvent<FileReader>) => {
|
||||
if (readerEvt.target && readerEvt.target.result) {
|
||||
addSvgXmlToCanvas(readerEvt.target.result.toString());
|
||||
}
|
||||
};
|
||||
reader.onerror = (readerEvt: ProgressEvent<FileReader>) => {
|
||||
console.error(readerEvt);
|
||||
};
|
||||
} else if (file.type === "image/png" || file.type === "image/jpeg") {
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = (readerEvt: ProgressEvent<FileReader>) => {
|
||||
if (readerEvt.target && readerEvt.target.result) {
|
||||
fabric.Image.fromURL(readerEvt.target.result.toString(), (img: fabric.Image) => {
|
||||
img.set({ left: 0, top: 0, snapAngle:10 });
|
||||
img.scaleToHeight(defaultSize).scaleToHeight(defaultSize);
|
||||
fabricCanvas.add(img);
|
||||
});
|
||||
}
|
||||
};
|
||||
reader.onerror = (readerEvt: ProgressEvent<FileReader>) => {
|
||||
console.error(readerEvt);
|
||||
};
|
||||
}
|
||||
ImageEditorUtils.addImageFile(fabricCanvas, file);
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -253,14 +170,6 @@
|
||||
<svelte:window on:keydown={onKeyDown} />
|
||||
|
||||
<div class="image-editor">
|
||||
<!-- <div class="row mb-1">
|
||||
<div class="col d-flex justify-content-center">
|
||||
<div class="toolbar mb-1 d-flex flex-wrap gap-1 justify-content-center align-items-center">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div class="row mb-1">
|
||||
<div class="col d-flex justify-content-center">
|
||||
<div class="canvas-wrapper print-start-{labelProps.startPos}">
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { PrinterModel, type RfidInfo } from "@mmote/niimbluelib";
|
||||
import { PrinterModel, SoundSettingsItemType, type RfidInfo } from "@mmote/niimbluelib";
|
||||
import { printerClient, connectedPrinterName, connectionState, initClient, heartbeatData, printerConfig } from "../stores";
|
||||
import type { ConnectionType } from "../types";
|
||||
import FaIcon from "./FaIcon.svelte";
|
||||
@ -26,16 +26,21 @@
|
||||
};
|
||||
|
||||
const startHeartbeat = async () => {
|
||||
// timer = setInterval(async () => {
|
||||
// const data = await $printerClient.abstraction.heartbeat();
|
||||
// console.log(data);
|
||||
// }, 1000);
|
||||
$printerClient.startHeartbeat();
|
||||
};
|
||||
const stopHeartbeat = async () => {
|
||||
// clearInterval(timer);
|
||||
$printerClient.stopHeartbeat();
|
||||
};
|
||||
|
||||
const soundOn = async () => {
|
||||
await $printerClient.abstraction.setSoundEnabled(SoundSettingsItemType.BluetoothConnectionSound, true);
|
||||
await $printerClient.abstraction.setSoundEnabled(SoundSettingsItemType.PowerSound, true);
|
||||
};
|
||||
|
||||
const soundOff = async () => {
|
||||
await $printerClient.abstraction.setSoundEnabled(SoundSettingsItemType.BluetoothConnectionSound, false);
|
||||
await $printerClient.abstraction.setSoundEnabled(SoundSettingsItemType.PowerSound, false);
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="input-group flex-nowrap justify-content-end">
|
||||
@ -67,10 +72,12 @@
|
||||
<div>
|
||||
Tests
|
||||
</div>
|
||||
|
||||
|
||||
<button class="btn btn-sm btn-primary" on:click={getRfidInfo}>Rfid</button>
|
||||
<button class="btn btn-sm btn-primary" on:click={startHeartbeat}>Heartbeat on</button>
|
||||
<button class="btn btn-sm btn-primary" on:click={stopHeartbeat}>Heartbeat off</button>
|
||||
<button class="btn btn-sm btn-primary" on:click={soundOn}>Sound on</button>
|
||||
<button class="btn btn-sm btn-primary" on:click={soundOff}>Sound off</button>
|
||||
</div>
|
||||
<span class="input-group-text">{$connectedPrinterName}</span>
|
||||
{:else}
|
||||
|
@ -213,7 +213,6 @@ export class PacketGenerator {
|
||||
return new NiimbotPacket(RequestCommandId.PageEnd, [1]);
|
||||
}
|
||||
|
||||
// https://github.com/ayufan/niimprint-web/blob/main/cmds.js#L215
|
||||
public static printEmptySpace(pos: number, repeats: number): NiimbotPacket {
|
||||
const packet = new NiimbotPacket(RequestCommandId.PrintEmptyRow, [...Utils.u16ToBytes(pos), repeats]);
|
||||
packet.oneWay = true;
|
||||
|
Reference in New Issue
Block a user