Label generator: back-side codes, pictures, two-column layout, measurement guards
This commit is contained in:
@@ -342,6 +342,7 @@ import { ref, computed, watch, onMounted, onBeforeUnmount, nextTick } from 'vue'
|
||||
import { LABEL_PRESETS, qrModuleCount, qrFit, qrSvgDataUri, barcodeSvgDataUri }
|
||||
from '@/utils/codes'
|
||||
import { parseCsv, buildPages, MAX_LABELS } from '../labelPages'
|
||||
import { labelVars, LABEL_VAR_NAMES } from '../labelVars'
|
||||
|
||||
const PRESETS = LABEL_PRESETS
|
||||
|
||||
@@ -591,43 +592,44 @@ async function renderAll() {
|
||||
|
||||
// @page cannot read a scoped style, so the sizing lives in custom properties on
|
||||
// the root element. Chromium honors var() in @page size.
|
||||
const VAR_NAMES = [
|
||||
'--tool-label-w', '--tool-label-h', '--tool-pad', '--tool-code', '--tool-barh',
|
||||
'--tool-quiet', '--tool-gap', '--tool-font', '--tool-align', '--tool-valign',
|
||||
'--tool-content-x', '--tool-content-y', '--tool-nudge-x', '--tool-nudge-y',
|
||||
'--tool-pic', '--tool-pic-opacity',
|
||||
]
|
||||
|
||||
//
|
||||
// The values are built in ../labelVars.js, which is also where the rule lives
|
||||
// that none of them may be NaN or empty: a cleared number field used to emit
|
||||
// `NaNin`, the browser dropped the declaration, and a box that fell back to
|
||||
// auto height rendered the barcode 176 wide by 0 high.
|
||||
function applyVars() {
|
||||
const root = document.documentElement
|
||||
root.style.setProperty('--tool-label-w', labelwidth.value + 'in')
|
||||
root.style.setProperty('--tool-label-h', labelheight.value + 'in')
|
||||
root.style.setProperty('--tool-pad', padding.value + 'in')
|
||||
root.style.setProperty('--tool-code', codesize.value + 'in')
|
||||
root.style.setProperty('--tool-barh', barheight.value + 'in')
|
||||
// Both symbologies need clear space: a QR wants a quiet zone around it, and
|
||||
// CODE128 wants one at each end (10x the narrow bar). It is the code's own
|
||||
// margin and nothing else's - the space between the code and the caption is
|
||||
// --tool-gap, so a tight caption no longer means shaving the quiet zone.
|
||||
root.style.setProperty('--tool-quiet', quiet.value + 'in')
|
||||
root.style.setProperty('--tool-gap', gap.value + 'in')
|
||||
root.style.setProperty('--tool-font', labelfont.value + 'pt')
|
||||
root.style.setProperty('--tool-align', align.value)
|
||||
root.style.setProperty('--tool-valign', valign.value)
|
||||
// Content offset moves what is printed WITHIN the label. Media offset moves
|
||||
// the label box itself on the stock. They are different fixes: the first
|
||||
// composes a label, the second corrects a printer whose origin is off.
|
||||
root.style.setProperty('--tool-content-x', contentx.value + 'in')
|
||||
root.style.setProperty('--tool-content-y', contenty.value + 'in')
|
||||
root.style.setProperty('--tool-nudge-x', nudgex.value + 'in')
|
||||
root.style.setProperty('--tool-nudge-y', nudgey.value + 'in')
|
||||
root.style.setProperty('--tool-pic', picturesize.value + 'in')
|
||||
root.style.setProperty('--tool-pic-opacity', String(pictureopacity.value))
|
||||
const vars = labelVars({
|
||||
labelwidth: labelwidth.value,
|
||||
labelheight: labelheight.value,
|
||||
padding: padding.value,
|
||||
codesize: codesize.value,
|
||||
barheight: barheight.value,
|
||||
// Both symbologies need clear space: a QR wants a quiet zone around it, and
|
||||
// CODE128 wants one at each end (10x the narrow bar). It is the code's own
|
||||
// margin and nothing else's - the space between the code and the caption is
|
||||
// the gap, so a tight caption no longer means shaving the quiet zone.
|
||||
quiet: quiet.value,
|
||||
gap: gap.value,
|
||||
labelfont: labelfont.value,
|
||||
align: align.value,
|
||||
valign: valign.value,
|
||||
// Content offset moves what is printed WITHIN the label. Media offset moves
|
||||
// the label box itself on the stock. They are different fixes: the first
|
||||
// composes a label, the second corrects a printer whose origin is off.
|
||||
contentx: contentx.value,
|
||||
contenty: contenty.value,
|
||||
nudgex: nudgex.value,
|
||||
nudgey: nudgey.value,
|
||||
picturesize: picturesize.value,
|
||||
pictureopacity: pictureopacity.value,
|
||||
})
|
||||
for (const [name, value] of Object.entries(vars)) root.style.setProperty(name, value)
|
||||
}
|
||||
|
||||
function clearVars() {
|
||||
const root = document.documentElement
|
||||
for (const name of VAR_NAMES) root.style.removeProperty(name)
|
||||
for (const name of LABEL_VAR_NAMES) root.style.removeProperty(name)
|
||||
}
|
||||
|
||||
function applyPreset() {
|
||||
@@ -748,7 +750,7 @@ watch([pages, codetype, backcodetype, errorcorrection], renderAll)
|
||||
<style scoped>
|
||||
/* One page per side. Chromium reads var() here; the print dialog must be set
|
||||
to Margins = None and Scale = 100%. */
|
||||
@page { size: var(--tool-label-w) var(--tool-label-h); margin: 0; }
|
||||
@page { size: var(--tool-label-w, 1in) var(--tool-label-h, 0.5in); margin: 0; }
|
||||
|
||||
.code-generator { width: 100%; }
|
||||
|
||||
@@ -875,9 +877,9 @@ watch([pages, codetype, backcodetype, errorcorrection], renderAll)
|
||||
media offset moves it, and that exists for a printer whose origin is off. */
|
||||
.label {
|
||||
box-sizing: border-box;
|
||||
width: var(--tool-label-w);
|
||||
height: var(--tool-label-h);
|
||||
padding: var(--tool-pad);
|
||||
width: var(--tool-label-w, 1in);
|
||||
height: var(--tool-label-h, 0.5in);
|
||||
padding: var(--tool-pad, 0);
|
||||
background: #fff;
|
||||
color: #000;
|
||||
overflow: hidden;
|
||||
@@ -898,7 +900,7 @@ watch([pages, codetype, backcodetype, errorcorrection], renderAll)
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--tool-gap);
|
||||
gap: var(--tool-gap, 0.03in);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
transform: translate(var(--tool-content-x, 0), var(--tool-content-y, 0));
|
||||
@@ -908,7 +910,7 @@ watch([pages, codetype, backcodetype, errorcorrection], renderAll)
|
||||
.codegroup {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--tool-gap);
|
||||
gap: var(--tool-gap, 0.03in);
|
||||
}
|
||||
|
||||
.label.layout-stack .codegroup { flex-direction: column; justify-content: center; }
|
||||
@@ -923,8 +925,8 @@ watch([pages, codetype, backcodetype, errorcorrection], renderAll)
|
||||
|
||||
.picturebox {
|
||||
flex: 0 0 auto;
|
||||
width: var(--tool-pic);
|
||||
height: var(--tool-pic);
|
||||
width: var(--tool-pic, 0.5in);
|
||||
height: var(--tool-pic, 0.5in);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -952,9 +954,9 @@ watch([pages, codetype, backcodetype, errorcorrection], renderAll)
|
||||
|
||||
.codebox {
|
||||
flex: 0 0 auto;
|
||||
margin: var(--tool-quiet);
|
||||
width: var(--tool-code);
|
||||
height: var(--tool-code);
|
||||
margin: var(--tool-quiet, 0.035in);
|
||||
width: var(--tool-code, 0.43in);
|
||||
height: var(--tool-code, 0.43in);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -969,7 +971,7 @@ watch([pages, codetype, backcodetype, errorcorrection], renderAll)
|
||||
/* Never below 40% of the label: past that a CODE128 is too few narrow bars
|
||||
to scan, so it is better for the caption to wrap or clip. */
|
||||
min-width: 40%;
|
||||
height: var(--tool-barh);
|
||||
height: var(--tool-barh, 0.3in);
|
||||
}
|
||||
|
||||
.label.layout-stack.type-barcode .codebox { min-width: 100%; }
|
||||
@@ -998,7 +1000,7 @@ watch([pages, codetype, backcodetype, errorcorrection], renderAll)
|
||||
min-width: 0;
|
||||
text-align: center;
|
||||
font-family: "Arial Narrow", Arial, Helvetica, sans-serif;
|
||||
font-size: var(--tool-font);
|
||||
font-size: var(--tool-font, 7pt);
|
||||
font-weight: 700;
|
||||
line-height: 1.05;
|
||||
overflow-wrap: anywhere;
|
||||
|
||||
Reference in New Issue
Block a user