diff --git a/frontend/src/metadata/utils/sort/sort-row.js b/frontend/src/metadata/utils/sort/sort-row.js index b3b3b714e3..376abb654b 100644 --- a/frontend/src/metadata/utils/sort/sort-row.js +++ b/frontend/src/metadata/utils/sort/sort-row.js @@ -59,13 +59,13 @@ const sortRowsWithMultiSorts = (tableRows, sorts, { collaborators }) => { * @param {object} value e.g. { collaborators, ... } * @returns sorted rows ids, array */ -const sortTableRows = (table, rows, sorts, { collaborators }) => { +const sortTableRows = (table, rows, sorts, { collaborators, isReturnID = true } = {}) => { const { columns } = table; if (!Array.isArray(rows) || rows.length === 0) return []; const sortRows = rows.slice(0); const validSorts = deleteInvalidSort(sorts, columns); sortRowsWithMultiSorts(sortRows, validSorts, { collaborators }); - return sortRows.map((row) => row._id); + return isReturnID ? sortRows.map((row) => row._id) : sortRows; }; export { diff --git a/frontend/src/metadata/views/face-recognition/person-photos/index.js b/frontend/src/metadata/views/face-recognition/person-photos/index.js index ce4169499c..f8692af425 100644 --- a/frontend/src/metadata/views/face-recognition/person-photos/index.js +++ b/frontend/src/metadata/views/face-recognition/person-photos/index.js @@ -1,6 +1,8 @@ import React, { useCallback, useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import deepCopy from 'deep-copy'; +import dayjs from 'dayjs'; +import utc from 'dayjs/plugin/utc'; import { CenteredLoading } from '@seafile/sf-metadata-ui-component'; import metadataAPI from '../../../api'; import Metadata from '../../../model/metadata'; @@ -10,11 +12,16 @@ import { Utils } from '../../../../utils/utils'; import toaster from '../../../../components/toast'; import Gallery from '../../gallery/main'; import { useMetadataView } from '../../../hooks/metadata-view'; -import { PER_LOAD_NUMBER, EVENT_BUS_TYPE, FACE_RECOGNITION_VIEW_ID } from '../../../constants'; +import { PER_LOAD_NUMBER, EVENT_BUS_TYPE, FACE_RECOGNITION_VIEW_ID, UTC_FORMAT_DEFAULT } from '../../../constants'; +import { getRecordIdFromRecord, getParentDirFromRecord, getFileNameFromRecord } from '../../../utils/cell'; +import { sortTableRows } from '../../../utils/sort'; +import { useCollaborators } from '../../../hooks/collaborators'; import './index.css'; import '../../gallery/index.css'; +dayjs.extend(utc); + const PeoplePhotos = ({ view, people, onClose, onDeletePeoplePhotos, onRemovePeoplePhotos }) => { const [isLoading, setLoading] = useState(true); const [isLoadingMore, setLoadingMore] = useState(false); @@ -22,6 +29,7 @@ const PeoplePhotos = ({ view, people, onClose, onDeletePeoplePhotos, onRemovePeo const repoID = window.sfMetadataContext.getSetting('repoID'); const { deleteFilesCallback, store } = useMetadataView(); + const { collaborators } = useCollaborators(); const onLoadMore = useCallback(async () => { if (isLoadingMore) return; @@ -150,6 +158,38 @@ const PeoplePhotos = ({ view, people, onClose, onDeletePeoplePhotos, onRemovePeo }); }, [repoID, metadata, store, loadData]); + const onRecordChange = useCallback(({ recordId, parentDir, fileName }, update) => { + const modifyTime = dayjs().utc().format(UTC_FORMAT_DEFAULT); + const modifier = window.sfMetadataContext.getUsername(); + const { rows, columns, view } = metadata; + let newRows = [...rows]; + newRows.forEach((row, index) => { + const _rowId = getRecordIdFromRecord(row); + const _parentDir = getParentDirFromRecord(row); + const _fileName = getFileNameFromRecord(row); + if ((_rowId === recordId || (_parentDir === parentDir && _fileName === fileName)) && update) { + const updatedRow = Object.assign({}, row, update, { + '_mtime': modifyTime, + '_last_modifier': modifier, + }); + newRows[index] = updatedRow; + } + }); + let updatedColumnKeyMap = { + '_mtime': true, + '_last_modifier': true + }; + Object.keys(update).forEach(key => { + updatedColumnKeyMap[key] = true; + }); + if (view.sorts.some(sort => updatedColumnKeyMap[sort.column_key])) { + newRows = sortTableRows({ columns }, newRows, view?.sorts || [], { collaborators, isReturnID: false }); + } + let newMetadata = new Metadata({ rows: newRows, columns, view }); + newMetadata.hasMore = false; + setMetadata(newMetadata); + }, [metadata, collaborators]); + useEffect(() => { loadData({ sorts: view.sorts }); // eslint-disable-next-line react-hooks/exhaustive-deps @@ -164,11 +204,15 @@ const PeoplePhotos = ({ view, people, onClose, onDeletePeoplePhotos, onRemovePeo }, []); useEffect(() => { - const unsubscribeViewChange = window.sfMetadataContext.eventBus.subscribe(EVENT_BUS_TYPE.UPDATE_SERVER_VIEW, onViewChange); + const eventBus = window?.sfMetadataContext?.eventBus; + if (!eventBus) return; + const unsubscribeViewChange = eventBus.subscribe(EVENT_BUS_TYPE.UPDATE_SERVER_VIEW, onViewChange); + const localRecordChangedSubscribe = eventBus.subscribe(EVENT_BUS_TYPE.LOCAL_RECORD_CHANGED, onRecordChange); return () => { unsubscribeViewChange && unsubscribeViewChange(); + localRecordChangedSubscribe && localRecordChangedSubscribe(); }; - }, [onViewChange]); + }, [onViewChange, onRecordChange]); if (isLoading) return (); diff --git a/frontend/src/metadata/views/map/cluster-photos/index.js b/frontend/src/metadata/views/map/cluster-photos/index.js index d829ebb311..4678e616fc 100644 --- a/frontend/src/metadata/views/map/cluster-photos/index.js +++ b/frontend/src/metadata/views/map/cluster-photos/index.js @@ -1,9 +1,11 @@ -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import deepCopy from 'deep-copy'; +import dayjs from 'dayjs'; +import utc from 'dayjs/plugin/utc'; import { CenteredLoading } from '@seafile/sf-metadata-ui-component'; import Gallery from '../../gallery/main'; -import { EVENT_BUS_TYPE } from '../../../constants'; +import { EVENT_BUS_TYPE, UTC_FORMAT_DEFAULT } from '../../../constants'; import metadataAPI from '../../../api'; import { Utils } from '../../../../utils/utils'; import toaster from '../../../../components/toast'; @@ -12,30 +14,29 @@ import { getRowsByIds } from '../../../utils/table'; import Metadata from '../../../model/metadata'; import { sortTableRows } from '../../../utils/sort'; import { useCollaborators } from '../../../hooks/collaborators'; +import { getRecordIdFromRecord, getParentDirFromRecord, getFileNameFromRecord } from '../../../utils/cell'; import './index.css'; -const ClusterPhotos = ({ markerIds, onClose }) => { - const [isLoading, setLoading] = useState(true); - const [metadata, setMetadata] = useState({ rows: [] }); +dayjs.extend(utc); +const ClusterPhotos = ({ photoIds, onClose }) => { const { repoID, viewID, metadata: allMetadata, store, addFolder, deleteRecords } = useMetadataView(); const { collaborators } = useCollaborators(); - const rows = useMemo(() => getRowsByIds(allMetadata, markerIds), [allMetadata, markerIds]); - const columns = useMemo(() => allMetadata?.columns || [], [allMetadata]); + const [isLoading, setLoading] = useState(true); + const [metadata, setMetadata] = useState({ rows: getRowsByIds(allMetadata, photoIds), columns: allMetadata?.columns || [] }); const loadData = useCallback((view) => { setLoading(true); - const orderRows = sortTableRows({ columns }, rows, view?.sorts || [], { collaborators }); - let metadata = new Metadata({ rows, columns, view }); - metadata.hasMore = false; - metadata.row_ids = orderRows; - metadata.view.rows = orderRows; - setMetadata(metadata); - window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.RESET_VIEW, metadata.view); + const columns = metadata.columns; + const orderRows = sortTableRows({ columns }, metadata.rows, view?.sorts || [], { collaborators, isReturnID: false }); + let newMetadata = new Metadata({ rows: orderRows, columns, view }); + newMetadata.hasMore = false; + setMetadata(newMetadata); + window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.RESET_VIEW, newMetadata.view); setLoading(false); - }, [rows, columns, collaborators]); + }, [metadata, collaborators]); const deletedByIds = useCallback((ids) => { if (!Array.isArray(ids) || ids.length === 0) return; @@ -84,23 +85,61 @@ const ClusterPhotos = ({ markerIds, onClose }) => { }); }, [metadata, repoID, viewID, store, loadData]); + const onRecordChange = useCallback(({ recordId, parentDir, fileName }, update) => { + const modifyTime = dayjs().utc().format(UTC_FORMAT_DEFAULT); + const modifier = window.sfMetadataContext.getUsername(); + const { rows, columns, view } = metadata; + let newRows = [...rows]; + newRows.forEach((row, index) => { + const _rowId = getRecordIdFromRecord(row); + const _parentDir = getParentDirFromRecord(row); + const _fileName = getFileNameFromRecord(row); + if ((_rowId === recordId || (_parentDir === parentDir && _fileName === fileName)) && update) { + const updatedRow = Object.assign({}, row, update, { + '_mtime': modifyTime, + '_last_modifier': modifier, + }); + newRows[index] = updatedRow; + } + }); + let updatedColumnKeyMap = { + '_mtime': true, + '_last_modifier': true + }; + Object.keys(update).forEach(key => { + updatedColumnKeyMap[key] = true; + }); + if (view.sorts.some(sort => updatedColumnKeyMap[sort.column_key])) { + newRows = sortTableRows({ columns }, newRows, view?.sorts || [], { collaborators, isReturnID: false }); + } + let newMetadata = new Metadata({ rows: newRows, columns, view }); + newMetadata.hasMore = false; + setMetadata(newMetadata); + }, [metadata, collaborators]); + useEffect(() => { - window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.TOGGLE_VIEW_TOOLBAR, true); + const eventBus = window?.sfMetadataContext?.eventBus; + if (!eventBus) return; + eventBus.dispatch(EVENT_BUS_TYPE.TOGGLE_VIEW_TOOLBAR, true); return () => { - window?.sfMetadataContext?.eventBus?.dispatch(EVENT_BUS_TYPE.TOGGLE_VIEW_TOOLBAR, false); + eventBus.dispatch(EVENT_BUS_TYPE.TOGGLE_VIEW_TOOLBAR, false); }; }, []); useEffect(() => { - const unsubscribeViewChange = window?.sfMetadataContext?.eventBus?.subscribe(EVENT_BUS_TYPE.UPDATE_SERVER_VIEW, onViewChange); + const eventBus = window?.sfMetadataContext?.eventBus; + if (!eventBus) return; + const unsubscribeViewChange = eventBus.subscribe(EVENT_BUS_TYPE.UPDATE_SERVER_VIEW, onViewChange); + const localRecordChangedSubscribe = eventBus.subscribe(EVENT_BUS_TYPE.LOCAL_RECORD_CHANGED, onRecordChange); return () => { unsubscribeViewChange && unsubscribeViewChange(); + localRecordChangedSubscribe && localRecordChangedSubscribe(); }; - }, [onViewChange]); + }, [onViewChange, onRecordChange]); useEffect(() => { loadData({ sorts: allMetadata.view.sorts }); - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); if (isLoading) return (); @@ -113,7 +152,7 @@ const ClusterPhotos = ({ markerIds, onClose }) => { }; ClusterPhotos.propTypes = { - markerIds: PropTypes.array, + photoIds: PropTypes.array, onClose: PropTypes.func, }; diff --git a/frontend/src/metadata/views/map/control/geolocation-control.js b/frontend/src/metadata/views/map/control/geolocation-control.js deleted file mode 100644 index d067348c81..0000000000 --- a/frontend/src/metadata/views/map/control/geolocation-control.js +++ /dev/null @@ -1,50 +0,0 @@ -import { mediaUrl } from '../../../../utils/constants'; -import { Utils } from '../../../../utils/utils'; - -export function createBMapGeolocationControl(BMapGL, callback) { - function GeolocationControl() { - this.defaultAnchor = window.BMAP_ANCHOR_BOTTOM_RIGHT; - this.defaultOffset = new BMapGL.Size(30, Utils.isDesktop() ? 30 : 90); - } - GeolocationControl.prototype = new BMapGL.Control(); - GeolocationControl.prototype.initialize = function (map) { - const div = document.createElement('div'); - div.className = 'sf-BMap-geolocation-control'; - div.style = 'display: flex; justify-content: center; align-items: center;'; - - const icon = document.createElement('img'); - icon.className = 'sf-BMap-icon-current-location'; - icon.src = `${mediaUrl}/img/current-location.svg`; - icon.style = 'width: 18px; height: 18px; display: block;'; - div.appendChild(icon); - if (Utils.isDesktop()) { - setNodeStyle(div, 'height: 40px; width: 40px; line-height: 40px'); - } else { - setNodeStyle(div, 'height: 35px; width: 35px; line-height: 35px; opacity: 0.75'); - } - div.onclick = (e) => { - e.preventDefault(); - const geolocation = new BMapGL.Geolocation(); - div.className = 'sf-BMap-geolocation-control sf-BMap-geolocation-control-loading'; - geolocation.getCurrentPosition((result) => { - div.className = 'sf-BMap-geolocation-control'; - if (result) { - const point = result.point; - map.setCenter(point); - callback(null, point); - } else { - // Positioning failed - callback(true); - } - }); - }; - map.getContainer().appendChild(div); - return div; - }; - - return GeolocationControl; -} - -function setNodeStyle(dom, styleText) { - dom.style.cssText += styleText; -} diff --git a/frontend/src/metadata/views/map/control/zoom-control.js b/frontend/src/metadata/views/map/control/zoom-control.js deleted file mode 100644 index de799d2840..0000000000 --- a/frontend/src/metadata/views/map/control/zoom-control.js +++ /dev/null @@ -1,68 +0,0 @@ -import { Utils } from '../../../../utils/utils'; - -const maxZoom = 18; -const minZoom = 3; - -export function createBMapZoomControl(BMapGL, callback) { - function ZoomControl() { - this.defaultAnchor = window.BMAP_ANCHOR_BOTTOM_RIGHT; - this.defaultOffset = new BMapGL.Size(80, Utils.isDesktop() ? 30 : 90); - } - ZoomControl.prototype = new BMapGL.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 btn btn-secondary'; - zoomInButton.style = 'display: flex; justify-content: center; align-items: center;'; - zoomInButton.innerHTML = ''; - 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 btn btn-secondary'; - zoomOutButton.style = 'display: flex; justify-content: center; align-items: center;'; - zoomOutButton.innerHTML = ''; - 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(); - zoomInButton.disabled = zoomLevel >= maxZoom; - zoomOutButton.disabled = zoomLevel <= minZoom; - callback && callback(zoomLevel); - }; - - zoomInButton.onclick = (e) => { - e.preventDefault(); - const nextZoom = map.getZoom() + 2; - map.zoomTo(Math.min(nextZoom, maxZoom)); - }; - - zoomOutButton.onclick = (e) => { - e.preventDefault(); - const nextZoom = map.getZoom() - 2; - map.zoomTo(Math.max(nextZoom, minZoom)); - }; - - map.addEventListener('zoomend', updateButtonStates); - map.getContainer().appendChild(div); - return div; - }; - - return ZoomControl; -} - -function setNodeStyle(dom, styleText) { - dom.style.cssText += styleText; -} diff --git a/frontend/src/metadata/views/map/index.css b/frontend/src/metadata/views/map/index.css index cf9cd9ce28..22ff37c943 100644 --- a/frontend/src/metadata/views/map/index.css +++ b/frontend/src/metadata/views/map/index.css @@ -4,136 +4,3 @@ display: flex; flex-direction: column; } - -.sf-metadata-view-map #platform div:has(.custom-avatar-overlay) { - display: block !important; -} - -.sf-metadata-view-map #platform div:has(.custom-image-overlay) { - display: block !important; -} - -.sf-metadata-view-map .sf-metadata-map-container { - width: 100%; - height: 100%; -} - -.sf-metadata-view-map .custom-image-container { - width: 86px; - height: 86px; - background-color: #fff; - padding: 3px; - border-radius: 6px; - position: relative; - cursor: default; -} - -.sf-metadata-view-map .custom-image-container img { - width: 100%; - height: 100%; - border-radius: 6px; -} - -.sf-metadata-view-map .custom-image-number { - position: absolute; - right: -16px; - top: -16px; - width: 32px; - height: 32px; - padding: 6px; - background: #007bff; - color: #fff; - border-radius: 50%; - text-align: center; - font-size: 16px; - line-height: 20px; - font-weight: 400; -} - -.sf-metadata-view-map .custom-image-container:active::before, -.sf-metadata-view-map .custom-image-container:active .custom-image-number::before, -.sf-metadata-view-map .custom-image-number:active::before, -.sf-metadata-view-map .custom-image-number:active .custom-image-container::before { - content: ''; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: rgba(0, 0, 0, 0.4); - border-radius: 6px; -} - -.sf-metadata-view-map .custom-image-container:active .custom-image-number::before, -.sf-metadata-view-map .custom-image-number:active::before { - border-radius: 50%; -} - -.sf-metadata-view-map .custom-image-container::after { - content: ''; - position: absolute; - bottom: -10px; - left: 50%; - transform: translateX(-50%); - width: 0; - height: 0; - border-left: 10px solid transparent; - border-right: 10px solid transparent; - border-top: 10px solid #fff; - border-radius: 2px; -} - -.sf-metadata-view-map .custom-image-container:active::after, -.sf-metadata-view-map .custom-image-number:active .custom-image-container::after { - border-top: 10px solid rgba(0, 0, 0, 0.4); -} - -.sf-metadata-view-map .sf-BMap-geolocation-control, -.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-geolocation-control-loading { - opacity: 0.7; -} - -.sf-metadata-view-map .sf-BMap-geolocation-control:hover, -.sf-metadata-view-map .sf-BMap-zoom-button:not(.disabled):hover { - background-color: #f5f5f5; - cursor: pointer; -} - -.sf-metadata-view-map .sf-BMap-zoom-button { - width: 100%; - height: 100%; - padding: 0; - margin: 0; - color: #666; - 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: currentColor; -} - -.sf-metadata-view-map .sf-BMap-zoom-button:not(:disabled):active:focus { - box-shadow: none; -} - -.sf-metadata-view-map .sf-BMap-zoom-button:hover { - color: #212529; -} - -.sf-metadata-view-map .sf-BMap-zoom-button:disabled { - color: #ccc !important; -} diff --git a/frontend/src/metadata/views/map/index.js b/frontend/src/metadata/views/map/index.js index 4df75e4c95..df78a5a991 100644 --- a/frontend/src/metadata/views/map/index.js +++ b/frontend/src/metadata/views/map/index.js @@ -1,7 +1,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { getFileNameFromRecord, getFileTypeFromRecord, getImageLocationFromRecord, getParentDirFromRecord, getRecordIdFromRecord } from '../../utils/cell'; import ClusterPhotos from './cluster-photos'; -import MapView from './map'; +import MapView from './map-view'; import { PREDEFINED_FILE_TYPE_OPTION_KEY } from '../../constants'; import { useMetadataView } from '../../hooks/metadata-view'; import { Utils } from '../../../utils/utils'; @@ -60,7 +60,7 @@ const Map = () => { }, []); if (showCluster) { - return (); + return (); } return (); diff --git a/frontend/src/metadata/views/map/map-view/control/geolocation-control/index.css b/frontend/src/metadata/views/map/map-view/control/geolocation-control/index.css new file mode 100644 index 0000000000..49359bb5bd --- /dev/null +++ b/frontend/src/metadata/views/map/map-view/control/geolocation-control/index.css @@ -0,0 +1,4 @@ +.sf-map-control-container.sf-map-geolocation-control { + width: 40px; + line-height: 40px; +} diff --git a/frontend/src/metadata/views/map/map-view/control/geolocation-control/index.js b/frontend/src/metadata/views/map/map-view/control/geolocation-control/index.js new file mode 100644 index 0000000000..62e05f53c3 --- /dev/null +++ b/frontend/src/metadata/views/map/map-view/control/geolocation-control/index.js @@ -0,0 +1,44 @@ +import classnames from 'classnames'; +import { Utils } from '../../../../../../utils/utils'; + +import './index.css'; + +export function createBMapGeolocationControl(BMapGL, callback) { + function GeolocationControl() { + this.defaultAnchor = window.BMAP_ANCHOR_BOTTOM_RIGHT; + this.defaultOffset = new BMapGL.Size(30, Utils.isDesktop() ? 30 : 90); + } + GeolocationControl.prototype = new BMapGL.Control(); + GeolocationControl.prototype.initialize = function (map) { + const div = document.createElement('div'); + let className = classnames('sf-map-control-container sf-map-geolocation-control d-flex align-items-center justify-content-center', { + 'sf-map-geolocation-control-mobile': !Utils.isDesktop() + }); + + const locationButton = document.createElement('div'); + locationButton.className = 'sf-map-control d-flex align-items-center justify-content-center'; + locationButton.innerHTML = ''; + div.appendChild(locationButton); + + div.className = className; + div.onclick = (e) => { + e.preventDefault(); + const geolocation = new BMapGL.Geolocation(); + div.className = classnames(className, 'sf-map-control-loading'); + geolocation.getCurrentPosition((result) => { + div.className = className; + if (result) { + const point = result.point; + callback(point); + } else { + // Positioning failed + callback(); + } + }); + }; + map.getContainer().appendChild(div); + return div; + }; + + return GeolocationControl; +} diff --git a/frontend/src/metadata/views/map/map-view/control/index.css b/frontend/src/metadata/views/map/map-view/control/index.css new file mode 100644 index 0000000000..c9157de961 --- /dev/null +++ b/frontend/src/metadata/views/map/map-view/control/index.css @@ -0,0 +1,63 @@ +.sf-map-control-container { + height: 40px; + width: fit-content; + background-color: rgba(255, 255, 255, .9); + opacity: 1; + overflow: hidden; + border-radius: 6px; + box-shadow: -2px -2px 4px 2px rgba(0, 0, 0, 0.1); + line-height: 40px; +} + +.sf-map-control-container.sf-map-control-loading { + opacity: 0.7; +} + +.sf-map-control-container.sf-map-control-container-mobile { + height: 35px; + line-height: 35px; + opacity: .75; +} + +.sf-map-control-container .sf-map-control-divider { + height: 100%; + width: 1px; + position: relative; + background-color: inherit; +} + +.sf-map-control-container .sf-map-control-divider::before { + content: ''; + position: absolute; + top: 9px; + height: 22px; + width: 1px; + background-color: #ccc; +} + +.sf-map-control-container .sf-map-control { + height: 40px; + width: 40px; + color: #666; + background-color: inherit; + text-align: center; +} + +.sf-map-control-container.sf-map-control-container-mobile .sf-map-control { + height: 35px; + width: 35px; + opacity: .75; +} + +.sf-map-control-container .sf-map-control .sf-map-control-icon { + font-size: 18px; +} + +.sf-map-control-container .sf-map-control:not(.disabled):hover { + cursor: pointer; + color: #212529; +} + +.sf-map-control-container .sf-map-control.disabled { + color: #ccc; +} diff --git a/frontend/src/metadata/views/map/control/index.js b/frontend/src/metadata/views/map/map-view/control/index.js similarity index 89% rename from frontend/src/metadata/views/map/control/index.js rename to frontend/src/metadata/views/map/map-view/control/index.js index 46577bee52..8cd156d393 100644 --- a/frontend/src/metadata/views/map/control/index.js +++ b/frontend/src/metadata/views/map/map-view/control/index.js @@ -1,6 +1,8 @@ import { createBMapGeolocationControl } from './geolocation-control'; import { createBMapZoomControl } from './zoom-control'; +import './index.css'; + export { createBMapGeolocationControl, createBMapZoomControl diff --git a/frontend/src/metadata/views/map/map-view/control/zoom-control/index.css b/frontend/src/metadata/views/map/map-view/control/zoom-control/index.css new file mode 100644 index 0000000000..98deb1eabd --- /dev/null +++ b/frontend/src/metadata/views/map/map-view/control/zoom-control/index.css @@ -0,0 +1,3 @@ +.sf-map-control-container.sf-map-zoom-control-container .sf-map-control { + width: 55px; +} diff --git a/frontend/src/metadata/views/map/map-view/control/zoom-control/index.js b/frontend/src/metadata/views/map/map-view/control/zoom-control/index.js new file mode 100644 index 0000000000..79057f567e --- /dev/null +++ b/frontend/src/metadata/views/map/map-view/control/zoom-control/index.js @@ -0,0 +1,59 @@ +import classnames from 'classnames'; +import { Utils } from '../../../../../../utils/utils'; + +import './index.css'; + +export function createBMapZoomControl(BMapGL, { maxZoom, minZoom }, callback) { + function ZoomControl() { + this.defaultAnchor = window.BMAP_ANCHOR_BOTTOM_RIGHT; + this.defaultOffset = new BMapGL.Size(80, Utils.isDesktop() ? 30 : 90); + } + ZoomControl.prototype = new BMapGL.Control(); + ZoomControl.prototype.initialize = function (map) { + const zoomLevel = map.getZoom(); + const div = document.createElement('div'); + div.className = classnames('sf-map-control-container sf-map-zoom-control-container d-flex align-items-center justify-content-center', { + 'sf-map-control-container-mobile': !Utils.isDesktop() + }); + + const buttonClassName = 'sf-map-control d-flex align-items-center justify-content-center'; + const zoomInButton = document.createElement('div'); + zoomInButton.className = classnames(buttonClassName, { 'disabled': zoomLevel >= maxZoom }); + zoomInButton.innerHTML = ''; + div.appendChild(zoomInButton); + + const divider = document.createElement('div'); + divider.className = 'sf-map-control-divider'; + div.appendChild(divider); + + const zoomOutButton = document.createElement('div'); + zoomOutButton.className = classnames(buttonClassName, { 'disabled': zoomLevel <= minZoom }); + zoomOutButton.innerHTML = ''; + div.appendChild(zoomOutButton); + + const updateButtonStates = () => { + const zoomLevel = map.getZoom(); + zoomInButton.className = classnames(buttonClassName, { 'disabled': zoomLevel >= maxZoom }); + zoomOutButton.className = classnames(buttonClassName, { 'disabled': zoomLevel <= minZoom }); + callback && callback(zoomLevel); + }; + + zoomInButton.onclick = (e) => { + e.preventDefault(); + const nextZoom = map.getZoom() + 1; + map.zoomTo(Math.min(nextZoom, maxZoom)); + }; + + zoomOutButton.onclick = (e) => { + e.preventDefault(); + const nextZoom = map.getZoom() - 1; + map.zoomTo(Math.max(nextZoom, minZoom)); + }; + + map.addEventListener('zoomend', updateButtonStates); + map.getContainer().appendChild(div); + return div; + }; + + return ZoomControl; +} diff --git a/frontend/src/metadata/views/map/map-view/index.css b/frontend/src/metadata/views/map/map-view/index.css new file mode 100644 index 0000000000..58f9773770 --- /dev/null +++ b/frontend/src/metadata/views/map/map-view/index.css @@ -0,0 +1,82 @@ +.sf-metadata-view-map #platform div:has(.custom-avatar-overlay) { + display: block !important; +} + +.sf-metadata-view-map #platform div:has(.custom-image-overlay) { + display: block !important; +} + +.sf-metadata-view-map .sf-metadata-map-container { + width: 100%; + height: 100%; +} + +.sf-metadata-view-map .custom-image-container { + width: 86px; + height: 86px; + display: flex; + align-items: center; + justify-content: center; + background-color: #fff; + padding: 3px; + border-radius: 6px; + position: relative; + cursor: default; +} + +.sf-metadata-view-map .custom-image-container img { + border-radius: 6px; +} + +.sf-metadata-view-map .custom-image-number { + position: absolute; + right: -16px; + top: -16px; + width: 32px; + height: 32px; + line-height: 32px; + background: #007bff; + color: #fff; + border-radius: 50%; + text-align: center; + font-size: 16px; + font-weight: 400; +} + +.sf-metadata-view-map .custom-image-container:active::before, +.sf-metadata-view-map .custom-image-container:active .custom-image-number::before, +.sf-metadata-view-map .custom-image-number:active::before, +.sf-metadata-view-map .custom-image-number:active .custom-image-container::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.4); + border-radius: 6px; +} + +.sf-metadata-view-map .custom-image-container:active .custom-image-number::before, +.sf-metadata-view-map .custom-image-number:active::before { + border-radius: 50%; +} + +.sf-metadata-view-map .custom-image-container::after { + content: ''; + position: absolute; + bottom: -10px; + left: 50%; + transform: translateX(-50%); + width: 0; + height: 0; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + border-top: 10px solid #fff; + border-radius: 2px; +} + +.sf-metadata-view-map .custom-image-container:active::after, +.sf-metadata-view-map .custom-image-number:active .custom-image-container::after { + border-top: 10px solid rgba(0, 0, 0, 0.4); +} diff --git a/frontend/src/metadata/views/map/map.js b/frontend/src/metadata/views/map/map-view/index.js similarity index 88% rename from frontend/src/metadata/views/map/map.js rename to frontend/src/metadata/views/map/map-view/index.js index 4dbef7eadd..9b07c82a03 100644 --- a/frontend/src/metadata/views/map/map.js +++ b/frontend/src/metadata/views/map/map-view/index.js @@ -1,19 +1,23 @@ import React, { useCallback, useEffect, useMemo, useRef } from 'react'; import PropTypes from 'prop-types'; -import loadBMap, { initMapInfo } from '../../../utils/map-utils'; -import { appAvatarURL, baiduMapKey, googleMapKey, mediaUrl } from '../../../utils/constants'; -import { isValidPosition } from '../../utils/validate'; -import { wgs84_to_gcj02, gcj02_to_bd09 } from '../../../utils/coord-transform'; -import { MAP_TYPE as MAP_PROVIDER } from '../../../constants'; -import { EVENT_BUS_TYPE, MAP_TYPE, STORAGE_MAP_CENTER_KEY, STORAGE_MAP_TYPE_KEY, STORAGE_MAP_ZOOM_KEY } from '../../constants'; +import loadBMap, { initMapInfo } from '../../../../utils/map-utils'; +import { appAvatarURL, baiduMapKey, googleMapKey, mediaUrl } from '../../../../utils/constants'; +import { isValidPosition } from '../../../utils/validate'; +import { wgs84_to_gcj02, gcj02_to_bd09 } from '../../../../utils/coord-transform'; +import { MAP_TYPE as MAP_PROVIDER } from '../../../../constants'; +import { EVENT_BUS_TYPE, MAP_TYPE, STORAGE_MAP_CENTER_KEY, STORAGE_MAP_TYPE_KEY, STORAGE_MAP_ZOOM_KEY } from '../../../constants'; import { createBMapGeolocationControl, createBMapZoomControl } from './control'; import { customAvatarOverlay, customImageOverlay } from './overlay'; +import './index.css'; + const DEFAULT_POSITION = { lng: 104.195, lat: 35.861 }; const DEFAULT_ZOOM = 4; const BATCH_SIZE = 500; +const MAX_ZOOM = 21; +const MIN_ZOOM = 3; -const Map = ({ images, onOpenCluster }) => { +const MapView = ({ images, onOpenCluster }) => { const mapInfo = useMemo(() => initMapInfo({ baiduMapKey, googleMapKey }), []); const mapRef = useRef(null); @@ -29,16 +33,13 @@ const Map = ({ images, onOpenCluster }) => { }, []); const addMapController = useCallback(() => { - const ZoomControl = createBMapZoomControl(window.BMapGL, saveMapState); + const ZoomControl = createBMapZoomControl(window.BMapGL, { maxZoom: MAX_ZOOM, minZoom: MIN_ZOOM }, saveMapState); const zoomControl = new ZoomControl(); - const GeolocationControl = createBMapGeolocationControl(window.BMapGL, (err, point) => { - if (!err && point) { - mapRef.current.setCenter(point); - } + const GeolocationControl = createBMapGeolocationControl(window.BMapGL, (point) => { + point && mapRef.current && mapRef.current.setCenter(point); }); const geolocationControl = new GeolocationControl(); - mapRef.current.addControl(zoomControl); mapRef.current.addControl(geolocationControl); }, [saveMapState]); @@ -124,8 +125,8 @@ const Map = ({ images, onOpenCluster }) => { const mapTypeValue = window.sfMetadataContext.localStorage.getItem(STORAGE_MAP_TYPE_KEY); mapRef.current = new window.BMapGL.Map('sf-metadata-map-container', { enableMapClick: false, - minZoom: 3, - maxZoom: 21, + minZoom: MIN_ZOOM, + maxZoom: MAX_ZOOM, mapType: getBMapType(mapTypeValue), }); @@ -175,9 +176,9 @@ const Map = ({ images, onOpenCluster }) => { ); }; -Map.propTypes = { +MapView.propTypes = { images: PropTypes.array, onOpenCluster: PropTypes.func, }; -export default Map; +export default MapView; diff --git a/frontend/src/metadata/views/map/overlay/custom-avatar-overlay.js b/frontend/src/metadata/views/map/map-view/overlay/custom-avatar-overlay.js similarity index 100% rename from frontend/src/metadata/views/map/overlay/custom-avatar-overlay.js rename to frontend/src/metadata/views/map/map-view/overlay/custom-avatar-overlay.js diff --git a/frontend/src/metadata/views/map/overlay/custom-image-overlay.js b/frontend/src/metadata/views/map/map-view/overlay/custom-image-overlay.js similarity index 97% rename from frontend/src/metadata/views/map/overlay/custom-image-overlay.js rename to frontend/src/metadata/views/map/map-view/overlay/custom-image-overlay.js index 583d6def10..871e004617 100644 --- a/frontend/src/metadata/views/map/overlay/custom-image-overlay.js +++ b/frontend/src/metadata/views/map/map-view/overlay/custom-image-overlay.js @@ -1,4 +1,4 @@ -import { Utils } from '../../../../utils/utils'; +import { Utils } from '../../../../../utils/utils'; const customImageOverlay = (center, image, callback) => { class ImageOverlay extends window.BMapLib.TextIconOverlay { diff --git a/frontend/src/metadata/views/map/overlay/index.js b/frontend/src/metadata/views/map/map-view/overlay/index.js similarity index 100% rename from frontend/src/metadata/views/map/overlay/index.js rename to frontend/src/metadata/views/map/map-view/overlay/index.js diff --git a/frontend/src/utils/map-utils.js b/frontend/src/utils/map-utils.js index fa2c07f395..dfa0982225 100644 --- a/frontend/src/utils/map-utils.js +++ b/frontend/src/utils/map-utils.js @@ -1,6 +1,8 @@ import { MAP_TYPE } from '../constants'; import { mediaUrl } from './constants'; +const STATIC_RESOURCE_VERSION = 0.1; + export const initMapInfo = ({ baiduMapKey, googleMapKey, mineMapKey }) => { if (baiduMapKey) return { type: MAP_TYPE.B_MAP, key: baiduMapKey }; if (googleMapKey) return { type: MAP_TYPE.G_MAP, key: googleMapKey }; @@ -30,8 +32,8 @@ export const loadMapSource = (type, key, callback) => { export default function loadBMap(ak) { return new Promise((resolve, reject) => { asyncLoadBaiduJs(ak) - .then(() => asyncLoadJs(`${mediaUrl}/js/map/text-icon-overlay.js`)) - .then(() => asyncLoadJs(`${mediaUrl}/js/map/marker-clusterer.js`)) + .then(() => asyncLoadJs(`${mediaUrl}/js/map/text-icon-overlay.js?v=${STATIC_RESOURCE_VERSION}`)) + .then(() => asyncLoadJs(`${mediaUrl}/js/map/marker-cluster.js?v=${STATIC_RESOURCE_VERSION}`)) .then(() => resolve(true)) .catch((err) => reject(err)); }); diff --git a/media/css/sf_font3/iconfont.css b/media/css/sf_font3/iconfont.css index def6c7fe63..b6650f591a 100644 --- a/media/css/sf_font3/iconfont.css +++ b/media/css/sf_font3/iconfont.css @@ -1,11 +1,11 @@ @font-face { font-family: "sf3-font"; /* Project id 1230969 */ - src: url('./iconfont.eot?t=1733301127109'); /* IE9 */ - src: url('./iconfont.eot?t=1733301127109#iefix') format('embedded-opentype'), /* IE6-IE8 */ - url('./iconfont.woff2?t=1733301127109') format('woff2'), - url('./iconfont.woff?t=1733301127109') format('woff'), - url('./iconfont.ttf?t=1733301127109') format('truetype'), - url('./iconfont.svg?t=1733301127109#sf3-font') format('svg'); + src: url('./iconfont.eot?t=1736476800596'); /* IE9 */ + src: url('./iconfont.eot?t=1736476800596#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('./iconfont.woff2?t=1736476800596') format('woff2'), + url('./iconfont.woff?t=1736476800596') format('woff'), + url('./iconfont.ttf?t=1736476800596') format('truetype'), + url('./iconfont.svg?t=1736476800596#sf3-font') format('svg'); } .sf3-font { @@ -16,6 +16,30 @@ -moz-osx-font-smoothing: grayscale; } +.sf3-font-zoom-out:before { + content: "\e630"; +} + +.sf3-font-current-location:before { + content: "\e62e"; +} + +.sf3-font-zoom-in:before { + content: "\e62f"; +} + +.sf3-font-ai:before { + content: "\e854"; +} + +.sf3-font-time:before { + content: "\e852"; +} + +.sf3-font-description:before { + content: "\e853"; +} + .sf3-font-hi:before { content: "\e603"; } @@ -24,10 +48,6 @@ content: "\e851"; } -.sf3-font-current-location:before { - content: "\e850"; -} - .sf3-font-ai_generated:before { content: "\e84f"; } diff --git a/media/css/sf_font3/iconfont.eot b/media/css/sf_font3/iconfont.eot index 4bb9fed7ba..bfefade4d6 100644 Binary files a/media/css/sf_font3/iconfont.eot and b/media/css/sf_font3/iconfont.eot differ diff --git a/media/css/sf_font3/iconfont.svg b/media/css/sf_font3/iconfont.svg index d40bdac538..e3a48dd6bf 100644 --- a/media/css/sf_font3/iconfont.svg +++ b/media/css/sf_font3/iconfont.svg @@ -14,12 +14,22 @@ /> + + + + + + + + + + + + - - @@ -188,7 +198,7 @@ - + @@ -224,7 +234,7 @@ - + diff --git a/media/css/sf_font3/iconfont.ttf b/media/css/sf_font3/iconfont.ttf index 0a1dae1a5d..6e2143aaa5 100644 Binary files a/media/css/sf_font3/iconfont.ttf and b/media/css/sf_font3/iconfont.ttf differ diff --git a/media/css/sf_font3/iconfont.woff b/media/css/sf_font3/iconfont.woff index 77a4a0b7a7..0d71528c2b 100644 Binary files a/media/css/sf_font3/iconfont.woff and b/media/css/sf_font3/iconfont.woff differ diff --git a/media/css/sf_font3/iconfont.woff2 b/media/css/sf_font3/iconfont.woff2 index 48dbc69dbe..f576b8fab3 100644 Binary files a/media/css/sf_font3/iconfont.woff2 and b/media/css/sf_font3/iconfont.woff2 differ diff --git a/media/js/map/marker-clusterer.js b/media/js/map/marker-cluster.js similarity index 95% rename from media/js/map/marker-clusterer.js rename to media/js/map/marker-cluster.js index e29c871024..42fc369509 100644 --- a/media/js/map/marker-clusterer.js +++ b/media/js/map/marker-cluster.js @@ -111,7 +111,7 @@ var BMapLib = window.BMapLib = BMapLib || {}; * girdSize {Number} 聚合计算时网格的像素大小,默认60
* maxZoom {Number} 最大的聚合级别,大于该级别就不进行相应的聚合
* minClusterSize {Number} 最小的聚合数量,小于该数量的不能成为一个聚合,默认为2
- * isAverangeCenter {Boolean} 聚合点的落脚位置是否是所有聚合在内点的平均值,默认为否,落脚在聚合内的第一个点
+ * isAvgCenter {Boolean} 聚合点的落脚位置是否是所有聚合在内点的平均值,默认为否,落脚在聚合内的第一个点
* styles {Array} 自定义聚合后的图标风格,请参考TextIconOverlay类
*/ BMapLib.MarkerCluster = function(map, options){ @@ -142,8 +142,8 @@ var BMapLib = window.BMapLib = BMapLib || {}; // that._redraw(); // }); - var mkrs = opts["markers"]; - isArray(mkrs) && this.addMarkers(mkrs); + var markers = opts["markers"]; + isArray(markers) && this.addMarkers(markers); }; /** @@ -454,19 +454,19 @@ var BMapLib = window.BMapLib = BMapLib || {}; * Cluster * @class 表示一个聚合对象,该聚合,包含有N个标记,这N个标记组成的范围,并有予以显示在Map上的TextIconOverlay等。 * @constructor - * @param {MarkerCluster} markerClusterer 一个标记聚合器示例。 + * @param {MarkerCluster} markerCluster 一个标记聚合器示例。 */ - function Cluster(markerClusterer){ - this._markerClusterer = markerClusterer; - this._map = markerClusterer.getMap(); - this._minClusterSize = markerClusterer.getMinClusterSize(); - this._isAverageCenter = markerClusterer.isAverageCenter(); + function Cluster(markerCluster){ + this._markerCluster = markerCluster; + this._map = markerCluster.getMap(); + this._minClusterSize = markerCluster.getMinClusterSize(); + this._isAverageCenter = markerCluster.isAverageCenter(); this._center = null;//落脚位置 this._markers = [];//这个Cluster中所包含的markers this._gridBounds = null;//以中心点为准,向四边扩大gridSize个像素的范围,也即网格范围 this._isReal = false; //真的是个聚合 - this._clusterMarker = new BMapLib.TextIconOverlay(this._center, this._markers.length, {"styles":this._markerClusterer.getStyles()}); + this._clusterMarker = new BMapLib.TextIconOverlay(this._center, this._markers.length, {"styles":this._markerCluster.getStyles()}); //this._map.addOverlay(this._clusterMarker); } @@ -552,7 +552,7 @@ var BMapLib = window.BMapLib = BMapLib || {}; */ Cluster.prototype.updateGridBounds = function() { var bounds = new BMapGL.Bounds(this._center, this._center); - this._gridBounds = getExtendedBounds(this._map, bounds, this._markerClusterer.getGridSize()); + this._gridBounds = getExtendedBounds(this._map, bounds, this._markerCluster.getGridSize()); }; /** @@ -560,7 +560,7 @@ var BMapLib = window.BMapLib = BMapLib || {}; * @return 无返回值。 */ Cluster.prototype.updateClusterMarker = function () { - if (this._map.getZoom() > this._markerClusterer.getMaxZoom()) { + if (this._map.getZoom() > this._markerCluster.getMaxZoom()) { this._clusterMarker && this._map.removeOverlay(this._clusterMarker); for (var i = 0, marker; marker = this._markers[i]; i++) { this._map.addOverlay(marker); @@ -589,9 +589,9 @@ var BMapLib = window.BMapLib = BMapLib || {}; return; } clickTimeout = setTimeout(() => { - if (this._markerClusterer && typeof this._markerClusterer.getCallback() === 'function') { + if (this._markerCluster && typeof this._markerCluster.getCallback() === 'function') { const markers = this._markers; - this._markerClusterer.getCallback()(event, markers); + this._markerCluster.getCallback()(event, markers); } clickTimeout = null; }, 300); // Delay to differentiate between single and double click diff --git a/media/js/map/text-icon-overlay.js b/media/js/map/text-icon-overlay.js index 963f811617..c713ea3670 100644 --- a/media/js/map/text-icon-overlay.js +++ b/media/js/map/text-icon-overlay.js @@ -211,7 +211,7 @@ var BMapLib = window.BMapLib = BMapLib || {}; * @returns {string} 驼峰化处理后的字符串 */ baidu.string.toCamelCase = function (source) { - //提前判断,提高getStyle等的效率 thanks xianwei + //提前判断,提高getStyle等的效率 if (source.indexOf('-') < 0 && source.indexOf('_') < 0) { return source; } @@ -649,7 +649,7 @@ var BMapLib = window.BMapLib = BMapLib || {}; * @grammar obj.dispatchEvent(event, options) * @param {baidu.lang.Event|String} event Event对象,或事件名称(1.1.1起支持) * @param {Object} options 扩展参数,所含属性键值会扩展到Event对象上(1.2起支持) - * @remark 处理会调用通过addEventListenr绑定的自定义事件回调函数之外,还会调用直接绑定到对象上面的自定义事件。例如:
+ * @remark 处理会调用通过addEventListener绑定的自定义事件回调函数之外,还会调用直接绑定到对象上面的自定义事件。例如:
myobj.onMyEvent = function(){}
myobj.addEventListener("onMyEvent", function(){}); */ @@ -767,7 +767,7 @@ var BMapLib = window.BMapLib = BMapLib || {}; }; /** - *继承Overlay的intialize方法,自定义覆盖物时必须。 + *继承Overlay的initialize方法,自定义覆盖物时必须。 *@param {Map} map BMapGL.Map的实例化对象。 *@return {HTMLElement} 返回覆盖物对应的HTML元素。 */ @@ -860,21 +860,20 @@ var BMapLib = window.BMapLib = BMapLib || {}; var style = this.getStyleByText(this._text, this._styles); var newStyle = { url: imageUrl, - size: {width: 72, height: 72} + size: { width: 86, height: 86 } } if (imageUrl) { - style = Object.assign(style, {url: imageUrl, size: {width: 72, height: 72}}) + style = Object.assign(style, { url: imageUrl, size: { width: 86, height: 86 } }) } - const customImageNumber = `${this._text}`; + const customImageNumber = `${this._text < 1000 ? this._text : '1k+'}`; this._domElement.style.cssText = this.buildImageCssText(newStyle); - const imageElement = `` + const imageElement = `` const htmlString = ` -
- ${this._text > 1 ? customImageNumber : ''} - ${imageUrl ? imageElement : '
'} - -
+
+ ${this._text > 1 ? customImageNumber : ''} + ${imageUrl ? imageElement : '
'} +
` const labelDocument = new DOMParser().parseFromString(htmlString, 'text/html'); const label = labelDocument.body.firstElementChild; @@ -888,14 +887,14 @@ var BMapLib = window.BMapLib = BMapLib || {}; var textColor = style['textColor'] || 'black'; var textSize = style['textSize'] || 10; - var csstext = []; + var cssText = []; - csstext.push('height:' + size.height + 'px; line-height:' + size.height + 'px;'); - csstext.push('width:' + size.width + 'px; text-align:center;'); + cssText.push('height:' + size.height + 'px; line-height:' + size.height + 'px;'); + cssText.push('width:' + size.width + 'px; text-align:center;'); - csstext.push('cursor:pointer; color:' + textColor + '; position:absolute; font-size:' + + cssText.push('cursor:pointer; color:' + textColor + '; position:absolute; font-size:' + textSize + 'px; font-family:Arial,sans-serif; font-weight:bold'); - return csstext.join(''); + return cssText.join(''); }; /** @@ -937,34 +936,34 @@ var BMapLib = window.BMapLib = BMapLib || {}; var textColor = style['textColor'] || 'black'; var textSize = style['textSize'] || 10; - var csstext = []; + var cssText = []; if (T.browser["ie"] < 7) { - csstext.push('filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(' + + cssText.push('filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(' + 'sizingMethod=scale,src="' + url + '");'); } else { - csstext.push('background-image:url(' + url + ');'); + cssText.push('background-image:url(' + url + ');'); var backgroundPosition = '0 0'; (offset instanceof BMapGL.Size) && (backgroundPosition = offset.width + 'px' + ' ' + offset.height + 'px'); - csstext.push('background-position:' + backgroundPosition + ';'); + cssText.push('background-position:' + backgroundPosition + ';'); } if (size instanceof BMapGL.Size){ if (anchor instanceof BMapGL.Size) { if (anchor.height > 0 && anchor.height < size.height) { - csstext.push('height:' + (size.height - anchor.height) + 'px; padding-top:' + anchor.height + 'px;'); + cssText.push('height:' + (size.height - anchor.height) + 'px; padding-top:' + anchor.height + 'px;'); } if(anchor.width > 0 && anchor.width < size.width){ - csstext.push('width:' + (size.width - anchor.width) + 'px; padding-left:' + anchor.width + 'px;'); + cssText.push('width:' + (size.width - anchor.width) + 'px; padding-left:' + anchor.width + 'px;'); } } else { - csstext.push('height:' + size.height + 'px; line-height:' + size.height + 'px;'); - csstext.push('width:' + size.width + 'px; text-align:center;'); + cssText.push('height:' + size.height + 'px; line-height:' + size.height + 'px;'); + cssText.push('width:' + size.width + 'px; text-align:center;'); } } - csstext.push('cursor:pointer; color:' + textColor + '; position:absolute; font-size:' + + cssText.push('cursor:pointer; color:' + textColor + '; position:absolute; font-size:' + textSize + 'px; font-family:Arial,sans-serif; font-weight:bold'); - return csstext.join(''); + return cssText.join(''); };