<template>
|
<div class="matnr-print-canvas-shell">
|
<div
|
ref="canvasRef"
|
class="matnr-print-canvas"
|
:class="{
|
'matnr-print-canvas--editor': editorMode,
|
'matnr-print-canvas--interactive': interactive,
|
'matnr-print-canvas--grid': showGrid && editorMode
|
}"
|
:style="canvasStyle"
|
@mousedown.self="handleCanvasMouseDown"
|
>
|
<div
|
v-for="element in renderedTemplate.elements"
|
:key="element.id"
|
class="matnr-print-element"
|
:class="{
|
'is-selected': interactive && selectedElementId === element.id,
|
'is-hidden': element.visible === false,
|
'is-table': element.type === 'table'
|
}"
|
:style="getElementBoxStyle(element)"
|
@mousedown.stop="handleElementMouseDown($event, element)"
|
>
|
<div
|
v-if="element.type === 'text'"
|
class="matnr-print-element__text"
|
:style="getTextStyle(element)"
|
>
|
{{ element.resolvedText }}
|
</div>
|
|
<div
|
v-else-if="element.type === 'barcode'"
|
class="matnr-print-element__barcode"
|
v-html="element.svgMarkup"
|
></div>
|
|
<div v-else-if="element.type === 'qrcode'" class="matnr-print-element__qrcode">
|
<QrcodeVue
|
:value="element.resolvedValue || ' '"
|
render-as="svg"
|
level="M"
|
:size="getQrcodeSize(element)"
|
:margin="0"
|
/>
|
</div>
|
|
<div v-else-if="element.type === 'image'" class="matnr-print-element__image">
|
<img
|
v-if="element.resolvedSrc"
|
:src="element.resolvedSrc"
|
:style="getImageStyle(element)"
|
alt=""
|
draggable="false"
|
/>
|
<div v-else class="matnr-print-element__image-placeholder"></div>
|
</div>
|
|
<div
|
v-else-if="element.type === 'line'"
|
class="matnr-print-element__line"
|
:style="getLineStyle(element)"
|
></div>
|
|
<div
|
v-else-if="element.type === 'rect'"
|
class="matnr-print-element__rect"
|
:style="getRectStyle(element)"
|
></div>
|
|
<div
|
v-else-if="element.type === 'table'"
|
class="matnr-print-element__table"
|
:style="getTableStyle(element)"
|
>
|
<div
|
v-for="cell in element.resolvedCells"
|
:key="`${element.id}_${cell.row}_${cell.col}`"
|
class="matnr-print-element__table-cell"
|
:style="getTableCellStyle(cell, element)"
|
>
|
<div
|
class="matnr-print-element__table-cell-content"
|
:style="getTableCellContentStyle()"
|
>
|
{{ cell.resolvedText }}
|
</div>
|
</div>
|
</div>
|
|
<template
|
v-if="interactive && selectedElementId === element.id && element.type === 'table'"
|
>
|
<span
|
v-for="handle in getTableColumnHandles(element)"
|
:key="`${element.id}_col_handle_${handle.index}`"
|
class="matnr-print-element__table-divider is-column"
|
:style="getTableDividerStyle(element, 'column', handle)"
|
@mousedown.stop="handleTableResizeMouseDown($event, element, 'column', handle.index)"
|
></span>
|
<span
|
v-for="handle in getTableRowHandles(element)"
|
:key="`${element.id}_row_handle_${handle.index}`"
|
class="matnr-print-element__table-divider is-row"
|
:style="getTableDividerStyle(element, 'row', handle)"
|
@mousedown.stop="handleTableResizeMouseDown($event, element, 'row', handle.index)"
|
></span>
|
</template>
|
|
<template v-if="interactive && selectedElementId === element.id && element.type !== 'line'">
|
<span
|
v-for="handle in resizeHandles"
|
:key="handle.direction"
|
class="matnr-print-element__handle"
|
:class="`is-${handle.direction}`"
|
@mousedown.stop="handleResizeMouseDown($event, element, handle.direction)"
|
></span>
|
</template>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script setup>
|
import { computed, onBeforeUnmount, ref } from 'vue'
|
import QrcodeVue from 'qrcode.vue'
|
import {
|
mmToPx,
|
normalizeMatnrPrintTemplate,
|
renderMatnrPrintTemplate
|
} from '../matnrPrintTemplate.helpers'
|
|
defineOptions({ name: 'MatnrPrintCanvas' })
|
|
const props = defineProps({
|
template: {
|
type: Object,
|
default: () => ({})
|
},
|
activeRecord: {
|
type: Object,
|
default: () => ({})
|
},
|
selectedElementId: {
|
type: String,
|
default: ''
|
},
|
mode: {
|
type: String,
|
default: 'editor'
|
},
|
scale: {
|
type: Number,
|
default: 4
|
},
|
interactive: {
|
type: Boolean,
|
default: false
|
},
|
showGrid: {
|
type: Boolean,
|
default: false
|
}
|
})
|
|
const emit = defineEmits(['select-element', 'update-element'])
|
|
const canvasRef = ref(null)
|
const interactionState = ref(null)
|
const TABLE_MIN_COLUMN_WIDTH = 6
|
const TABLE_MIN_ROW_HEIGHT = 4
|
const resizeHandles = [
|
{ direction: 'top-left' },
|
{ direction: 'top' },
|
{ direction: 'top-right' },
|
{ direction: 'right' },
|
{ direction: 'bottom-right' },
|
{ direction: 'bottom' },
|
{ direction: 'bottom-left' },
|
{ direction: 'left' }
|
]
|
|
const editorMode = computed(() => props.mode === 'editor')
|
const normalizedTemplate = computed(() => normalizeMatnrPrintTemplate(props.template))
|
const renderedTemplate = computed(() =>
|
renderMatnrPrintTemplate(normalizedTemplate.value, props.activeRecord || {})
|
)
|
|
const canvasStyle = computed(() => {
|
const canvas = renderedTemplate.value.canvas
|
const width = editorMode.value ? mmToPx(canvas.width, props.scale) : `${canvas.width}mm`
|
const height = editorMode.value ? mmToPx(canvas.height, props.scale) : `${canvas.height}mm`
|
const gridSize = `${canvas.gridSize * props.scale}px`
|
return {
|
width,
|
height,
|
backgroundColor: canvas.backgroundColor || '#FFFFFF',
|
'--matnr-print-grid-size': gridSize
|
}
|
})
|
|
function getUnitValue(value) {
|
return editorMode.value ? mmToPx(value, props.scale) : `${value}mm`
|
}
|
|
function getElementBoxStyle(element) {
|
return {
|
left: getUnitValue(element.x),
|
top: getUnitValue(element.y),
|
width: getUnitValue(element.w),
|
height: getUnitValue(element.h),
|
zIndex: element.zIndex
|
}
|
}
|
|
function getTextStyle(element) {
|
const style = element.style || {}
|
return {
|
fontSize: editorMode.value ? mmToPx(style.fontSize, props.scale) : `${style.fontSize}mm`,
|
fontWeight: style.fontWeight,
|
color: style.color,
|
textAlign: style.textAlign,
|
lineHeight: style.lineHeight
|
}
|
}
|
|
function getLineStyle(element) {
|
const borderSize = editorMode.value
|
? mmToPx(element.borderWidth || 0.4, props.scale)
|
: `${element.borderWidth || 0.4}mm`
|
return {
|
backgroundColor: element.color || '#111111',
|
height: element.direction === 'horizontal' ? borderSize : editorMode.value ? '100%' : '100%',
|
width: element.direction === 'vertical' ? borderSize : editorMode.value ? '100%' : '100%'
|
}
|
}
|
|
function getRectStyle(element) {
|
return {
|
borderWidth: editorMode.value
|
? mmToPx(element.borderWidth || 0.4, props.scale)
|
: `${element.borderWidth || 0.4}mm`,
|
borderStyle: 'solid',
|
borderColor: element.borderColor || '#111111',
|
backgroundColor: element.backgroundColor || '#FFFFFF',
|
borderRadius: editorMode.value
|
? mmToPx(element.radius || 0, props.scale)
|
: `${element.radius || 0}mm`
|
}
|
}
|
|
function getImageStyle(element) {
|
return {
|
objectFit: element.objectFit || 'contain'
|
}
|
}
|
|
function getTableStyle(element) {
|
const style = element.style || {}
|
return {
|
fontSize: editorMode.value ? mmToPx(style.fontSize, props.scale) : `${style.fontSize}mm`,
|
color: style.color,
|
position: 'relative'
|
}
|
}
|
|
function getTableColumnSpanWidth(element, cell) {
|
const columns = Array.isArray(element?.columns) ? element.columns : []
|
const startCol = Number(cell?.col) || 0
|
const colspan = Math.max(1, Number(cell?.colspan) || 1)
|
return columns
|
.slice(startCol, startCol + colspan)
|
.reduce((total, column) => total + (Number(column?.width) || 6), 0)
|
}
|
|
function getTableCellSpanHeight(element, cell) {
|
const rows = Array.isArray(element?.rows) ? element.rows : []
|
const startRow = Number(cell?.row) || 0
|
const rowspan = Math.max(1, Number(cell?.rowspan) || 1)
|
return rows
|
.slice(startRow, startRow + rowspan)
|
.reduce((total, row) => total + (Number(row?.height) || 6), 0)
|
}
|
|
function getTableCellStyle(cell, element) {
|
const style = cell.style || {}
|
const borderWidth = editorMode.value
|
? mmToPx(style.borderWidth || 0.2, props.scale)
|
: `${style.borderWidth || 0.2}mm`
|
const borderColor = style.borderColor || '#111111'
|
const columns = Array.isArray(element?.columns) ? element.columns : []
|
const rows = Array.isArray(element?.rows) ? element.rows : []
|
const left = columns
|
.slice(0, Math.max(0, Number(cell?.col) || 0))
|
.reduce((total, column) => total + (Number(column?.width) || 6), 0)
|
const top = rows
|
.slice(0, Math.max(0, Number(cell?.row) || 0))
|
.reduce((total, row) => total + (Number(row?.height) || 6), 0)
|
|
return {
|
position: 'absolute',
|
left: getUnitValue(left),
|
top: getUnitValue(top),
|
width: getUnitValue(getTableColumnSpanWidth(element, cell)),
|
height: getUnitValue(getTableCellSpanHeight(element, cell)),
|
borderTop: Number(cell?.row) === 0 ? `${borderWidth} solid ${borderColor}` : 'none',
|
borderLeft: Number(cell?.col) === 0 ? `${borderWidth} solid ${borderColor}` : 'none',
|
borderRight: `${borderWidth} solid ${borderColor}`,
|
borderBottom: `${borderWidth} solid ${borderColor}`,
|
backgroundColor: style.backgroundColor || '#FFFFFF',
|
textAlign: style.textAlign || 'left',
|
fontWeight: style.fontWeight || 400,
|
boxSizing: 'border-box',
|
padding: 0,
|
overflow: 'hidden'
|
}
|
}
|
|
function getTableCellContentStyle() {
|
const paddingY = editorMode.value ? `${0.4 * props.scale}px` : '0.4mm'
|
const paddingX = editorMode.value ? `${0.8 * props.scale}px` : '0.8mm'
|
return {
|
width: '100%',
|
height: '100%',
|
boxSizing: 'border-box',
|
padding: `${paddingY} ${paddingX}`,
|
overflow: 'hidden',
|
display: 'flex',
|
alignItems: 'center',
|
whiteSpace: 'pre-wrap',
|
wordBreak: 'break-word'
|
}
|
}
|
|
function getTableColumnHandles(element) {
|
const columns = Array.isArray(element?.columns) ? element.columns : []
|
let offset = 0
|
return columns.slice(0, -1).map((column, index) => {
|
offset += Number(column?.width) || 0
|
return {
|
index,
|
offset
|
}
|
})
|
}
|
|
function getTableRowHandles(element) {
|
const rows = Array.isArray(element?.rows) ? element.rows : []
|
let offset = 0
|
return rows.slice(0, -1).map((row, index) => {
|
offset += Number(row?.height) || 0
|
return {
|
index,
|
offset
|
}
|
})
|
}
|
|
function getTableDividerStyle(element, axis, handle) {
|
const baseOffset = Number(handle?.offset) || 0
|
|
return axis === 'column'
|
? { left: getUnitValue(baseOffset) }
|
: { top: getUnitValue(baseOffset) }
|
}
|
|
function getQrcodeSize(element) {
|
const sizeMm = Math.max(element.w || 12, element.h || 12)
|
return Math.max(48, sizeMm * (editorMode.value ? props.scale : 4))
|
}
|
|
function handleCanvasMouseDown() {
|
if (!props.interactive) {
|
return
|
}
|
emit('select-element', '')
|
}
|
|
function handleElementMouseDown(event, element) {
|
if (!props.interactive) {
|
return
|
}
|
emit('select-element', element.id)
|
if (element.type === 'line') {
|
return startInteraction(event, element, 'drag')
|
}
|
if (event.target?.classList?.contains('matnr-print-element__handle')) {
|
return
|
}
|
startInteraction(event, element, 'drag')
|
}
|
|
function handleResizeMouseDown(event, element, direction) {
|
if (!props.interactive) {
|
return
|
}
|
emit('select-element', element.id)
|
startInteraction(event, element, 'resize', direction, {
|
tableColumns:
|
element.type === 'table' && Array.isArray(element?.columns)
|
? element.columns.map((column) => ({
|
width: Number(column?.width) || TABLE_MIN_COLUMN_WIDTH
|
}))
|
: [],
|
tableRows:
|
element.type === 'table' && Array.isArray(element?.rows)
|
? element.rows.map((row) => ({
|
height: Number(row?.height) || TABLE_MIN_ROW_HEIGHT
|
}))
|
: [],
|
elementType: element?.type || ''
|
})
|
}
|
|
function handleTableResizeMouseDown(event, element, axis, index) {
|
if (!props.interactive) {
|
return
|
}
|
emit('select-element', element.id)
|
startInteraction(event, element, `table-${axis}-resize`, '', {
|
index,
|
columns: Array.isArray(element?.columns)
|
? element.columns.map((column) => ({
|
width: Number(column?.width) || TABLE_MIN_COLUMN_WIDTH
|
}))
|
: [],
|
rows: Array.isArray(element?.rows)
|
? element.rows.map((row) => ({
|
height: Number(row?.height) || TABLE_MIN_ROW_HEIGHT
|
}))
|
: []
|
})
|
}
|
|
function startInteraction(event, element, type, direction = '', extra = {}) {
|
interactionState.value = {
|
type,
|
direction,
|
elementId: element.id,
|
startX: event.clientX,
|
startY: event.clientY,
|
origin: {
|
x: Number(element.x) || 0,
|
y: Number(element.y) || 0,
|
w: Number(element.w) || 0,
|
h: Number(element.h) || 0
|
},
|
...extra
|
}
|
window.addEventListener('mousemove', handleWindowMouseMove)
|
window.addEventListener('mouseup', stopInteraction)
|
}
|
|
function handleWindowMouseMove(event) {
|
if (!interactionState.value) {
|
return
|
}
|
const dx = snapMm((event.clientX - interactionState.value.startX) / props.scale)
|
const dy = snapMm((event.clientY - interactionState.value.startY) / props.scale)
|
const origin = interactionState.value.origin
|
let patch = {}
|
|
if (interactionState.value.type === 'drag') {
|
patch = {
|
x: Math.max(0, origin.x + dx),
|
y: Math.max(0, origin.y + dy)
|
}
|
} else if (interactionState.value.type === 'resize') {
|
patch =
|
interactionState.value.elementType === 'table'
|
? buildTableElementResizePatch(
|
origin,
|
dx,
|
dy,
|
interactionState.value.direction,
|
interactionState.value.tableColumns,
|
interactionState.value.tableRows
|
)
|
: buildResizePatch(origin, dx, dy, interactionState.value.direction)
|
} else if (interactionState.value.type === 'table-column-resize') {
|
patch = buildTableColumnResizePatch(
|
interactionState.value.columns,
|
interactionState.value.index,
|
dx
|
)
|
} else if (interactionState.value.type === 'table-row-resize') {
|
patch = buildTableRowResizePatch(
|
interactionState.value.rows,
|
interactionState.value.index,
|
dy
|
)
|
}
|
|
emit('update-element', {
|
id: interactionState.value.elementId,
|
patch
|
})
|
}
|
|
function buildResizePatch(origin, dx, dy, direction) {
|
const next = {
|
x: origin.x,
|
y: origin.y,
|
w: origin.w,
|
h: origin.h
|
}
|
|
if (direction.includes('left')) {
|
next.x = Math.max(0, origin.x + dx)
|
next.w = Math.max(2, origin.w - dx)
|
}
|
if (direction.includes('right')) {
|
next.w = Math.max(2, origin.w + dx)
|
}
|
if (direction.includes('top')) {
|
next.y = Math.max(0, origin.y + dy)
|
next.h = Math.max(2, origin.h - dy)
|
}
|
if (direction.includes('bottom')) {
|
next.h = Math.max(2, origin.h + dy)
|
}
|
|
if (next.w === 2 && direction.includes('left')) {
|
next.x = origin.x + origin.w - 2
|
}
|
if (next.h === 2 && direction.includes('top')) {
|
next.y = origin.y + origin.h - 2
|
}
|
|
return next
|
}
|
|
function buildTableElementResizePatch(origin, dx, dy, direction, columns, rows) {
|
const basePatch = buildResizePatch(origin, dx, dy, direction)
|
const nextColumns = scaleTableTracks(columns, 'width', basePatch.w, TABLE_MIN_COLUMN_WIDTH)
|
const nextRows = scaleTableTracks(rows, 'height', basePatch.h, TABLE_MIN_ROW_HEIGHT)
|
const nextWidth = Number(
|
nextColumns.reduce((total, column) => total + (Number(column?.width) || 0), 0).toFixed(2)
|
)
|
const nextHeight = Number(
|
nextRows.reduce((total, row) => total + (Number(row?.height) || 0), 0).toFixed(2)
|
)
|
|
return {
|
...basePatch,
|
x: direction.includes('left') ? Math.max(0, origin.x + origin.w - nextWidth) : basePatch.x,
|
y: direction.includes('top') ? Math.max(0, origin.y + origin.h - nextHeight) : basePatch.y,
|
w: nextWidth,
|
h: nextHeight,
|
columns: nextColumns,
|
rows: nextRows
|
}
|
}
|
|
function scaleTableTracks(tracks, key, targetTotal, minValue) {
|
const source = Array.isArray(tracks)
|
? tracks.map((track) => ({
|
[key]: Number(track?.[key]) || minValue
|
}))
|
: []
|
if (!source.length) {
|
return []
|
}
|
|
const minimumTotal = minValue * source.length
|
const effectiveTarget = Math.max(minimumTotal, Number(targetTotal) || minimumTotal)
|
const sourceTotal = source.reduce((total, track) => total + (Number(track?.[key]) || 0), 0)
|
|
let nextTracks =
|
sourceTotal > 0
|
? source.map((track) => ({
|
[key]: Math.max(
|
minValue,
|
Number((((Number(track?.[key]) || 0) / sourceTotal) * effectiveTarget).toFixed(2))
|
)
|
}))
|
: source.map(() => ({
|
[key]: Number((effectiveTarget / source.length).toFixed(2))
|
}))
|
|
let remainder = Number(
|
(
|
effectiveTarget -
|
nextTracks.reduce((total, track) => total + (Number(track?.[key]) || 0), 0)
|
).toFixed(2)
|
)
|
|
if (Math.abs(remainder) < 0.01) {
|
return nextTracks
|
}
|
|
if (remainder > 0) {
|
nextTracks[nextTracks.length - 1] = {
|
...nextTracks[nextTracks.length - 1],
|
[key]: Number((nextTracks[nextTracks.length - 1][key] + remainder).toFixed(2))
|
}
|
return nextTracks
|
}
|
|
let remaining = Math.abs(remainder)
|
for (let index = nextTracks.length - 1; index >= 0 && remaining > 0.009; index -= 1) {
|
const currentValue = Number(nextTracks[index]?.[key]) || minValue
|
const adjustable = Number(Math.max(0, currentValue - minValue).toFixed(2))
|
if (adjustable <= 0) {
|
continue
|
}
|
const deduction = Math.min(adjustable, remaining)
|
nextTracks[index] = {
|
...nextTracks[index],
|
[key]: Number((currentValue - deduction).toFixed(2))
|
}
|
remaining = Number((remaining - deduction).toFixed(2))
|
}
|
|
return nextTracks
|
}
|
|
function buildTableColumnResizePatch(columns, index, delta) {
|
const nextColumns = Array.isArray(columns)
|
? columns.map((column) => ({
|
width: Number(column?.width) || TABLE_MIN_COLUMN_WIDTH
|
}))
|
: []
|
if (!nextColumns[index] || !nextColumns[index + 1]) {
|
return {}
|
}
|
|
const leftWidth = nextColumns[index].width
|
const rightWidth = nextColumns[index + 1].width
|
const boundedDelta = Math.min(
|
Math.max(delta, TABLE_MIN_COLUMN_WIDTH - leftWidth),
|
rightWidth - TABLE_MIN_COLUMN_WIDTH
|
)
|
|
nextColumns[index] = {
|
...nextColumns[index],
|
width: Number((leftWidth + boundedDelta).toFixed(2))
|
}
|
nextColumns[index + 1] = {
|
...nextColumns[index + 1],
|
width: Number((rightWidth - boundedDelta).toFixed(2))
|
}
|
|
return {
|
columns: nextColumns,
|
w: Number(
|
nextColumns.reduce((total, column) => total + (Number(column?.width) || 0), 0).toFixed(2)
|
)
|
}
|
}
|
|
function buildTableRowResizePatch(rows, index, delta) {
|
const nextRows = Array.isArray(rows)
|
? rows.map((row) => ({
|
height: Number(row?.height) || TABLE_MIN_ROW_HEIGHT
|
}))
|
: []
|
if (!nextRows[index]) {
|
return {}
|
}
|
|
const currentHeight = nextRows[index].height
|
const boundedDelta = Math.max(delta, TABLE_MIN_ROW_HEIGHT - currentHeight)
|
|
nextRows[index] = {
|
...nextRows[index],
|
height: Number((currentHeight + boundedDelta).toFixed(2))
|
}
|
|
return {
|
rows: nextRows,
|
h: Number(nextRows.reduce((total, row) => total + (Number(row?.height) || 0), 0).toFixed(2))
|
}
|
}
|
|
function stopInteraction() {
|
interactionState.value = null
|
window.removeEventListener('mousemove', handleWindowMouseMove)
|
window.removeEventListener('mouseup', stopInteraction)
|
}
|
|
function snapMm(value) {
|
return Math.round(Number(value || 0))
|
}
|
|
onBeforeUnmount(() => {
|
stopInteraction()
|
})
|
</script>
|
|
<style scoped>
|
.matnr-print-canvas-shell {
|
width: 100%;
|
min-width: 100%;
|
min-height: 100%;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
overflow: auto;
|
}
|
|
.matnr-print-canvas {
|
position: relative;
|
box-sizing: border-box;
|
flex: none;
|
margin: 0 auto;
|
box-shadow: 0 18px 36px rgba(15, 23, 42, 0.08);
|
}
|
|
.matnr-print-canvas--editor {
|
border: 1px solid rgba(148, 163, 184, 0.45);
|
}
|
|
.matnr-print-canvas--grid {
|
background-image:
|
linear-gradient(to right, rgba(148, 163, 184, 0.2) 1px, transparent 1px),
|
linear-gradient(to bottom, rgba(148, 163, 184, 0.2) 1px, transparent 1px);
|
background-size: var(--matnr-print-grid-size) var(--matnr-print-grid-size);
|
}
|
|
.matnr-print-element {
|
position: absolute;
|
box-sizing: border-box;
|
overflow: hidden;
|
user-select: none;
|
}
|
|
.matnr-print-element.is-table {
|
overflow: visible;
|
}
|
|
.matnr-print-element.is-selected {
|
outline: 1px solid #2563eb;
|
outline-offset: 0;
|
}
|
|
.matnr-print-element__text,
|
.matnr-print-element__barcode,
|
.matnr-print-element__qrcode,
|
.matnr-print-element__image,
|
.matnr-print-element__rect,
|
.matnr-print-element__table {
|
width: 100%;
|
height: 100%;
|
}
|
|
.matnr-print-element__text {
|
display: flex;
|
align-items: center;
|
word-break: break-word;
|
white-space: pre-wrap;
|
}
|
|
.matnr-print-element__barcode :deep(svg) {
|
width: 100%;
|
height: 100%;
|
display: block;
|
}
|
|
.matnr-print-element__qrcode {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
}
|
|
.matnr-print-element__qrcode :deep(svg) {
|
width: 100%;
|
height: 100%;
|
}
|
|
.matnr-print-element__image {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
background: rgba(248, 250, 252, 0.6);
|
}
|
|
.matnr-print-element__image img {
|
width: 100%;
|
height: 100%;
|
display: block;
|
user-select: none;
|
pointer-events: none;
|
}
|
|
.matnr-print-element__image-placeholder {
|
width: 100%;
|
height: 100%;
|
border: 1px dashed rgba(148, 163, 184, 0.65);
|
background:
|
linear-gradient(135deg, rgba(226, 232, 240, 0.75), rgba(241, 245, 249, 0.35)),
|
linear-gradient(45deg, rgba(203, 213, 225, 0.35), transparent);
|
}
|
|
.matnr-print-element__line {
|
position: absolute;
|
inset: 0;
|
}
|
|
.matnr-print-element__rect {
|
box-sizing: border-box;
|
}
|
|
.matnr-print-element__table {
|
position: relative;
|
overflow: hidden;
|
}
|
|
.matnr-print-element__table-cell {
|
box-sizing: border-box;
|
vertical-align: middle;
|
}
|
|
.matnr-print-element__table-cell-content {
|
box-sizing: border-box;
|
}
|
|
.matnr-print-element__table-divider {
|
position: absolute;
|
z-index: 2;
|
background: transparent;
|
color: rgba(37, 99, 235, 0.7);
|
transition:
|
color 0.15s ease,
|
opacity 0.15s ease;
|
opacity: 0.95;
|
}
|
|
.matnr-print-element__table-divider::before {
|
position: absolute;
|
content: '';
|
background: currentColor;
|
border-radius: 999px;
|
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.92);
|
}
|
|
.matnr-print-element__table-divider.is-column {
|
top: 0;
|
bottom: 0;
|
width: 12px;
|
transform: translateX(-6px);
|
cursor: ew-resize;
|
}
|
|
.matnr-print-element__table-divider.is-column::before {
|
top: calc(50% - 12px);
|
left: calc(50% - 2px);
|
width: 4px;
|
height: 24px;
|
}
|
|
.matnr-print-element__table-divider.is-row {
|
left: 0;
|
right: 0;
|
height: 12px;
|
transform: translateY(-6px);
|
cursor: ns-resize;
|
}
|
|
.matnr-print-element__table-divider.is-row::before {
|
top: calc(50% - 2px);
|
left: calc(50% - 12px);
|
width: 24px;
|
height: 4px;
|
}
|
|
.matnr-print-element__table-divider:hover {
|
color: rgba(37, 99, 235, 1);
|
opacity: 1;
|
}
|
|
.matnr-print-element__handle {
|
position: absolute;
|
width: 10px;
|
height: 10px;
|
border: 1px solid #2563eb;
|
background: #ffffff;
|
border-radius: 50%;
|
z-index: 3;
|
}
|
|
.matnr-print-element__handle.is-top-left {
|
top: -5px;
|
left: -5px;
|
cursor: nwse-resize;
|
}
|
|
.matnr-print-element__handle.is-top {
|
top: -5px;
|
left: calc(50% - 5px);
|
cursor: ns-resize;
|
}
|
|
.matnr-print-element__handle.is-top-right {
|
top: -5px;
|
right: -5px;
|
cursor: nesw-resize;
|
}
|
|
.matnr-print-element__handle.is-right {
|
top: calc(50% - 5px);
|
right: -5px;
|
cursor: ew-resize;
|
}
|
|
.matnr-print-element__handle.is-bottom-right {
|
right: -5px;
|
bottom: -5px;
|
cursor: nwse-resize;
|
}
|
|
.matnr-print-element__handle.is-bottom {
|
left: calc(50% - 5px);
|
bottom: -5px;
|
cursor: ns-resize;
|
}
|
|
.matnr-print-element__handle.is-bottom-left {
|
left: -5px;
|
bottom: -5px;
|
cursor: nesw-resize;
|
}
|
|
.matnr-print-element__handle.is-left {
|
top: calc(50% - 5px);
|
left: -5px;
|
cursor: ew-resize;
|
}
|
</style>
|