| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- <template>
- <div class="rectangle-zoom-container" ref="containerRef"></div>
- </template>
- <script>
- import { ref, onMounted, onUnmounted, watch } from 'vue';
- export default {
- name: 'RectangleZoom',
- props: {
- viewer: {
- type: Object,
- required: true
- },
- enabled: {
- type: Boolean,
- default: true
- },
- lineColor: {
- type: String,
- default: '#00aaff'
- },
- fillColor: {
- type: String,
- default: 'rgba(0, 170, 255, 0.2)'
- },
- lineWidth: {
- type: Number,
- default: 2
- },
- minSize: {
- type: Number,
- default: 10
- }
- },
- setup(props) {
- const containerRef = ref(null);
- let canvas = null;
- let ctx = null;
- let isDrawing = false;
- let isShiftDown = false;
- let startX = 0;
- let startY = 0;
- let currentX = 0;
- let currentY = 0;
- const initCanvas = () => {
- if (!props.viewer || !props.viewer.container) return;
-
- const container = props.viewer.container;
-
- const existingCanvas = document.getElementById('rectangle-zoom-canvas');
- if (existingCanvas) {
- existingCanvas.parentNode.removeChild(existingCanvas);
- }
-
- canvas = document.createElement('canvas');
- canvas.id = 'rectangle-zoom-canvas';
- canvas.style.position = 'absolute';
- canvas.style.top = '0';
- canvas.style.left = '0';
- canvas.style.width = '100%';
- canvas.style.height = '100%';
- canvas.style.pointerEvents = 'none';
- canvas.style.zIndex = '1000';
- container.appendChild(canvas);
-
- ctx = canvas.getContext('2d');
- resizeCanvas();
- };
- const resizeCanvas = () => {
- if (!canvas || !props.viewer || !props.viewer.container) return;
- const rect = props.viewer.container.getBoundingClientRect();
- canvas.width = rect.width;
- canvas.height = rect.height;
- };
- const drawRectangle = () => {
- if (!ctx) return;
-
- ctx.clearRect(0, 0, canvas.width, canvas.height);
-
- if (!isDrawing) return;
-
- const x = Math.min(startX, currentX);
- const y = Math.min(startY, currentY);
- const width = Math.abs(currentX - startX);
- const height = Math.abs(currentY - startY);
-
- ctx.beginPath();
- ctx.strokeStyle = props.lineColor;
- ctx.lineWidth = props.lineWidth;
- ctx.setLineDash([8, 4]);
- ctx.strokeRect(x, y, width, height);
-
- ctx.fillStyle = props.fillColor;
- ctx.fillRect(x, y, width, height);
-
- ctx.setLineDash([]);
- };
- const getRectangleExtent = () => {
- if (!props.viewer || !props.viewer.scene || !props.viewer.scene.globe) return null;
- const x1 = Math.min(startX, currentX);
- const y1 = Math.min(startY, currentY);
- const x2 = Math.max(startX, currentX);
- const y2 = Math.max(startY, currentY);
- const scene = props.viewer.scene;
- const camera = props.viewer.camera;
- const globe = scene.globe;
- const corners = [
- [x1, y1], [x2, y1], [x2, y2], [x1, y2]
- ];
- let lons = [];
- let lats = [];
- for (const [cx, cy] of corners) {
- const ray = camera.getPickRay(new Cesium.Cartesian2(cx, cy));
- if (!ray) continue;
- let cartesian;
- if (globe) {
- cartesian = globe.pick(ray, scene);
- }
- if (!cartesian) {
- cartesian = camera.pickEllipsoid(new Cesium.Cartesian2(cx, cy), Cesium.Ellipsoid.WGS84);
- }
- if (!cartesian) continue;
- const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
- lons.push(cartographic.longitude);
- lats.push(cartographic.latitude);
- }
- if (lons.length === 0) return null;
- return {
- west: Math.min(...lons),
- east: Math.max(...lons),
- south: Math.min(...lats),
- north: Math.max(...lats)
- };
- };
- const flyToExtent = (extent) => {
- if (!extent || !props.viewer) return;
- const rectangle = Cesium.Rectangle.fromRadians(
- extent.west, extent.south, extent.east, extent.north
- );
- props.viewer.camera.flyTo({
- destination: rectangle,
- duration: 1.0,
- easingFunction: Cesium.EasingFunction.QUADRATIC_IN_OUT
- });
- };
- const setCanvasCapture = (capture) => {
- if (!canvas) return;
- canvas.style.pointerEvents = capture ? 'auto' : 'none';
- };
- const setCursor = (cursor) => {
- if (canvas) {
- canvas.style.cursor = cursor;
- }
- if (!props.viewer) return;
- if (props.viewer.container) {
- props.viewer.container.style.cursor = cursor;
- }
- if (props.viewer.scene && props.viewer.scene.canvas) {
- props.viewer.scene.canvas.style.cursor = cursor;
- }
- };
- const clearCursorOverride = () => {
- if (canvas) {
- canvas.style.cursor = '';
- }
- if (!props.viewer) return;
- if (props.viewer.container) {
- props.viewer.container.style.cursor = '';
- }
- if (props.viewer.scene && props.viewer.scene.canvas) {
- props.viewer.scene.canvas.style.cursor = '';
- }
- };
- const getCanvasPos = (clientX, clientY) => {
- if (!canvas) return null;
- const rect = canvas.getBoundingClientRect();
- return new Cesium.Cartesian2(clientX - rect.left, clientY - rect.top);
- };
- const handleMouseDown = (event) => {
- if (!props.enabled) return;
- if (event.button !== 0) return;
- if (!isShiftDown) return;
- const pos = getCanvasPos(event.clientX, event.clientY);
- if (!pos) return;
- startX = pos.x;
- startY = pos.y;
- currentX = pos.x;
- currentY = pos.y;
- isDrawing = true;
- };
- const handleMouseMove = (event) => {
- if (!isDrawing) return;
- const pos = getCanvasPos(event.clientX, event.clientY);
- if (!pos) return;
- currentX = pos.x;
- currentY = pos.y;
- drawRectangle();
- };
- const endDrawing = () => {
- if (!isDrawing) return;
- if (!ctx) return;
- const width = Math.abs(currentX - startX);
- const height = Math.abs(currentY - startY);
- if (width >= props.minSize && height >= props.minSize) {
- const extent = getRectangleExtent();
- if (extent) {
- flyToExtent(extent);
- }
- }
- ctx.clearRect(0, 0, canvas.width, canvas.height);
- isDrawing = false;
- };
- const handleMouseUp = (event) => {
- if (!isDrawing) return;
- if (event.button !== 0) return;
- const pos = getCanvasPos(event.clientX, event.clientY);
- if (pos) {
- currentX = pos.x;
- currentY = pos.y;
- }
- endDrawing();
- };
- const handleKeyDown = (event) => {
- if (event.key === 'Shift' || event.key === 'ShiftLeft' || event.key === 'ShiftRight') {
- isShiftDown = true;
- setCanvasCapture(true);
- setCursor('crosshair');
- }
- };
- const handleKeyUp = (event) => {
- if (event.key === 'Shift' || event.key === 'ShiftLeft' || event.key === 'ShiftRight') {
- isShiftDown = false;
- endDrawing();
- setCanvasCapture(false);
- clearCursorOverride();
- }
- };
- const addEventListeners = () => {
- if (!canvas) return;
- canvas.addEventListener('mousedown', handleMouseDown);
- canvas.addEventListener('mousemove', handleMouseMove);
- canvas.addEventListener('mouseup', handleMouseUp);
- canvas.addEventListener('mouseleave', endDrawing);
- window.addEventListener('mouseup', handleMouseUp);
- window.addEventListener('keydown', handleKeyDown);
- window.addEventListener('keyup', handleKeyUp);
- window.addEventListener('resize', resizeCanvas);
- };
- const removeEventListeners = () => {
- if (canvas) {
- canvas.removeEventListener('mousedown', handleMouseDown);
- canvas.removeEventListener('mousemove', handleMouseMove);
- canvas.removeEventListener('mouseup', handleMouseUp);
- canvas.removeEventListener('mouseleave', endDrawing);
- }
- window.removeEventListener('mouseup', handleMouseUp);
- window.removeEventListener('keydown', handleKeyDown);
- window.removeEventListener('keyup', handleKeyUp);
- window.removeEventListener('resize', resizeCanvas);
- };
- const destroyCanvas = () => {
- if (canvas && canvas.parentNode) {
- canvas.parentNode.removeChild(canvas);
- canvas = null;
- ctx = null;
- }
- };
- onMounted(() => {
- if (props.enabled) {
- initCanvas();
- addEventListeners();
- }
- });
- onUnmounted(() => {
- removeEventListeners();
- destroyCanvas();
- });
- watch(() => props.enabled, (newVal) => {
- if (newVal) {
- initCanvas();
- addEventListeners();
- } else {
- removeEventListeners();
- destroyCanvas();
- }
- });
- return {
- containerRef
- };
- }
- };
- </script>
- <style scoped>
- .rectangle-zoom-container {
- display: none;
- }
- </style>
|