Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
586 changes: 441 additions & 145 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@mmote/niimbluelib": "0.0.1-alpha.38",
"@popperjs/core": "^2.11.8",
"bootstrap": "5.3.8",
"bwip-js": "4.9.0",
"d3-dsv": "^3.0.1",
"dayjs": "^1.11.19",
"fabric": "^7.1.0",
Expand All @@ -38,6 +39,7 @@
"@sveltejs/vite-plugin-svelte": "^6.2.1",
"@tsconfig/svelte": "^5.0.5",
"@types/bootstrap": "^5.2.10",
"@types/bwip-js": "3.2.3",
"@types/d3-dsv": "^3.0.7",
"@types/node": "^24.10.0",
"@types/qrcode-svg": "^1.1.5",
Expand Down
8 changes: 7 additions & 1 deletion src/components/LabelDesigner.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { ArUcoMarker } from "$/fabric-object/aruco";
import { Barcode } from "$/fabric-object/barcode";
import { QRCode } from "$/fabric-object/qrcode";
import { DataMatrix } from "$/fabric-object/datamatrix";
import { iconCodepoints, type MaterialIcon } from "$/styles/mdi_icons";
import { automation, connectionState, csvData, loadedFonts } from "$/stores";
import {
Expand All @@ -30,6 +31,7 @@
import PrintPreview from "$/components/PrintPreview.svelte";
import ArUcoParamsPanel from "$/components/designer-controls/ArUcoParamsControls.svelte";
import QrCodeParamsPanel from "$/components/designer-controls/QRCodeParamsControls.svelte";
import DataMatrixParamsPanel from "$/components/designer-controls/DataMatrixParamsControls.svelte";
import TextParamsControls from "$/components/designer-controls/TextParamsControls.svelte";
import VariableInsertControl from "$/components/designer-controls/VariableInsertControl.svelte";
import { DEFAULT_LABEL_PROPS, GRID_SIZE, OBJECT_DEFAULTS } from "$/defaults";
Expand Down Expand Up @@ -550,6 +552,10 @@
{#if selectedObject instanceof QRCode}
<QrCodeParamsPanel selectedQRCode={selectedObject} {editRevision} valueUpdated={controlValueUpdated} />
{/if}

{#if selectedObject instanceof DataMatrix}
<DataMatrixParamsPanel selectedDataMatrix={selectedObject} {editRevision} valueUpdated={controlValueUpdated} />
{/if}

{#if selectedObject instanceof ArUcoMarker}
<ArUcoParamsPanel selectedArUco={selectedObject} {editRevision} valueUpdated={controlValueUpdated} />
Expand All @@ -559,7 +565,7 @@
<BarcodeParamsPanel selectedBarcode={selectedObject} {editRevision} valueUpdated={controlValueUpdated} />
{/if}

{#if selectedObject instanceof fabric.IText || selectedObject instanceof QRCode || (selectedObject instanceof Barcode && selectedObject.encoding === "CODE128B")}
{#if selectedObject instanceof fabric.IText || selectedObject instanceof QRCode || selectedObject instanceof DataMatrix || (selectedObject instanceof Barcode && selectedObject.encoding === "CODE128B")}
<VariableInsertControl {selectedObject} valueUpdated={controlValueUpdated} />
{/if}
</div>
Expand Down
31 changes: 31 additions & 0 deletions src/components/designer-controls/DataMatrixParamsControls.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script lang="ts">
import { DataMatrix } from "$/fabric-object/datamatrix";

interface Props {
selectedDataMatrix: DataMatrix;
editRevision: number;
valueUpdated: () => void;
}

let { selectedDataMatrix, editRevision, valueUpdated }: Props = $props();
</script>

<input type="hidden" value={editRevision}>

<textarea
class="datamatrix-content form-control"
value={selectedDataMatrix.text}
oninput={(e) => {
selectedDataMatrix?.set("text", e.currentTarget.value);
valueUpdated();
}}></textarea>

<style>
.input-group {
width: fit-content;
}

.datamatrix-content {
height: 100px;
}
</style>
4 changes: 4 additions & 0 deletions src/components/designer-controls/ObjectPicker.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
<MdIcon icon="qr_code_2" />
{$tr("editor.objectpicker.qrcode")}
</button>
<button class="btn me-1" onclick={() => onSubmit("datamatrix")}>
<MdIcon icon="qr_code_2" />
{$tr("editor.objectpicker.datamatrix")}
</button>
<button class="btn me-1" onclick={() => onSubmit("aruco")}>
<MdIcon icon="grid_on" />
{$tr("editor.objectpicker.aruco")}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import QRCode from "$/fabric-object/qrcode";
import Barcode from "$/fabric-object/barcode";

import { DataMatrix } from "$/fabric-object/datamatrix";

interface Props {
selectedObject: fabric.FabricObject;
}
Expand Down Expand Up @@ -75,7 +77,7 @@
<span class="input-group-text">y</span>
<input class="form-control" type="number" bind:value={y} onchange={updateObject} />
</div>
{#if !(selectedObject instanceof fabric.FabricText || selectedObject instanceof fabric.FabricImage || selectedObject instanceof QRCode || selectedObject instanceof Barcode)}
{#if !(selectedObject instanceof fabric.FabricText || selectedObject instanceof fabric.FabricImage || selectedObject instanceof QRCode || selectedObject instanceof DataMatrix || selectedObject instanceof Barcode)}
<div class="input-group flex-nowrap input-group-sm mb-2">
<input class="form-control" type="number" min="1" bind:value={width} onchange={updateObject} />
<span class="input-group-text">x</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import * as fabric from "fabric";
import { tr } from "$/utils/i18n";
import QRCode from "$/fabric-object/qrcode";
import { DataMatrix } from "$/fabric-object/datamatrix";
import Barcode from "$/fabric-object/barcode";
import MdIcon from "$/components/basic/MdIcon.svelte";

Expand All @@ -21,7 +22,7 @@
if (selectedObject instanceof fabric.IText) {
selectedObject.exitEditing();
selectedObject.set({ text: `${selectedObject.text}${value}` });
} else if (selectedObject instanceof QRCode) {
} else if (selectedObject instanceof QRCode || selectedObject instanceof DataMatrix) {
selectedObject.set({ text: `${selectedObject.text}${value}` });
} else if (selectedObject instanceof Barcode) {
selectedObject.set({ text: `${selectedObject.text}${value}` });
Expand Down
128 changes: 128 additions & 0 deletions src/fabric-object/datamatrix.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import bwipjs from "bwip-js";
import * as fabric from "fabric";
import { OBJECT_SIZE_DEFAULTS } from "$/defaults";
import { CanvasUtils } from "$/utils/canvas_utils";

export const dataMatrixDefaultValues: Partial<fabric.TClassProperties<DataMatrix>> = {
text: "Text",
stroke: "#000000",
fill: "#ffffff",
...OBJECT_SIZE_DEFAULTS,
};

interface UniqueDataMatrixProps {
text: string;
}
export interface DataMatrixProps extends fabric.FabricObjectProps, UniqueDataMatrixProps {}
export interface SerializedDataMatrixProps extends fabric.SerializedObjectProps, UniqueDataMatrixProps {}
const DATAMATRIX_PROPS = ["text", "size"] as const;

export class DataMatrix<
Props extends fabric.TOptions<DataMatrixProps> = Partial<DataMatrixProps>,
SProps extends SerializedDataMatrixProps = SerializedDataMatrixProps,
EventSpec extends fabric.ObjectEvents = fabric.ObjectEvents,
>
extends fabric.FabricObject<Props, SProps, EventSpec>
implements DataMatrixProps
{
static override readonly type = "DataMatrix";

/**
* DataMatrix text
*/
declare text: string;

constructor(options?: Props) {
super();
Object.assign(this, dataMatrixDefaultValues);
this.setOptions(options);
this.lockScalingFlip = true;
this.setControlsVisibility({
ml: false,
mt: false,
mr: false,
mb: false,
tl: false,
tr: false,
bl: false,
});
}

override _set(key: string, value: any): this {
super._set(key, value);
if (key === "text") {
this.dirty = true;
}

return this;
}

override _render(ctx: CanvasRenderingContext2D): void {
if (!this.text) {
CanvasUtils.renderError(ctx, this.width, this.height);
super._render(ctx);
return;
}

let dmData: any;

try {
const res = bwipjs.raw({ bcid: "datamatrix", text: this.text });
dmData = res?.[0];
if (!dmData || !('pixs' in dmData)) throw new Error("Invalid bwip-js output");
} catch (e) {
console.error(e);
CanvasUtils.renderError(ctx, this.width, this.height);
super._render(ctx);
return;
}

const { pixs, pixx, pixy } = dmData;

// Choose scaling factor to map modules to canvas size
const dmScaleX = Math.floor(this.width / pixx);
const dmScaleY = Math.floor(this.height / pixy);
const dmScale = Math.min(dmScaleX, dmScaleY);

let dmWidth = dmScale * pixx;
let dmHeight = dmScale * pixy;
dmWidth -= dmWidth % 2; // avoid half-pixel rendering
dmHeight -= dmHeight % 2;

if (dmScale < 1 || dmWidth > this.width || dmHeight > this.height) {
CanvasUtils.renderError(ctx, this.width, this.height);
super._render(ctx);
return;
}

ctx.save();

const offsetX = -dmWidth / 2;
const offsetY = -dmHeight / 2;
ctx.translate(offsetX, offsetY); // center
ctx.translate(-0.5, -0.5); // blurry rendering fix

ctx.fillStyle = this.fill as string;
ctx.fillRect(0, 0, dmWidth, dmHeight);

ctx.fillStyle = "#000000";

for (let y = 0; y < pixy; y++) {
for (let x = 0; x < pixx; x++) {
if (pixs[y * pixx + x]) {
ctx.fillRect(x * dmScale, y * dmScale, dmScale, dmScale);
}
}
}

ctx.restore();

super._render(ctx);
}

override toObject(propertiesToInclude: any[] = []) {
return super.toObject([...DATAMATRIX_PROPS, ...propertiesToInclude]);
}
}

fabric.classRegistry.setClass(DataMatrix, "DataMatrix");
1 change: 1 addition & 0 deletions src/locale/dicts/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"editor.objectpicker.image": "صورة",
"editor.objectpicker.line": "خط",
"editor.objectpicker.qrcode": "QR Code",
"editor.objectpicker.datamatrix": "DataMatrix",
"editor.objectpicker.rectangle": "مستطيل",
"editor.objectpicker.text": "نص",
"editor.objectpicker.title": "أضف عنصر",
Expand Down
1 change: 1 addition & 0 deletions src/locale/dicts/bg.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"editor.objectpicker.image": "Изображение",
"editor.objectpicker.line": "Ред",
"editor.objectpicker.qrcode": "Код на QR",
"editor.objectpicker.datamatrix": "DataMatrix",
"editor.objectpicker.rectangle": "Правоъгълник",
"editor.objectpicker.text": "Текст",
"editor.objectpicker.title": "Добавяне на обект",
Expand Down
1 change: 1 addition & 0 deletions src/locale/dicts/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"editor.objectpicker.image": "Obrázek",
"editor.objectpicker.line": "Čára",
"editor.objectpicker.qrcode": "QR Kód",
"editor.objectpicker.datamatrix": "DataMatrix",
"editor.objectpicker.rectangle": "Obdélník",
"editor.objectpicker.text": "Text",
"editor.objectpicker.title": "Přidat objekt",
Expand Down
1 change: 1 addition & 0 deletions src/locale/dicts/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"editor.objectpicker.image": "Grafik",
"editor.objectpicker.line": "Linie",
"editor.objectpicker.qrcode": "QR-Code",
"editor.objectpicker.datamatrix": "DataMatrix",
"editor.objectpicker.rectangle": "Rechteck",
"editor.objectpicker.text": "Text",
"editor.objectpicker.title": "Objekt hinzufügen",
Expand Down
1 change: 1 addition & 0 deletions src/locale/dicts/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"editor.objectpicker.image": "Image",
"editor.objectpicker.line": "Line",
"editor.objectpicker.qrcode": "QR Code",
"editor.objectpicker.datamatrix": "DataMatrix",
"editor.objectpicker.rectangle": "Rectangle",
"editor.objectpicker.text": "Text",
"editor.objectpicker.title": "Add object",
Expand Down
1 change: 1 addition & 0 deletions src/locale/dicts/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"editor.objectpicker.image": "Imagen",
"editor.objectpicker.line": "Línea",
"editor.objectpicker.qrcode": "Código QR",
"editor.objectpicker.datamatrix": "DataMatrix",
"editor.objectpicker.rectangle": "Rectángulo",
"editor.objectpicker.text": "Texto",
"editor.objectpicker.title": "Añadir objeto",
Expand Down
1 change: 1 addition & 0 deletions src/locale/dicts/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"editor.objectpicker.image": "Image",
"editor.objectpicker.line": "Ligne",
"editor.objectpicker.qrcode": "QR Code",
"editor.objectpicker.datamatrix": "DataMatrix",
"editor.objectpicker.rectangle": "Rectangle",
"editor.objectpicker.text": "Texte",
"editor.objectpicker.title": "Ajouter un objet",
Expand Down
1 change: 1 addition & 0 deletions src/locale/dicts/hi.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"editor.objectpicker.image": "इमेज",
"editor.objectpicker.line": "लाइन",
"editor.objectpicker.qrcode": "क्यूआर कोड",
"editor.objectpicker.datamatrix": "DataMatrix",
"editor.objectpicker.rectangle": "आयत (Rectangle)",
"editor.objectpicker.text": "टेक्स्ट",
"editor.objectpicker.title": "ऑब्जेक्ट जोड़ें",
Expand Down
1 change: 1 addition & 0 deletions src/locale/dicts/hr.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"editor.objectpicker.image": "Slika",
"editor.objectpicker.line": "Linija",
"editor.objectpicker.qrcode": "QR kod",
"editor.objectpicker.datamatrix": "DataMatrix",
"editor.objectpicker.rectangle": "Pravokutnik",
"editor.objectpicker.text": "Tekst",
"editor.objectpicker.title": "Dodaj objekt",
Expand Down
1 change: 1 addition & 0 deletions src/locale/dicts/hu.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"editor.objectpicker.image": "Kép",
"editor.objectpicker.line": "Vonal",
"editor.objectpicker.qrcode": "QR-kód",
"editor.objectpicker.datamatrix": "DataMatrix",
"editor.objectpicker.rectangle": "Négyzet",
"editor.objectpicker.text": "Szöveg",
"editor.objectpicker.title": "Elem beszúrása",
Expand Down
1 change: 1 addition & 0 deletions src/locale/dicts/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"editor.objectpicker.image": "Immagine",
"editor.objectpicker.line": "Linea",
"editor.objectpicker.qrcode": "Codice QR",
"editor.objectpicker.datamatrix": "DataMatrix",
"editor.objectpicker.rectangle": "Rettangolo",
"editor.objectpicker.text": "Testo",
"editor.objectpicker.title": "Aggiungi oggetto",
Expand Down
1 change: 1 addition & 0 deletions src/locale/dicts/ko_KR.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"editor.objectpicker.image": "이미지",
"editor.objectpicker.line": "선",
"editor.objectpicker.qrcode": "QR 코드",
"editor.objectpicker.datamatrix": "DataMatrix",
"editor.objectpicker.rectangle": "사각형",
"editor.objectpicker.text": "텍스트",
"editor.objectpicker.title": "개체 추가",
Expand Down
1 change: 1 addition & 0 deletions src/locale/dicts/mr.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"editor.objectpicker.image": "प्रतिमा",
"editor.objectpicker.line": "रेषा",
"editor.objectpicker.qrcode": "QR कोड",
"editor.objectpicker.datamatrix": "DataMatrix",
"editor.objectpicker.rectangle": "आयत",
"editor.objectpicker.text": "मजकूर",
"editor.objectpicker.title": "ऑब्जेक्ट जोडा",
Expand Down
1 change: 1 addition & 0 deletions src/locale/dicts/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"editor.objectpicker.image": "Obraz",
"editor.objectpicker.line": "Linia",
"editor.objectpicker.qrcode": "Kod QR",
"editor.objectpicker.datamatrix": "DataMatrix",
"editor.objectpicker.rectangle": "Prostokąt",
"editor.objectpicker.text": "Tekst",
"editor.objectpicker.title": "Dodaj obiekt",
Expand Down
1 change: 1 addition & 0 deletions src/locale/dicts/pt_BR.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"editor.objectpicker.image": "Imagem",
"editor.objectpicker.line": "Linha",
"editor.objectpicker.qrcode": "QR Code",
"editor.objectpicker.datamatrix": "DataMatrix",
"editor.objectpicker.rectangle": "Retângulo",
"editor.objectpicker.text": "Texto",
"editor.objectpicker.title": "Adicionar objeto",
Expand Down
1 change: 1 addition & 0 deletions src/locale/dicts/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"editor.objectpicker.image": "Картинка",
"editor.objectpicker.line": "Линия",
"editor.objectpicker.qrcode": "QR Код",
"editor.objectpicker.datamatrix": "DataMatrix",
"editor.objectpicker.rectangle": "Прямоугольник",
"editor.objectpicker.text": "Текст",
"editor.objectpicker.title": "Добавить объект",
Expand Down
1 change: 1 addition & 0 deletions src/locale/dicts/tr.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"editor.objectpicker.image": "Resim",
"editor.objectpicker.line": "Çizgi",
"editor.objectpicker.qrcode": "QR Kod",
"editor.objectpicker.datamatrix": "DataMatrix",
"editor.objectpicker.rectangle": "Dikdörtgen",
"editor.objectpicker.text": "Metin",
"editor.objectpicker.title": "Nesne ekle",
Expand Down
Loading