Измерения линейкой
Внимание!
В Vue 2 компонент завезти не удалось =(
html
<yandex-map
:height="height"
:settings="{
location: LOCATION,
theme,
showScaleInCopyrights: true,
}"
:width="width"
>
<yandex-map-default-scheme-layer/>
<yandex-map-default-features-layer/>
<yandex-map-controls :settings="{ position: 'top left' }">
<yandex-map-control>
<label class="editable">
editable
<input
v-model="editable"
type="checkbox"
>
</label>
<label>
Режим
<select v-model="mode">
<option value="ruler">
ruler
</option>
<option value="planimeter">
planimeter
</option>
</select>
</label>
</yandex-map-control>
</yandex-map-controls>
<yandex-map-controls :settings="{ position: 'top right' }">
<yandex-map-control>
<div class="info">
{{ totalLabel }}
</div>
</yandex-map-control>
</yandex-map-controls>
<yandex-map-ruler
v-model:points-state="state"
:settings="{
type: mode,
points: RULER_COORDINATES,
editable,
geometry: { style: FEATURE_STYLE } ,
onUpdate: setTotalLabel,
}"
>
<template #point="{ state: pointState, onDelete }">
<div
class="point"
:class="{ 'point--last': pointState.index === pointState.totalCount - 1 }"
@click="($event.target as HTMLElement).classList.toggle('point--active')"
>
<div class="point_popup">
{{ getLabel(pointState) }}
<div
class="point_popup_delete"
@click.stop.prevent="onDelete()"
>
Удалить точку
</div>
</div>
</div>
</template>
<template #previewPoint>
<div class="point point--preview"/>
</template>
</yandex-map-ruler>
</yandex-map>
ts
import { YandexMap, YandexMapControls, YandexMapDefaultFeaturesLayer, YandexMapDefaultSchemeLayer, YandexMapControl, YandexMapRuler } from 'vue-yandex-maps';
import { ref, shallowRef } from 'vue';
import type { YandexMapRulerSettings } from 'vue-yandex-maps';
import type { YMapLocationRequest } from '@yandex/ymaps3-types/imperative/YMap';
import type { RulerCommonState, RulerPointState } from '@yandex/ymaps3-types/modules/ruler/YMapRulerCommon';
import type { RenderPointArgs } from '@yandex/ymaps3-types/modules/ruler/YMapRuler';
const editable = ref(true);
const mode = ref<YandexMapRulerSettings['type']>('ruler');
const totalLabel = ref('');
const state = shallowRef<RenderPointArgs[]>([]);
const FEATURE_STYLE: DrawingStyle = {
simplificationRate: 0,
fill: '#666',
fillOpacity: 0.3,
stroke: [
{ width: 3, opacity: 0.7, color: '#666' },
{ width: 5, opacity: 0.7, color: '#fff' },
],
};
function formatDistance(distance: number): string {
return distance > 900 ? `${ roundDistance(distance / 1000) } km` : `${ roundDistance(distance) } m`;
}
function formatArea(area: number): string {
return area > 900_000
? `${ splitNumber(roundDistance(area / 1_000_000)) } km²`
: `${ splitNumber(roundDistance(area)) } m²`;
}
function roundDistance(distance: number): number {
if (distance > 100) {
return Math.round(distance);
}
const factor = Math.pow(10, distance > 10 ? 1 : 2);
return Math.round(distance * factor) / factor;
}
function splitNumber(value: number): string {
return value.toString().replace(/(\d)(?=(\d{3})+$)/g, '$1 ');
}
function setTotalLabel(state: RulerCommonState) {
totalLabel.value = state.measurements.type === 'ruler'
? `Total distance: ${ formatDistance(state.measurements.totalDistance) }`
: `Area: ${ formatArea(state.measurements.area) }`;
}
function getLabel(state: RulerPointState) {
return state.measurements.type === 'ruler'
? formatDistance(state.measurements.distance)
: formatArea(state.measurements.area);
}
const LOCATION: YMapLocationRequest = {
center: [31.245384, 30.051434], // starting position [lng, lat]
zoom: 3, // starting zoom
};
const RULER_COORDINATES: LngLat[] = [
[-0.128407, 51.506807], // London
[31.245384, 30.051434], // Cairo
[77.201224, 28.614653], // New Delhi
];
css
<style scoped>
.editable {
&, ~ * {
padding: 5px;
display: inline-block;
}
}
.info {
padding: 5px;
}
select {
border: 1px solid currentColor;
border-radius: 4px;
padding: 5px;
}
.point {
width: 24px;
height: 24px;
border-radius: 100%;
cursor: pointer;
background: green;
position: relative;
display: flex;
justify-content: center;
align-items: center;
&.point--preview {
background: red;
}
.point_popup {
display: none;
}
&.point--active, &.point--last {
.point_popup {
display: flex;
gap: 8px;
align-items: center;
position: absolute;
bottom: calc(100% + 10px);
background: #fff;
white-space: nowrap;
font-size: 12px;
padding: 5px;
border-radius: 8px;
cursor: default;
.point_popup_delete {
background: #ccc;
border-radius: 4px;
cursor: pointer;
padding: 2px 10px;
}
}
}
}
textarea {
width:100%;
height: 300px;
}
</style>