camera.vue 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. <script setup lang="ts">
  2. import Camera from '@/assets/camera.html?url';
  3. import { DEFAULT_HEIGHT, DEFAULT_WIDTH, DEFAULT_ZOOM } from '@/modules/camera/camera.config';
  4. const {
  5. preview = true,
  6. scale = 1,
  7. offsetX = 0,
  8. offsetY = 0,
  9. } = defineProps<{
  10. scale?: number;
  11. offsetX?: number;
  12. offsetY?: number;
  13. preview?: boolean;
  14. }>();
  15. const emits = defineEmits<{ loaded: [] }>();
  16. const style = computed(() => `width: ${scale * DEFAULT_WIDTH}px;height: ${scale * DEFAULT_HEIGHT}px;`);
  17. const snapshot = ref<string | void>();
  18. const cameraFrameRef = useTemplateRef<
  19. HTMLIFrameElement & {
  20. contentWindow: {
  21. loadCamera(props: { width: number; height: number; zoom?: number }): Promise<void>;
  22. handle(promise?: Promise<void>): string;
  23. updateCoordinate(offsetX: number, offsetY: number): void;
  24. };
  25. }
  26. >('camera-frame');
  27. const loadCamera = async () => {
  28. await cameraFrameRef.value?.contentWindow.loadCamera?.({
  29. width: DEFAULT_WIDTH,
  30. height: DEFAULT_HEIGHT,
  31. zoom: DEFAULT_ZOOM,
  32. });
  33. cameraFrameRef.value?.contentWindow.addEventListener('resize', update);
  34. emits('loaded');
  35. };
  36. watch([() => offsetX, () => offsetY], () => { setTimeout(update, 100); });
  37. function update() {
  38. cameraFrameRef.value?.contentWindow.updateCoordinate?.(offsetX, offsetY);
  39. }
  40. defineExpose({
  41. handle() {
  42. if ( !preview || !snapshot.value ) {
  43. snapshot.value = cameraFrameRef.value?.contentWindow.handle?.();
  44. } else {
  45. snapshot.value = void 0;
  46. }
  47. return snapshot.value;
  48. },
  49. });
  50. </script>
  51. <template>
  52. <div class="relative camera-container" :style="style">
  53. <iframe ref="camera-frame" :src="Camera" @load="loadCamera()"></iframe>
  54. <img v-if="snapshot" :src="snapshot" alt="图像" />
  55. <slot name="shade" :style="style" :scale="scale"></slot>
  56. </div>
  57. </template>
  58. <style scoped lang="scss">
  59. .camera-container {
  60. iframe {
  61. clip-path: url('#shade');
  62. }
  63. img {
  64. object-fit: scale-down;
  65. }
  66. > * {
  67. position: absolute;
  68. width: 100%;
  69. height: 100%;
  70. }
  71. }
  72. </style>