zobrazenie pozicii cisel na mieste kliknutia,
pridane toleracnie 0 pre presny pixel a 1 pre okolie pixela
This commit is contained in:
@@ -10,7 +10,14 @@ const baseName = () => (imageName.value.replace(/\.[^.]+$/, '').replace(/[^\p{L}
|
||||
async function exportPng(): Promise<void> {
|
||||
if (!imageCanvas.value) return store.notify('Najprv načítajte obrázok.', 'warning')
|
||||
try {
|
||||
const canvas = renderExportCanvas(imageCanvas.value, { width: imageWidth.value, height: imageHeight.value }, regions.value, groups.value, settings.value.exportOverlay)
|
||||
const canvas = renderExportCanvas(
|
||||
imageCanvas.value,
|
||||
{ width: imageWidth.value, height: imageHeight.value },
|
||||
regions.value,
|
||||
groups.value,
|
||||
settings.value.exportOverlay,
|
||||
settings.value.useUserClickPositionForLabels,
|
||||
)
|
||||
downloadBlob(await canvasToBlob(canvas), `${baseName()}-ocislovane.png`)
|
||||
} catch (error) { store.notify(error instanceof Error ? error.message : 'Export PNG zlyhal.', 'error') }
|
||||
}
|
||||
@@ -22,9 +29,13 @@ function exportCsv(): void {
|
||||
|
||||
async function exportJson(): Promise<void> {
|
||||
if (!imageWidth.value) return store.notify('Nie je čo exportovať.', 'warning')
|
||||
const project = await store.serializeProject(true)
|
||||
downloadBlob(new Blob([JSON.stringify(project)], { type: 'application/json' }), `${baseName()}-projekt.json`)
|
||||
if (!project.imageDataUrl) store.notify('Obrázok je väčší než 5 MB. Pri importe JSON ho bude potrebné znova vybrať.', 'info')
|
||||
try {
|
||||
const project = await store.serializeProject(true)
|
||||
downloadBlob(new Blob([JSON.stringify(project)], { type: 'application/json' }), `${baseName()}-projekt.json`)
|
||||
if (!project.imageDataUrl) store.notify('Obrázok je väčší než 5 MB. Pri importe JSON ho bude potrebné znova vybrať.', 'info')
|
||||
} catch (error) {
|
||||
store.notify(error instanceof Error ? error.message : 'Export projektu JSON zlyhal.', 'error')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useMosaicStore } from '@/stores/mosaic'
|
||||
import { rgbToHex, relativeLuminance } from '@/utils/colors'
|
||||
import { forEachMaskRun } from '@/utils/regionMask'
|
||||
import { forEachMaskRun, resolveRegionLabelPosition } from '@/utils/regionMask'
|
||||
import { useCanvasViewport } from '@/composables/useCanvasViewport'
|
||||
import ImageDropzone from './ImageDropzone.vue'
|
||||
|
||||
@@ -76,8 +76,9 @@ function draw(): void {
|
||||
const group = groupMap.get(region.groupId)
|
||||
if (!group) continue
|
||||
if (selectedGroupId.value && settings.value.otherGroupsMode === 'hidden' && group.id !== selectedGroupId.value) continue
|
||||
const x = viewport.x + region.labelPosition.x * viewport.scale
|
||||
const y = viewport.y + region.labelPosition.y * viewport.scale
|
||||
const labelPosition = resolveRegionLabelPosition(region, settings.value.useUserClickPositionForLabels)
|
||||
const x = viewport.x + labelPosition.x * viewport.scale
|
||||
const y = viewport.y + labelPosition.y * viewport.scale
|
||||
const active = region.id === selectedRegionId.value
|
||||
context.beginPath()
|
||||
context.arc(x, y, active ? 13 : 11, 0, Math.PI * 2)
|
||||
@@ -133,7 +134,14 @@ function wheel(event: WheelEvent): void {
|
||||
}
|
||||
|
||||
watch([imageCanvas, imageWidth, imageHeight], async () => { await nextTick(); resetViewport() })
|
||||
watch([regions, groups, selectedGroupId, selectedRegionId, () => settings.value.otherGroupsMode], draw, { deep: true })
|
||||
watch([
|
||||
regions,
|
||||
groups,
|
||||
selectedGroupId,
|
||||
selectedRegionId,
|
||||
() => settings.value.otherGroupsMode,
|
||||
() => settings.value.useUserClickPositionForLabels,
|
||||
], draw, { deep: true })
|
||||
|
||||
onMounted(() => {
|
||||
observer = new ResizeObserver(resize)
|
||||
|
||||
@@ -15,7 +15,7 @@ function updateColorTolerance(event: Event): void {
|
||||
<h2>Nastavenia analýzy</h2>
|
||||
<label class="range-field">
|
||||
<span><b>Tolerancia výberu</b><output>{{ settings.floodTolerance }}</output></span>
|
||||
<input v-model.number="settings.floodTolerance" type="range" min="2" max="100" step="1" />
|
||||
<input v-model.number="settings.floodTolerance" type="range" min="0" max="100" step="1" />
|
||||
<small>Vyššia hodnota spojí väčšie farebné odchýlky v jednej ploche.</small>
|
||||
</label>
|
||||
<label class="range-field">
|
||||
@@ -46,6 +46,10 @@ function updateColorTolerance(event: Event): void {
|
||||
<span><b>Prahová tmavosť obrysu</b><output>{{ settings.darkBoundaryThreshold.toFixed(3) }}</output></span>
|
||||
<input v-model.number="settings.darkBoundaryThreshold" type="range" min="0" max="0.2" step="0.005" />
|
||||
</label>
|
||||
<label class="check-field">
|
||||
<input v-model="settings.useUserClickPositionForLabels" type="checkbox" />
|
||||
<span>Zobrazovať čísla na pozícii kliknutia</span>
|
||||
</label>
|
||||
</details>
|
||||
</section>
|
||||
</template>
|
||||
@@ -62,4 +66,5 @@ select { width: 100%; }
|
||||
details { margin-top: 13px; color: #475569; font-size: .76rem; }
|
||||
summary { cursor: pointer; }
|
||||
.compact { margin-bottom: 4px; }
|
||||
.check-field { display: flex; align-items: center; gap: 7px; margin-top: 12px; color: #475569; cursor: pointer; }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user