Skip to content

Commit d332844

Browse files
authored
feat: map-block changing the logic of zoom and center (#219)
1 parent 377b1f5 commit d332844

File tree

8 files changed

+71
-44
lines changed

8 files changed

+71
-44
lines changed

src/components/Map/GoogleMap.tsx

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,37 @@ import {GMapProps} from '../../models';
77
import {LocaleContext} from '../../context/localeContext/localeContext';
88
import {MobileContext} from '../../context/mobileContext';
99
import {getMapHeight} from './helpers';
10+
import {Lang} from '../../utils/configure';
1011

1112
const b = block('map');
1213

13-
function getScriptSrc(apiKey: string, scriptSrc: string, address: string, lang: 'ru' | 'en') {
14-
return `${scriptSrc}?key=${apiKey}&language=${lang}&q=${encodeURI(address)}`;
14+
interface GoogleMapLinkParams {
15+
apiKey: string;
16+
scriptSrc: string;
17+
address: string;
18+
lang: Lang;
19+
zoom?: number;
20+
}
21+
22+
function getScriptSrc(params: GoogleMapLinkParams) {
23+
const {apiKey, scriptSrc, address, lang, zoom} = params;
24+
25+
return `${scriptSrc}?key=${apiKey}&language=${lang}${zoom ? '&zoom=' + zoom : ''}&q=${encodeURI(
26+
address,
27+
)}`;
1528
}
1629

1730
const GoogleMap: React.FC<GMapProps> = (props) => {
18-
const {address} = props;
31+
const {address, zoom} = props;
1932
const {apiKey, scriptSrc} = useContext(MapsContext);
20-
const {lang = 'ru'} = useContext(LocaleContext);
33+
const {lang = Lang.Ru} = useContext(LocaleContext);
2134
const isMobile = useContext(MobileContext);
2235

2336
const [height, setHeight] = useState<number | undefined>(undefined);
2437
const ref = useRef<HTMLIFrameElement>(null);
2538
const src = useMemo(
26-
() => getScriptSrc(apiKey, scriptSrc, address, lang),
27-
[apiKey, scriptSrc, address, lang],
39+
() => getScriptSrc({apiKey, scriptSrc, address, lang, zoom}),
40+
[apiKey, scriptSrc, address, lang, zoom],
2841
);
2942

3043
useEffect(() => {

src/components/Map/Map.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,14 @@ $block: '.#{$ns}map';
1010
overflow: hidden;
1111
display: flex;
1212

13+
&_hidden {
14+
opacity: 0;
15+
}
16+
1317
&__spinner {
1418
margin: 0 auto;
1519
align-self: center;
20+
position: absolute;
1621
}
1722

1823
&__wrapper {
@@ -21,5 +26,6 @@ $block: '.#{$ns}map';
2126
flex-direction: column;
2227
align-items: center;
2328
justify-content: center;
29+
position: relative;
2430
}
2531
}

src/components/Map/README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ Map
22

33
`type: "map"`
44

5-
`center: number[]` - Geo coordinates of the map center, required for `Yandex maps`
6-
75
`zoom?: number` - Map zoom level. In google maps values ranging from 0 (the whole world) to 21 (individual buildings). In Yandex maps values ranging from 1 (the whole world) to 16 (individual buildings)
86

97
`address?: string;` - URL-escaped place name, address. You need to use it for `Google maps`

src/components/Map/YMap/YMap.ts

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {Coordinate} from '../../../models/constructor-items/common';
22

3-
import {YMapMarker, YMapMarkerLabel} from '../../../models';
3+
import {YMapProps, YMapMarker, YMapMarkerLabel} from '../../../models';
44

55
enum GeoObjectTypes {
66
Properties = 'properties',
@@ -19,6 +19,8 @@ const geoObjectPropsAndOptions = {
1919
preset: GeoObjectTypes.Options,
2020
};
2121

22+
type PlacemarksProps = Pick<YMapProps, 'zoom' | 'markers'>;
23+
2224
export class YMap {
2325
private ymap: Ymaps.Map;
2426
private mapRef: HTMLDivElement | null;
@@ -29,18 +31,18 @@ export class YMap {
2931
this.mapRef = mapRef;
3032
}
3133

32-
async showPlacemarks(markers: YMapMarker[]) {
34+
async showPlacemarks(props: PlacemarksProps) {
3335
this.clearOldPlacemarks();
3436

35-
for (const marker of markers) {
37+
for (const marker of props.markers) {
3638
if (marker.address) {
3739
await this.findAddress(marker);
3840
} else if (marker.coordinate) {
3941
this.findCoordinate(marker);
4042
}
4143
}
4244

43-
this.recalcZoomAndCenter();
45+
this.recalcZoomAndCenter(props);
4446
}
4547

4648
async findAddress(marker: YMapMarker) {
@@ -66,11 +68,7 @@ export class YMap {
6668
}
6769

6870
private drawPlaceMarkStyle(geoObject: Ymaps.GeoObject, marker: YMapMarker) {
69-
if (!marker.label) {
70-
return;
71-
}
72-
73-
const {iconColor, preset = DEFAULT_PLACEMARKS_PRESET} = marker.label;
71+
const {iconColor, preset = DEFAULT_PLACEMARKS_PRESET} = marker.label || {};
7472
let localIconColor: string | undefined = iconColor;
7573

7674
// You can set the preset option together with the iconColor option only if it not a 'Stretchy' preset
@@ -90,8 +88,9 @@ export class YMap {
9088
);
9189
}
9290

93-
private recalcZoomAndCenter() {
91+
private recalcZoomAndCenter(props: PlacemarksProps) {
9492
const coordsLength = this.coords.length;
93+
const {zoom = 0} = props;
9594

9695
if (!coordsLength) {
9796
return;
@@ -105,17 +104,27 @@ export class YMap {
105104
rightTop = [Math.max(rightTop[0], point[0]), Math.max(rightTop[1], point[1])];
106105
});
107106

108-
const newMapParams = window.ymaps.util.bounds.getCenterAndZoom(
109-
[leftBottom, rightTop],
110-
[this.mapRef?.clientWidth, this.mapRef?.clientHeight],
111-
undefined,
112-
{margin: DEFAULT_MAP_CONTROL_BUTTON_HEIGHT},
113-
);
107+
let newMapParams = {
108+
zoom,
109+
center: [],
110+
};
111+
112+
if (zoom) {
113+
// compute only the center
114+
newMapParams.center = window.ymaps.util.bounds.getCenter([leftBottom, rightTop]);
115+
} else {
116+
newMapParams = window.ymaps.util.bounds.getCenterAndZoom(
117+
[leftBottom, rightTop],
118+
[this.mapRef?.clientWidth, this.mapRef?.clientHeight],
119+
undefined,
120+
{margin: DEFAULT_MAP_CONTROL_BUTTON_HEIGHT},
121+
);
122+
}
114123

115124
this.ymap.setCenter(newMapParams.center);
116125

117126
// Use default zoom for one placemark
118-
if (coordsLength > 1) {
127+
if (coordsLength > 1 && !zoom) {
119128
this.ymap.setZoom(newMapParams.zoom);
120129
}
121130
}

src/components/Map/YMap/YandexMap.tsx

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@ import {getMapHeight} from '../helpers';
1616
const b = block('map');
1717
const DEFAULT_CONTAINER_ID = 'ymap';
1818
const DEFAULT_ZOOM = 9;
19+
// Center - is a required parameter for creating a new map
20+
// We use this init center to create a map
21+
// The real center of the map will be calculated later, using the coordinates of the markers
22+
const INITIAL_CENTER = [0, 0];
1923

2024
const YandexMap: React.FC<YMapProps> = (props) => {
21-
const {markers, zoom, center, id} = props;
25+
const {markers, zoom, id} = props;
2226
const {apiKey, scriptSrc, nonce} = useContext(MapsContext);
2327
const isMobile = useContext(MobileContext);
2428

@@ -30,17 +34,14 @@ const YandexMap: React.FC<YMapProps> = (props) => {
3034
const ref = useRef<HTMLDivElement>(null);
3135

3236
const [loading, setLoading] = useState<boolean>(false);
37+
const [ready, setReady] = useState<boolean>(false);
3338
const [attemptsIndex, setAttemptsIndex] = useState<number>(0);
3439
const onTryAgain = useCallback(() => {
3540
setAttemptsIndex(attemptsIndex + 1);
3641
}, [attemptsIndex]);
3742

3843
useEffect(() => {
3944
(async function () {
40-
if (!center) {
41-
return;
42-
}
43-
4445
setLoading(true);
4546

4647
await YMapsApiLoader.loadApi(apiKey, scriptSrc, lang, nonce);
@@ -51,7 +52,7 @@ const YandexMap: React.FC<YMapProps> = (props) => {
5152
new window.ymaps.Map(
5253
containerId,
5354
{
54-
center,
55+
center: INITIAL_CENTER,
5556
zoom: zoom || DEFAULT_ZOOM,
5657
},
5758
{autoFitToViewport: 'always'},
@@ -63,7 +64,7 @@ const YandexMap: React.FC<YMapProps> = (props) => {
6364

6465
setLoading(false);
6566
})();
66-
}, [apiKey, lang, scriptSrc, containerId, zoom, center, nonce, attemptsIndex, setLoading]);
67+
}, [apiKey, lang, scriptSrc, containerId, zoom, nonce, attemptsIndex, setLoading]);
6768

6869
useEffect(() => {
6970
const updateSize = _.debounce(() => {
@@ -82,11 +83,18 @@ const YandexMap: React.FC<YMapProps> = (props) => {
8283

8384
useEffect(() => {
8485
if (ymap) {
85-
ymap.showPlacemarks(markers);
86+
// show with computed center and placemarks
87+
const showPlacemarks = async () => {
88+
await ymap.showPlacemarks({markers, zoom});
89+
90+
setReady(true);
91+
};
92+
93+
showPlacemarks();
8694
}
8795
});
8896

89-
if (!center) return null;
97+
if (!markers) return null;
9098

9199
return (
92100
<ErrorWrapper
@@ -96,7 +104,9 @@ const YandexMap: React.FC<YMapProps> = (props) => {
96104
handler={onTryAgain}
97105
className={b('wrapper')}
98106
>
99-
<div id={containerId} className={b()} ref={ref} style={{height}}>
107+
<div className={b('wrapper')}>
108+
{/* hidden - to show the map after calculating the center */}
109+
<div id={containerId} className={b({hidden: !ready})} ref={ref} style={{height}} />
100110
{loading ? <Spin size="xl" className={b('spinner')} /> : null}
101111
</div>
102112
</ErrorWrapper>

src/components/Map/__stories__/data.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
{
22
"ymap": {
3-
"zoom": 9,
43
"id": "common-places",
5-
"center": [55.753994, 37.622093],
64
"markers": [
75
{
86
"address": "Moscow Arbat",
@@ -27,7 +25,6 @@
2725
]
2826
},
2927
"gmap": {
30-
"zoom": 9,
3128
"address": "Anthony Fokkerweg 1, 1059 CM Amsterdam"
3229
}
3330
}

src/models/constructor-items/common.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,6 @@ export type Coordinate = number[];
244244

245245
export interface MapBaseProps {
246246
zoom?: number;
247-
center?: Coordinate;
248247
}
249248
export interface GMapProps extends MapBaseProps {
250249
address: string;
@@ -253,7 +252,6 @@ export interface GMapProps extends MapBaseProps {
253252
export interface YMapProps extends MapBaseProps {
254253
markers: YMapMarker[];
255254
id: string;
256-
center: Coordinate;
257255
}
258256

259257
export interface YMapMarker {

src/schema/validators/common.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -549,10 +549,6 @@ export const MapProps = {
549549
zoom: {
550550
type: 'number',
551551
},
552-
center: {
553-
type: 'array',
554-
items: {type: 'number'},
555-
},
556552
address: {
557553
type: 'string',
558554
},

0 commit comments

Comments
 (0)