mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-26 15:26:19 +00:00
add map mode setter
This commit is contained in:
@@ -5,6 +5,7 @@ import SortSetter from './sort-setter';
|
||||
import GroupbySetter from './groupby-setter';
|
||||
import PreHideColumnSetter from './pre-hide-column-setter';
|
||||
import HideColumnSetter from './hide-column-setter';
|
||||
import MapTypeSetter from './map-type-setter';
|
||||
|
||||
export {
|
||||
GalleryGroupBySetter,
|
||||
@@ -14,4 +15,5 @@ export {
|
||||
GroupbySetter,
|
||||
PreHideColumnSetter,
|
||||
HideColumnSetter,
|
||||
MapTypeSetter,
|
||||
};
|
||||
|
@@ -0,0 +1,57 @@
|
||||
.metadata-map-type-setter {
|
||||
width: fit-content;
|
||||
height: 36px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border: 1px solid #e2e2e2;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.metadata-map-type-setter .metadata-map-type-button {
|
||||
width: 66px;
|
||||
height: 28px;
|
||||
color: #212529;
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.875rem;
|
||||
border: 0;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.metadata-map-type-setter .metadata-map-type-button:hover {
|
||||
background-color: #f0f0f0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.metadata-map-type-setter .metadata-map-type-button.active {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.metadata-map-type-setter .metadata-map-type-button span {
|
||||
display: block;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.metadata-map-type-button:not(:first-child)::before {
|
||||
content: '';
|
||||
width: 1px;
|
||||
height: 22px;
|
||||
background-color: #e2e2e2;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
transition: opacity 0.3s;
|
||||
left: -1px;
|
||||
}
|
||||
|
||||
.metadata-map-type-button:hover::before,
|
||||
.metadata-map-type-button.active::before,
|
||||
.metadata-map-type-button:hover + .metadata-map-type-button::before,
|
||||
.metadata-map-type-button.active + .metadata-map-type-button::before {
|
||||
opacity: 0;
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
import React, { useState, useCallback, useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
import { EVENT_BUS_TYPE, MAP_TYPE } from '../../../constants';
|
||||
import { gettext } from '../../../../utils/constants';
|
||||
|
||||
import './index.css';
|
||||
|
||||
const TYPE_MAP = {
|
||||
[MAP_TYPE.MAP]: gettext('Map'),
|
||||
[MAP_TYPE.SATELLITE]: gettext('Satellite')
|
||||
};
|
||||
|
||||
const MapTypeSetter = ({ view }) => {
|
||||
const [currentType, setCurrentType] = useState(MAP_TYPE.MAP);
|
||||
|
||||
useEffect(() => {
|
||||
const savedValue = window.sfMetadataContext.localStorage.getItem('map-type', MAP_TYPE.MAP);
|
||||
setCurrentType(savedValue || MAP_TYPE.MAP);
|
||||
}, [view?._id]);
|
||||
|
||||
const handleTypeChange = useCallback((newType) => {
|
||||
setCurrentType(newType);
|
||||
window.sfMetadataContext.localStorage.setItem('map-type', newType);
|
||||
window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.SWITCH_MAP_TYPE, newType);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="metadata-map-type-setter">
|
||||
{Object.entries(TYPE_MAP).map(([type, label]) => (
|
||||
<button
|
||||
key={type}
|
||||
className={classnames('metadata-map-type-button', { active: currentType === type })}
|
||||
onClick={() => handleTypeChange(type)}
|
||||
>
|
||||
<span>{label}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
MapTypeSetter.propTypes = {
|
||||
view: PropTypes.shape({
|
||||
_id: PropTypes.string
|
||||
})
|
||||
};
|
||||
|
||||
export default MapTypeSetter;
|
@@ -1,7 +1,7 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { PRIVATE_COLUMN_KEY } from '../../../constants';
|
||||
import { FilterSetter } from '../../data-process-setter';
|
||||
import { FilterSetter, MapTypeSetter } from '../../data-process-setter';
|
||||
|
||||
const MapViewToolBar = ({
|
||||
readOnly,
|
||||
@@ -22,6 +22,7 @@ const MapViewToolBar = ({
|
||||
return (
|
||||
<>
|
||||
<div className="sf-metadata-tool-left-operations">
|
||||
<MapTypeSetter view={view} />
|
||||
<FilterSetter
|
||||
isNeedSubmit={true}
|
||||
wrapperClass="sf-metadata-view-tool-operation-btn sf-metadata-view-tool-filter"
|
||||
|
@@ -73,4 +73,7 @@ export const EVENT_BUS_TYPE = {
|
||||
TOGGLE_KANBAN_SETTINGS: 'toggle_kanban_settings',
|
||||
OPEN_KANBAN_SETTINGS: 'open_kanban_settings',
|
||||
CLOSE_KANBAN_SETTINGS: 'close_kanban_settings',
|
||||
|
||||
// map
|
||||
SWITCH_MAP_TYPE: 'switch_map_type',
|
||||
};
|
||||
|
@@ -141,6 +141,11 @@ export const GALLERY_DATE_MODE = {
|
||||
ALL: 'all',
|
||||
};
|
||||
|
||||
export const MAP_TYPE = {
|
||||
MAP: 'map',
|
||||
SATELLITE: 'satellite',
|
||||
};
|
||||
|
||||
export const UNCATEGORIZED = '_uncategorized';
|
||||
|
||||
export const PASTE_SOURCE = {
|
||||
|
@@ -4,7 +4,7 @@ import { Utils } from '../../../utils/utils';
|
||||
export function createBMapGeolocationControl(BMap, callback) {
|
||||
function GeolocationControl() {
|
||||
this.defaultAnchor = window.BMAP_ANCHOR_BOTTOM_RIGHT;
|
||||
this.defaultOffset = new BMap.Size(10, Utils.isDesktop() ? 20 : 90);
|
||||
this.defaultOffset = new BMap.Size(30, Utils.isDesktop() ? 30 : 90);
|
||||
}
|
||||
GeolocationControl.prototype = new window.BMap.Control();
|
||||
GeolocationControl.prototype.initialize = function (map) {
|
||||
@@ -15,10 +15,10 @@ export function createBMapGeolocationControl(BMap, callback) {
|
||||
const icon = document.createElement('img');
|
||||
icon.className = 'sf-BMap-icon-current-location';
|
||||
icon.src = `${mediaUrl}/img/current-location.svg`;
|
||||
icon.style = 'width: 16px; height: 16px; display: block;';
|
||||
icon.style = 'width: 18px; height: 18px; display: block;';
|
||||
div.appendChild(icon);
|
||||
if (Utils.isDesktop()) {
|
||||
setNodeStyle(div, 'height: 30px; width: 30px; line-height: 30px');
|
||||
setNodeStyle(div, 'height: 40px; width: 40px; line-height: 40px');
|
||||
} else {
|
||||
setNodeStyle(div, 'height: 35px; width: 35px; line-height: 35px; opacity: 0.75');
|
||||
}
|
||||
|
@@ -25,11 +25,11 @@
|
||||
right: -15px;
|
||||
top: -8px;
|
||||
padding: 0 12px;
|
||||
background: #20AD7E;
|
||||
background: #007bff;
|
||||
color: #fff;
|
||||
border-radius: 10px;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
.sf-metadata-view-map .sf-BMap-geolocation-control {
|
||||
background-color: #ffffff;
|
||||
box-shadow: 0 0 4px rgb(0 0 0 / 12%);
|
||||
border-radius: 4px;
|
||||
border-radius: 6px;
|
||||
text-align: center;
|
||||
color: #212529;
|
||||
}
|
||||
@@ -80,6 +80,44 @@
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.sf-metadata-view-map .sf-BMap-geolocation-control:hover {
|
||||
.sf-metadata-view-map .sf-BMap-geolocation-control:hover,
|
||||
.sf-metadata-view-map .sf-BMap-zoom-button:hover {
|
||||
background-color: #f5f5f5;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sf-metadata-view-map .sf-BMap-zoom-control {
|
||||
background-color: #fff;
|
||||
opacity: 1;
|
||||
overflow: hidden;
|
||||
border-radius: 6px;
|
||||
box-shadow: 2px 2px 4px 2px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.sf-metadata-view-map .sf-BMap-zoom-button {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: #fff;
|
||||
border: none;
|
||||
overflow: hidden;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.sf-metadata-view-map .sf-BMap-zoom-button .zoom-in-icon,
|
||||
.sf-metadata-view-map .sf-BMap-zoom-button .zoom-out-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
fill: #666;
|
||||
}
|
||||
|
||||
.sf-metadata-view-map .sf-BMap-zoom-button:hover .zoom-in-icon,
|
||||
.sf-metadata-view-map .sf-BMap-zoom-button:hover .zoom-out-icon {
|
||||
fill: #212529;
|
||||
}
|
||||
|
||||
.sf-metadata-view-map .sf-BMap-zoom-button:disabled .zoom-in-icon,
|
||||
.sf-metadata-view-map .sf-BMap-zoom-button:disabled .zoom-out-icon {
|
||||
fill: #ccc;
|
||||
}
|
||||
|
@@ -2,11 +2,11 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { CenteredLoading } from '@seafile/sf-metadata-ui-component';
|
||||
import loadBMap, { initMapInfo } from '../../../utils/map-utils';
|
||||
import { wgs84_to_gcj02, gcj02_to_bd09 } from '../../../utils/coord-transform';
|
||||
import { MAP_TYPE } from '../../../constants';
|
||||
import { isValidPosition } from '../../utils/validate';
|
||||
import { MAP_TYPE as MAP_PROVIDER } from '../../../constants';
|
||||
import { appAvatarURL, baiduMapKey, gettext, googleMapKey, mediaUrl, siteRoot, thumbnailSizeForGrid } from '../../../utils/constants';
|
||||
import { useMetadataView } from '../../hooks/metadata-view';
|
||||
import { PREDEFINED_FILE_TYPE_OPTION_KEY } from '../../constants';
|
||||
import { EVENT_BUS_TYPE, PREDEFINED_FILE_TYPE_OPTION_KEY, MAP_TYPE } from '../../constants';
|
||||
import { getRecordIdFromRecord, getFileNameFromRecord, getImageLocationFromRecord, getParentDirFromRecord,
|
||||
getFileTypeFromRecord
|
||||
} from '../../utils/cell';
|
||||
@@ -17,6 +17,7 @@ import { createBMapGeolocationControl } from './geolocation-control';
|
||||
import toaster from '../../../components/toast';
|
||||
|
||||
import './index.css';
|
||||
import { createBMapZoomControl } from './zoom-control';
|
||||
|
||||
const DEFAULT_POSITION = { lng: 104.195, lat: 35.861 };
|
||||
const DEFAULT_ZOOM = 4;
|
||||
@@ -56,15 +57,18 @@ const Map = () => {
|
||||
}, [repoID, metadata]);
|
||||
|
||||
const addMapController = useCallback(() => {
|
||||
var navigation = new window.BMap.NavigationControl();
|
||||
const ZoomControl = createBMapZoomControl(window.BMap);
|
||||
const zoomControl = new ZoomControl();
|
||||
const GeolocationControl = createBMapGeolocationControl(window.BMap, (err, point) => {
|
||||
if (!err && point) {
|
||||
mapRef.current.setCenter({ lng: point.lng, lat: point.lat });
|
||||
}
|
||||
});
|
||||
|
||||
const geolocationControl = new GeolocationControl();
|
||||
|
||||
mapRef.current.addControl(zoomControl);
|
||||
mapRef.current.addControl(geolocationControl);
|
||||
mapRef.current.addControl(navigation);
|
||||
}, []);
|
||||
|
||||
const renderMarkersBatch = useCallback(() => {
|
||||
@@ -121,6 +125,16 @@ const Map = () => {
|
||||
);
|
||||
}, []);
|
||||
|
||||
const getMapType = useCallback((type) => {
|
||||
if (!mapRef.current) return;
|
||||
switch (type) {
|
||||
case MAP_TYPE.SATELLITE:
|
||||
return window.BMAP_SATELLITE_MAP;
|
||||
default:
|
||||
return window.BMAP_NORMAL_MAP;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const renderBaiduMap = useCallback(() => {
|
||||
setIsLoading(false);
|
||||
if (!window.BMap.Map) return;
|
||||
@@ -142,6 +156,8 @@ const Map = () => {
|
||||
const point = new window.BMap.Point(lng, lat);
|
||||
mapRef.current.centerAndZoom(point, DEFAULT_ZOOM);
|
||||
mapRef.current.enableScrollWheelZoom(true);
|
||||
// const type = window.sfMetadataContext.localStorage.getItem('map-type');
|
||||
// mapRef.current.setMapType(getMapType(type));
|
||||
|
||||
addMapController();
|
||||
initializeUserMarker();
|
||||
@@ -152,7 +168,19 @@ const Map = () => {
|
||||
}, [addMapController, initializeClusterer, initializeUserMarker, renderMarkersBatch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (mapInfo.type === MAP_TYPE.B_MAP) {
|
||||
const switchMapTypeSubscribe = window.sfMetadataContext.eventBus.subscribe(EVENT_BUS_TYPE.SWITCH_MAP_TYPE, (newType) => {
|
||||
window.sfMetadataContext.localStorage.setItem('map-type', newType);
|
||||
mapRef.current && mapRef.current.setMapType(getMapType(newType));
|
||||
});
|
||||
|
||||
return () => {
|
||||
switchMapTypeSubscribe();
|
||||
};
|
||||
|
||||
}, [getMapType]);
|
||||
|
||||
useEffect(() => {
|
||||
if (mapInfo.type === MAP_PROVIDER.B_MAP) {
|
||||
window.renderMap = renderBaiduMap;
|
||||
loadBMap(mapInfo.key).then(() => renderBaiduMap());
|
||||
return () => {
|
||||
|
65
frontend/src/metadata/views/map/zoom-control.js
Normal file
65
frontend/src/metadata/views/map/zoom-control.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import { Utils } from '../../../utils/utils';
|
||||
|
||||
export function createBMapZoomControl(BMap, callback) {
|
||||
function ZoomControl() {
|
||||
this.defaultAnchor = window.BMAP_ANCHOR_BOTTOM_RIGHT;
|
||||
this.defaultOffset = new BMap.Size(80, Utils.isDesktop() ? 30 : 90);
|
||||
}
|
||||
ZoomControl.prototype = new window.BMap.Control();
|
||||
ZoomControl.prototype.initialize = function (map) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'sf-BMap-zoom-control';
|
||||
div.style = 'display: flex; justify-content: center; align-items: center;';
|
||||
|
||||
const zoomInButton = document.createElement('button');
|
||||
zoomInButton.className = 'sf-BMap-zoom-button';
|
||||
zoomInButton.style = 'display: flex; justify-content: center; align-items: center;';
|
||||
zoomInButton.innerHTML = '<svg class="zoom-in-icon"><use xlink:href="#plus_sign" /></svg>';
|
||||
div.appendChild(zoomInButton);
|
||||
|
||||
const divider = document.createElement('div');
|
||||
divider.style = 'height: 22px; width: 1px; background-color: #ccc;';
|
||||
div.appendChild(divider);
|
||||
|
||||
const zoomOutButton = document.createElement('button');
|
||||
zoomOutButton.className = 'sf-BMap-zoom-button';
|
||||
zoomOutButton.style = 'display: flex; justify-content: center; align-items: center;';
|
||||
zoomOutButton.innerHTML = '<svg class="zoom-out-icon"><use xlink:href="#minus_sign" /></svg>';
|
||||
div.appendChild(zoomOutButton);
|
||||
|
||||
if (Utils.isDesktop()) {
|
||||
setNodeStyle(div, 'height: 40px; width: 111px; line-height: 40px');
|
||||
} else {
|
||||
setNodeStyle(div, 'height: 35px; width: 80px; line-height: 35px; opacity: 0.75');
|
||||
}
|
||||
|
||||
const updateButtonStates = () => {
|
||||
const zoomLevel = map.getZoom();
|
||||
const maxZoom = map.getMaxZoom();
|
||||
const minZoom = map.getMinZoom();
|
||||
|
||||
zoomInButton.disabled = zoomLevel >= maxZoom;
|
||||
zoomOutButton.disabled = zoomLevel <= minZoom;
|
||||
};
|
||||
|
||||
zoomInButton.onclick = (e) => {
|
||||
e.preventDefault();
|
||||
map.zoomTo(map.getZoom() + 2);
|
||||
};
|
||||
|
||||
zoomOutButton.onclick = (e) => {
|
||||
e.preventDefault();
|
||||
map.zoomTo(map.getZoom() - 2);
|
||||
};
|
||||
|
||||
map.addEventListener('zoomend', updateButtonStates);
|
||||
map.getContainer().appendChild(div);
|
||||
return div;
|
||||
};
|
||||
|
||||
return ZoomControl;
|
||||
}
|
||||
|
||||
function setNodeStyle(dom, styleText) {
|
||||
dom.style.cssText += styleText;
|
||||
}
|
Reference in New Issue
Block a user