add selection tool

This commit is contained in:
2025-10-20 17:52:50 +09:00
parent 6d31e1f37a
commit 2180afa529
4 changed files with 50 additions and 33 deletions

View File

@ -4,7 +4,7 @@ import { saveFeatures } from '../mapUtils';
import { Button, Tooltip } from '@fluentui/react-components'; import { Button, Tooltip } from '@fluentui/react-components';
import { useAppStore } from '../../../store/app'; import { useAppStore } from '../../../store/app';
import { useObjectsStore } from '../../../store/objects'; import { useObjectsStore } from '../../../store/objects';
import { AddFilled, RulerRegular, SubtractFilled } from '@fluentui/react-icons'; import { AddFilled, RulerRegular, SelectObjectRegular, SelectObjectSkewEditRegular, SubtractFilled } from '@fluentui/react-icons';
const MapToolbar = ({ const MapToolbar = ({
map_id map_id
@ -25,11 +25,17 @@ const MapToolbar = ({
</Tooltip> </Tooltip>
<Tooltip content={"Редактировать"} relationship='label' hideDelay={0} showDelay={0} withArrow> <Tooltip content={"Редактировать"} relationship='label' hideDelay={0} showDelay={0} withArrow>
<Button icon={<IconTransformPoint />} appearance={currentTool === 'Edit' ? 'primary' : 'transparent'} onClick={() => { <Button icon={<SelectObjectSkewEditRegular />} appearance={currentTool === 'Edit' ? 'primary' : 'transparent'} onClick={() => {
setCurrentTool(map_id, 'Edit') setCurrentTool(map_id, 'Edit')
}} /> }} />
</Tooltip> </Tooltip>
<Tooltip content={"Выделение"} relationship='label' hideDelay={0} showDelay={0} withArrow>
<Button icon={<SelectObjectRegular />} appearance={currentTool === 'Selection' ? 'primary' : 'transparent'} onClick={() => {
setCurrentTool(map_id, 'Selection')
}} />
</Tooltip>
<Tooltip content={"Точка"} relationship='label' hideDelay={0} showDelay={0} withArrow> <Tooltip content={"Точка"} relationship='label' hideDelay={0} showDelay={0} withArrow>
<Button icon={<IconPoint />} appearance={currentTool === 'Point' ? 'primary' : 'transparent'} onClick={() => { <Button icon={<IconPoint />} appearance={currentTool === 'Point' ? 'primary' : 'transparent'} onClick={() => {
setCurrentTool(map_id, 'Point') setCurrentTool(map_id, 'Point')

View File

@ -15,13 +15,13 @@ import { ImageStatic } from "ol/source";
import { IFigure, ILine } from "../../interfaces/gis"; import { IFigure, ILine } from "../../interfaces/gis";
import { fromCircle, fromExtent } from "ol/geom/Polygon"; import { fromCircle, fromExtent } from "ol/geom/Polygon";
import { measureStyleFunction, modifyStyle } from "./Measure/MeasureStyles"; import { measureStyleFunction, modifyStyle } from "./Measure/MeasureStyles";
import { getCurrentTool, getDraw, getDrawingLayerSource, getImageLayer, getMap, getMeasureClearPrevious, getMeasureDraw, getMeasureModify, getMeasureSource, getMeasureType, getOverlayLayerSource, getSnap, getTipPoint, getTranslate, PrintOrientation, setDraw, setFile, setMeasureDraw, setPolygonExtent, setRectCoords, setSnap, setTranslate } from "../../store/map"; import { getCurrentTool, getDraw, getDrawingLayerSource, getImageLayer, getMap, getMeasureClearPrevious, getMeasureDraw, getMeasureModify, getMeasureSource, getMeasureType, getOverlayLayerSource, getSelectionDragBox, getSnap, getTipPoint, getTranslate, PrintOrientation, setDraw, setFile, setMeasureDraw, setPolygonExtent, setRectCoords, setSnap, setTranslate, useMapStore } from "../../store/map";
import Collection from "ol/Collection"; import Collection from "ol/Collection";
import { SketchCoordType } from "ol/interaction/Draw"; import { SketchCoordType } from "ol/interaction/Draw";
import VectorImageLayer from "ol/layer/VectorImage"; import VectorImageLayer from "ol/layer/VectorImage";
import VectorSource from "ol/source/Vector"; import VectorSource from "ol/source/Vector";
const calculateAngle = (coords: [number, number][]) => { export const calculateAngle = (coords: [number, number][]) => {
const [start, end] = coords; const [start, end] = coords;
const dx = end[0] - start[0]; const dx = end[0] - start[0];
const dy = end[1] - start[1]; const dy = end[1] - start[1];
@ -390,7 +390,9 @@ export const addInteractions = (
const map = getMap(map_id) const map = getMap(map_id)
const measureModify = getMeasureModify(map_id) const measureModify = getMeasureModify(map_id)
if (currentTool !== 'Measure' && currentTool !== 'Mover' && currentTool !== 'Edit') { if (currentTool !== 'Measure' && currentTool !== 'Mover' && currentTool !== 'Edit' && currentTool !== 'Selection') {
map?.getInteractions().clear()
setDraw(map_id, new Draw({ setDraw(map_id, new Draw({
source: getDrawingLayerSource(map_id), source: getDrawingLayerSource(map_id),
type: currentTool as Type, type: currentTool as Type,
@ -430,6 +432,8 @@ export const addInteractions = (
} }
if (currentTool == 'Measure') { if (currentTool == 'Measure') {
map?.getInteractions().clear()
const drawType = measureType; const drawType = measureType;
const activeTip = const activeTip =
'Кликните, чтобы продолжить рисовать ' + 'Кликните, чтобы продолжить рисовать ' +
@ -474,6 +478,7 @@ export const addInteractions = (
const translate = getTranslate(map_id) const translate = getTranslate(map_id)
if (translate) { if (translate) {
map?.getInteractions().clear()
map?.addInteraction(translate) map?.addInteraction(translate)
} }
} }
@ -482,6 +487,17 @@ export const addInteractions = (
//const modify = new Modify() //const modify = new Modify()
//map?.current?.addInteraction(translate.current) //map?.current?.addInteraction(translate.current)
} }
if (currentTool == 'Selection') {
console.log("Selection tool selected")
map?.getInteractions().clear()
const selectionDragBox = useMapStore.getState().id[map_id].selectionDragBox
if (selectionDragBox) {
map?.addInteraction(selectionDragBox)
}
}
} }
export const zoomToFeature = (map_id: string, feature: Feature | undefined) => { export const zoomToFeature = (map_id: string, feature: Feature | undefined) => {
@ -525,7 +541,7 @@ export const loadFeatures = (map_id: string) => {
} }
} }
function rotateProjection(projection: ProjectionLike, angle: number, extent: Extent) { export function rotateProjection(projection: ProjectionLike, angle: number, extent: Extent) {
function rotateCoordinate(coordinate: Coordinate, angle: number, anchor: Coordinate) { function rotateCoordinate(coordinate: Coordinate, angle: number, anchor: Coordinate) {
const coord = rotate( const coord = rotate(
[coordinate[0] - anchor[0], coordinate[1] - anchor[1]], [coordinate[0] - anchor[0], coordinate[1] - anchor[1]],
@ -606,13 +622,13 @@ function rotateProjection(projection: ProjectionLike, angle: number, extent: Ext
} }
} }
const calculateCentroid = (bottomLeft: Coordinate, topLeft: Coordinate, topRight: Coordinate, bottomRight: Coordinate) => { export const calculateCentroid = (bottomLeft: Coordinate, topLeft: Coordinate, topRight: Coordinate, bottomRight: Coordinate) => {
const x = (bottomLeft[0] + topLeft[0] + topRight[0] + bottomRight[0]) / 4; const x = (bottomLeft[0] + topLeft[0] + topRight[0] + bottomRight[0]) / 4;
const y = (bottomLeft[1] + topLeft[1] + topRight[1] + bottomRight[1]) / 4; const y = (bottomLeft[1] + topLeft[1] + topRight[1] + bottomRight[1]) / 4;
return [x, y]; return [x, y];
} }
function calculateRotationAngle(bottomLeft: Coordinate, bottomRight: Coordinate) { export function calculateRotationAngle(bottomLeft: Coordinate, bottomRight: Coordinate) {
// Calculate the difference in x and y coordinates between bottom right and bottom left // Calculate the difference in x and y coordinates between bottom right and bottom left
const deltaX = bottomRight[0] - bottomLeft[0]; const deltaX = bottomRight[0] - bottomLeft[0];
const deltaY = bottomRight[1] - bottomLeft[1]; const deltaY = bottomRight[1] - bottomLeft[1];
@ -623,7 +639,7 @@ function calculateRotationAngle(bottomLeft: Coordinate, bottomRight: Coordinate)
return angle; return angle;
} }
function calculateExtent(bottomLeft: Coordinate, topLeft: Coordinate, topRight: Coordinate, bottomRight: Coordinate) { export function calculateExtent(bottomLeft: Coordinate, topLeft: Coordinate, topRight: Coordinate, bottomRight: Coordinate) {
const width = distance(bottomLeft, bottomRight); const width = distance(bottomLeft, bottomRight);
const height = distance(bottomLeft, topLeft); const height = distance(bottomLeft, topLeft);
@ -641,19 +657,19 @@ function calculateExtent(bottomLeft: Coordinate, topLeft: Coordinate, topRight:
return extent; return extent;
} }
function getTilesPerSide(zoom: number) { export function getTilesPerSide(zoom: number) {
return Math.pow(2, zoom) return Math.pow(2, zoom)
} }
function normalize(value: number, min: number, max: number) { export function normalize(value: number, min: number, max: number) {
return (value - min) / (max - min) return (value - min) / (max - min)
} }
function getTileIndex(normalized: number, tilesPerSide: number) { export function getTileIndex(normalized: number, tilesPerSide: number) {
return Math.floor(normalized * tilesPerSide) return Math.floor(normalized * tilesPerSide)
} }
function getGridCellPosition(x: number, y: number, extent: Extent, zoom: number) { export function getGridCellPosition(x: number, y: number, extent: Extent, zoom: number) {
const tilesPerSide = getTilesPerSide(zoom); const tilesPerSide = getTilesPerSide(zoom);
const minX = extent[0] const minX = extent[0]
const minY = extent[1] const minY = extent[1]
@ -671,7 +687,7 @@ function getGridCellPosition(x: number, y: number, extent: Extent, zoom: number)
return { tileX, tileY }; return { tileX, tileY };
} }
function calculateTransformations(alignPoints: Coordinate[]) { export function calculateTransformations(alignPoints: Coordinate[]) {
const [P1, P2, P3, P4] = alignPoints; const [P1, P2, P3, P4] = alignPoints;
// Translation vector (move P1 to P3) // Translation vector (move P1 to P3)
@ -690,7 +706,7 @@ function calculateTransformations(alignPoints: Coordinate[]) {
return { translation, scale, rotation }; return { translation, scale, rotation };
} }
function calculateCenter(geometry: SimpleGeometry) { export function calculateCenter(geometry: SimpleGeometry) {
let center, coordinates, minRadius; let center, coordinates, minRadius;
const type = geometry.getType(); const type = geometry.getType();
if (type === 'Polygon') { if (type === 'Polygon') {
@ -733,7 +749,7 @@ function calculateCenter(geometry: SimpleGeometry) {
}; };
} }
function applyTransformations( export function applyTransformations(
layer: VectorLayer, layer: VectorLayer,
transformations: { transformations: {
translation: number[]; translation: number[];
@ -764,17 +780,3 @@ function applyTransformations(
console.log("Transformations applied to figuresLayer"); console.log("Transformations applied to figuresLayer");
} }
export {
rotateProjection,
calculateTransformations,
calculateRotationAngle,
calculateExtent,
calculateCentroid,
getTilesPerSide,
normalize,
getTileIndex,
getGridCellPosition,
calculateCenter,
applyTransformations
}

View File

@ -8,7 +8,7 @@ import { TypeRole } from '../interfaces/gis';
import VectorSource from 'ol/source/Vector'; import VectorSource from 'ol/source/Vector';
import Feature from 'ol/Feature'; import Feature from 'ol/Feature';
import { containsExtent, Extent } from 'ol/extent'; import { containsExtent, Extent } from 'ol/extent';
import { Draw, Modify, Select, Snap, Translate } from 'ol/interaction'; import { DragBox, Draw, Modify, Select, Snap, Translate } from 'ol/interaction';
import TileLayer from 'ol/layer/Tile'; import TileLayer from 'ol/layer/Tile';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { googleMapsSatelliteSource } from '../components/map/MapSources'; import { googleMapsSatelliteSource } from '../components/map/MapSources';
@ -18,7 +18,7 @@ import ImageLayer from 'ol/layer/Image';
import { drawingLayerStyle, figureStyle, highlightStyleRed, highlightStyleYellow, lineStyle, overlayStyle, regionsLayerStyle, selectStyle } from '../components/map/MapStyles'; import { drawingLayerStyle, figureStyle, highlightStyleRed, highlightStyleYellow, lineStyle, overlayStyle, regionsLayerStyle, selectStyle } from '../components/map/MapStyles';
import { Fill, Stroke, Style } from 'ol/style'; import { Fill, Stroke, Style } from 'ol/style';
import { VectorImage } from 'ol/layer'; import { VectorImage } from 'ol/layer';
import { click, pointerMove } from 'ol/events/condition'; import { click, noModifierKeys, pointerMove } from 'ol/events/condition';
import { measureStyleFunction, modifyStyle } from '../components/map/Measure/MeasureStyles'; import { measureStyleFunction, modifyStyle } from '../components/map/Measure/MeasureStyles';
import MapBrowserEvent from 'ol/MapBrowserEvent'; import MapBrowserEvent from 'ol/MapBrowserEvent';
import { get, transform } from 'ol/proj'; import { get, transform } from 'ol/proj';
@ -96,6 +96,7 @@ interface MapState {
printOrientation: PrintOrientation; printOrientation: PrintOrientation;
printScale: PrintScale; printScale: PrintScale;
printScaleLine: boolean; printScaleLine: boolean;
selectionDragBox: DragBox;
}>; }>;
} }
@ -267,6 +268,10 @@ export const initializeMapState = (
} }
}) })
const selectionDragBox = new DragBox({
condition: noModifierKeys
})
const map = new Map({ const map = new Map({
controls: [], controls: [],
layers: [ layers: [
@ -476,13 +481,16 @@ export const initializeMapState = (
printOrientation: 'horizontal', printOrientation: 'horizontal',
printRes: 72, printRes: 72,
printScale: '250', printScale: '250',
printScaleLine: true printScaleLine: true,
selectionDragBox: selectionDragBox
} }
} }
} }
}) })
} }
export const getSelectionDragBox = (id: string) => useMapStore.getState().id[id].selectionDragBox
export const setPrintOrientation = (id: string, orientation: PrintOrientation) => useMapStore.setState((state) => { export const setPrintOrientation = (id: string, orientation: PrintOrientation) => useMapStore.setState((state) => {
return { return {
id: { id: {

View File

@ -11,4 +11,5 @@ export type ToolType =
"Measure" | "Measure" |
"Mover" | "Mover" |
"Edit" | "Edit" |
"Selection" |
null null