✨ new maps
This commit is contained in:
@@ -5,109 +5,232 @@
|
||||
:class="{
|
||||
'map-control--over': isDragOver
|
||||
}"
|
||||
@onDrop="onDrop"
|
||||
@dropFile="onDrop"
|
||||
@mousewheel="onScroll"
|
||||
@mousedown="onMouseDown"
|
||||
>
|
||||
<div ref="rendererWrapper">
|
||||
<MapRenderer
|
||||
ref="renderer"
|
||||
:layers="layers"
|
||||
:width="3840"
|
||||
:height="2160"
|
||||
:offsetX="offsetX"
|
||||
:offsetY="offsetY"
|
||||
:dpi="300"
|
||||
/>
|
||||
<button @click="reset()">reset</button>
|
||||
<select v-model="mode">
|
||||
<option value="drag">drag</option>
|
||||
<option value="draw">draw</option>
|
||||
<option value="measure">measure</option>
|
||||
</select>
|
||||
<select
|
||||
v-if="canvasDisplay?.mapLayer"
|
||||
v-model="canvasDisplay.mapLayer.grid"
|
||||
>
|
||||
<option value="none">no grid</option>
|
||||
<option value="light">light grid</option>
|
||||
<option value="dark">dark grid</option>
|
||||
</select>
|
||||
<select
|
||||
v-if="canvasDisplay?.mapLayer"
|
||||
v-model="canvasDisplay.mapLayer.rotation"
|
||||
>
|
||||
<option :value="0">0°</option>
|
||||
<option :value="1">90°</option>
|
||||
<option :value="2">180°</option>
|
||||
<option :value="3">270°</option>
|
||||
</select>
|
||||
<input
|
||||
v-if="canvasDisplay?.mapLayer"
|
||||
type="number"
|
||||
v-model="canvasDisplay.mapLayer.mapWidthInInches"
|
||||
/>
|
||||
<div ref="rendererWrapper" v-show="canvasDisplay">
|
||||
<canvas :width="selectedScreen?.imageSink?.resolution.width" :height="selectedScreen?.imageSink?.resolution.height" ref="canvas" style="max-width: 100%;" />
|
||||
</div>
|
||||
</Dropzone>
|
||||
<button @click="onLoad">load</button>
|
||||
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {inject, onMounted, ref} from 'vue';
|
||||
import {computed, inject, onBeforeUnmount, onMounted, reactive, ref} from 'vue';
|
||||
import Dropzone from '../Dropzone/Dropzone.vue';
|
||||
import MapRenderer from './MapRenderer.vue';
|
||||
import {MountedFsSymbol} from '../../model/injectionSymbols';
|
||||
import {MapDrawable, MapImage} from './helpers';
|
||||
import {MountedFsSymbol, RemoteDeviceManagerSymbol} from '../../model/injectionSymbols';
|
||||
import {closerToZero, MapDrawable, MapImage} from './helpers';
|
||||
import {VirtualFile} from '../../model/FileSystem/types';
|
||||
import {CanvasDisplay, MapLayerDrawable} from './object';
|
||||
import {Devices} from '../../model/Remote/RemoteDeviceManager';
|
||||
|
||||
const fs = inject(MountedFsSymbol)!;
|
||||
const layers = ref<MapDrawable[]>([])
|
||||
const renderer = ref<MapRenderer>();
|
||||
const rendererWrapper = ref<HTMLDivElement>();
|
||||
const scale = ref(1);
|
||||
const offsetX = ref(0);
|
||||
const offsetY = ref(0);
|
||||
const remoteManager = inject(RemoteDeviceManagerSymbol)!;
|
||||
|
||||
const screens = computed(() => {
|
||||
return remoteManager.devices
|
||||
.filter(device => device.hasImageSink)
|
||||
})
|
||||
|
||||
const canvas = ref<HTMLCanvasElement>();
|
||||
const selectedScreen = ref<Devices>();
|
||||
const pointerVisible = ref(false);
|
||||
let canvasDisplay: undefined | CanvasDisplay;
|
||||
|
||||
function selectScreen (screen: any) {
|
||||
if (screen.imageSink?.display) {
|
||||
selectedScreen.value = screen;
|
||||
console.log('selectScreen!!!', screen.imageSink?.display);
|
||||
canvasDisplay?.disconnectTarget(canvas.value!);
|
||||
canvasDisplay = screen.imageSink?.display;
|
||||
canvasDisplay?.connectTarget(canvas.value!);
|
||||
}
|
||||
}
|
||||
|
||||
async function onDrop(file: VirtualFile) {
|
||||
const data = await fs.download(file);
|
||||
console.log('file', file, data);
|
||||
console.log('onDrop!!', file);
|
||||
onLoad(file);
|
||||
}
|
||||
|
||||
const mode = ref<'drag' | 'draw'>('drag');
|
||||
|
||||
async function onLoad() {
|
||||
const newLayers = [];
|
||||
const map: VirtualFile = {
|
||||
"type": "file",
|
||||
"source": "Maps",
|
||||
"name": "G_AbandonedMineEntrance_EscapedDragon_Night.jpg",
|
||||
"mimeType": "image/jpeg",
|
||||
"path": [
|
||||
"Abandoned Mine Entrance [33x21] - $5 Rewards",
|
||||
"Gridded",
|
||||
"G_AbandonedMineEntrance_EscapedDragon_Night.jpg"
|
||||
],
|
||||
"map": {
|
||||
"width": 33,
|
||||
"height": 21,
|
||||
"valid": true,
|
||||
"animated": false
|
||||
}
|
||||
}
|
||||
|
||||
const mapFile = await fs.download(map);
|
||||
const mapLayer = await MapImage.fromImageFile(mapFile, {
|
||||
gameDimensions: {w: 33, h: 21},
|
||||
});
|
||||
newLayers.push(mapLayer);
|
||||
layers.value = newLayers;
|
||||
}
|
||||
|
||||
|
||||
const mode = ref<'drag' | 'draw' | 'measure'>('drag');
|
||||
const dragging = ref(false);
|
||||
|
||||
function onMouseMove(event: MouseEvent) {
|
||||
const mouseScale = rendererWrapper.value!.clientWidth / 3840;
|
||||
console.log(renderer.value)
|
||||
if (dragging.value) {
|
||||
offsetX.value += event.movementX / mouseScale;
|
||||
offsetY.value += event.movementY / mouseScale;
|
||||
|
||||
|
||||
function onScroll(event: WheelEvent) {
|
||||
event.preventDefault();
|
||||
// console.log('scroll', event.deltaY, event.offsetX, event.offsetY);
|
||||
const delta = -1 * event.deltaY / 2000;
|
||||
if (!canvasDisplay) {
|
||||
return;
|
||||
}
|
||||
canvasDisplay.scale = Math.min(Math.max(0.1, canvasDisplay.scale + delta), 10);
|
||||
|
||||
if (canvas.value) {
|
||||
if (delta > 0) {
|
||||
const displayMousePosition = {
|
||||
x: ((event.offsetX / canvas.value!.width) - 0.5) * 2 * canvasDisplay.width,
|
||||
y: ((event.offsetY / canvas.value!.height) - 0.5) * 2 * canvasDisplay.height,
|
||||
};
|
||||
canvasDisplay.offsetX += displayMousePosition.x * delta;
|
||||
canvasDisplay.offsetY += displayMousePosition.y * delta;
|
||||
} else {
|
||||
canvasDisplay.offsetX -= closerToZero((canvasDisplay.width * Math.abs(delta)) * Math.sign(canvasDisplay.offsetX), canvasDisplay.offsetX);
|
||||
canvasDisplay.offsetY -= closerToZero((canvasDisplay.height * Math.abs(delta)) * Math.sign(canvasDisplay.offsetY), canvasDisplay.offsetY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseUp(event: MouseEvent) {
|
||||
console.log('mouse up', event);
|
||||
dragging.value = false;
|
||||
window.removeEventListener('mousemove', onMouseMove);
|
||||
window.removeEventListener('mouseup', onMouseUp);
|
||||
function showPointer(show: boolean) {
|
||||
pointerVisible.value = show;
|
||||
if (canvasDisplay && !show) {
|
||||
canvasDisplay.distanceMeasurement.pointer = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseDown(event: MouseEvent) {
|
||||
console.log('mouse down', event);
|
||||
dragging.value = true;
|
||||
window.addEventListener('mousemove', onMouseMove);
|
||||
window.getSelection()?.removeAllRanges();
|
||||
if (mode.value === 'drag') {
|
||||
dragging.value = true;
|
||||
}
|
||||
if (mode.value === 'measure') {
|
||||
if (canvasDisplay) {
|
||||
const mouseScale = canvas.value!.clientWidth / canvasDisplay.width;
|
||||
canvasDisplay.distanceMeasurement.start = {x: event.offsetX / mouseScale, y: event.offsetY / mouseScale}
|
||||
}
|
||||
}
|
||||
window.addEventListener('mouseup', onMouseUp);
|
||||
}
|
||||
|
||||
function onMouseUp(event: MouseEvent) {
|
||||
dragging.value = false;
|
||||
|
||||
window.removeEventListener('mouseup', onMouseUp);
|
||||
if (mode.value === 'measure' && canvasDisplay) {
|
||||
canvasDisplay.distanceMeasurement.start = undefined;
|
||||
}
|
||||
}
|
||||
function onMouseMove(event: MouseEvent) {
|
||||
if (pointerVisible.value && canvasDisplay) {
|
||||
const mouseScale = canvas.value!.clientWidth / canvasDisplay.width;
|
||||
if (canvasDisplay) {
|
||||
canvasDisplay.distanceMeasurement.pointer = {x: event.offsetX / mouseScale, y: event.offsetY / mouseScale};
|
||||
}
|
||||
}
|
||||
|
||||
if (event.buttons === 0) {
|
||||
onMouseUp(event);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!canvasDisplay) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mouseScale = canvas.value!.clientWidth / canvasDisplay.width;
|
||||
|
||||
if (dragging.value) {
|
||||
canvasDisplay.offsetX -= event.movementX / mouseScale;
|
||||
canvasDisplay.offsetY -= event.movementY / mouseScale;
|
||||
}
|
||||
if (mode.value === 'measure') {
|
||||
if (canvasDisplay) {
|
||||
canvasDisplay.distanceMeasurement.end = {x: event.offsetX / mouseScale, y: event.offsetY / mouseScale};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function reset() {
|
||||
if (!canvasDisplay) {
|
||||
return;
|
||||
}
|
||||
canvasDisplay.offsetX = 0;
|
||||
canvasDisplay.offsetY = 0;
|
||||
canvasDisplay.scale = 1;
|
||||
}
|
||||
|
||||
function onKeydown(event: KeyboardEvent) {
|
||||
if (event.key === 'Control') {
|
||||
showPointer(true);
|
||||
}
|
||||
}
|
||||
|
||||
function onKeyup(event: KeyboardEvent) {
|
||||
if (event.key === 'Control') {
|
||||
showPointer(false);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
onLoad();
|
||||
canvasDisplay?.connectTarget(canvas.value!);
|
||||
window.addEventListener('reveal-screen', (event: CustomEvent) => {
|
||||
selectScreen(event.detail);
|
||||
});
|
||||
|
||||
window.addEventListener('keydown', onKeydown);
|
||||
window.addEventListener('keyup', onKeyup);
|
||||
window.addEventListener('mousemove', onMouseMove);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
canvasDisplay?.disconnectTarget(canvas.value!);
|
||||
window.removeEventListener('keydown', onKeydown);
|
||||
window.removeEventListener('keyup', onKeyup);
|
||||
window.removeEventListener('mousemove', onMouseMove);
|
||||
});
|
||||
|
||||
async function onLoad(file?: VirtualFile | File) {
|
||||
const meta = file;
|
||||
if (!canvasDisplay) {
|
||||
return;
|
||||
}
|
||||
if (!(file instanceof File) && file?.type === 'file') {
|
||||
file = await fs.download(file);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
console.log('onLoad', file, meta?.map?.width);
|
||||
// @ts-ignore
|
||||
const layer = new MapLayerDrawable(file, meta?.map?.width);
|
||||
await layer.preloadFile();
|
||||
canvasDisplay.mapLayer = layer;
|
||||
};
|
||||
|
||||
</script>
|
||||
<style lang="css">
|
||||
.map-control {
|
||||
display: inline-block;
|
||||
border: 1px solid black;
|
||||
border: 1px solid white;
|
||||
background: white;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user