123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649 |
- import AMapLoader from '@amap/amap-jsapi-loader';
- import { nanoid } from 'nanoid';
- import { deepClone } from '@/utils';
- import { mergeGeoJsonPolygons, wgs_gcj_encrypts } from '@/utils/gisUtils';
- export function useAMap(options) {
- let AMap, map, nowLayer, labelsLayer, scale, cluster;
- const markers = {
- point: []
- };
- let clickMarker = null;
- let addPoints = [];
- // 初始化事件
- const initMap = (options) => {
- window._AMapSecurityConfig = {
- securityJsCode: options.securityJsCode
- };
- AMapLoader.load({
- key: options.key, // 申请好的Web端开发者Key,首次调用 load 时必填
- version: !!options.version ? options.version : '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
- plugins: options.plugins
- ? options.plugins
- : [
- 'AMap.Scale',
- 'AMap.RangingTool',
- 'AMap.MouseTool',
- 'AMap.PolygonEditor',
- 'AMap.MarkerCluster',
- 'AMap.DistrictSearch',
- 'AMap.MoveAnimation',
- 'AMap.Driving',
- 'AMap.Geocoder',
- 'AMap.PlaceSearch',
- 'AMap.GeoJSON'
- ]
- }).then((res) => {
- AMap = res;
- map = new AMap.Map(options.el ? options.el : 'aMap', {
- WebGLParams: {
- preserveDrawingBuffer: true
- },
- // 是否为3D地图模式
- viewMode: '3D',
- pitch: options.pitch,
- // 初始化地图级别
- zoom: options.zoom ? options.zoom : 11,
- // 初始化地图中心点位置
- center: options.center,
- // 是否可拖拽
- dragEnable: options.dragEnable,
- // 是否允许通过鼠标滚轮来缩放
- scrollWheel: options.scrollWheel
- });
- // 初始化比例尺
- if (options.showScale) {
- scale = new AMap.Scale();
- map.addControl(scale);
- }
- if (typeof options.onLoadCompleted === 'function') {
- options.onLoadCompleted(AMap, map);
- }
- });
- };
- const getAMap = () => {
- return AMap;
- };
- const getMap = () => {
- return map;
- };
- const getScale = () => {
- return scale;
- };
- // 切换地图
- const switchMap = (type: string) => {
- if (type === 'vectorgraph') {
- map.removeLayer(nowLayer);
- } else if (type === 'satellite') {
- const satellite = new AMap.TileLayer.WMTS({
- // url: 'http://t0.tianditu.gov.cn/img_c/wmts',
- url: 'http://t4.tianditu.gov.cn/img_w/wmts',
- blend: false,
- tileSize: 256,
- params: {
- Layer: 'img',
- Version: '1.0.0',
- Format: 'tiles',
- TileMatrixSet: 'w',
- STYLE: 'default',
- tk: 'a8df87f1695d224d2679aa805c1268d9' // 申请的天地图开发者key
- }
- });
- satellite.setMap(map);
- // const satellite = new AMap.TileLayer.Satellite();
- // map.addLayer(satellite);
- nowLayer = satellite;
- }
- };
- // 添加搜索的标记的
- const addSearchMarker = (item) => {
- map.setZoom(18);
- map.setCenter(item.lnglat);
- addMarker([item], true);
- clickMarker = item;
- options.onMarkerClick(item);
- };
- // 添加多个点
- const addMarker = (points, notClean?: boolean) => {
- if (!notClean) {
- clearMarker('point');
- }
- addPoints = points;
- const count = points.length;
- const _renderClusterMarker = function (context) {
- // 聚合中点个数
- const clusterCount = context.count;
- const div = document.createElement('div');
- div.style.backgroundColor = 'rgba(78,179,211,.5)';
- const size = Math.round(25 + Math.pow(clusterCount / count, 1 / 5) * 20);
- div.style.width = div.style.height = size + 'px';
- div.style.border = 'solid 1px rgba(78,179,211,1)';
- div.style.borderRadius = size / 2 + 'px';
- div.innerHTML = context.count;
- div.style.lineHeight = size + 'px';
- div.style.color = '#ffffff';
- div.style.fontSize = '12px';
- div.style.textAlign = 'center';
- context.marker.setOffset(new AMap.Pixel(-size / 2, -size / 2));
- context.marker.setContent(div);
- context.marker.on('click', (e) => {
- const bounds = e.target.getBounds();
- map.setZoomAndCenter(map.getZoom() + 1, bounds.getCenter());
- });
- };
- const _renderMarker = function (context) {
- const content =
- '<div style="display: flex;flex-direction: column;align-items: center;justify-content: center">' +
- '<div style="background: url(' +
- context.data[0].icon +
- ') no-repeat; width: ' +
- context.data[0].size[0] +
- 'px;height: ' +
- context.data[0].size[1] +
- 'px;cursor: pointer; background-size: cover"></div>' +
- // '<div style="font-size: 36px;white-space: nowrap">'+ context.data[0].name +'</div>' +
- '</div>';
- const offset = new AMap.Pixel(-9, -9);
- context.marker.setContent(content);
- context.marker.setOffset(offset);
- context.marker.setExtData(context.data[0]);
- context.marker.on('click', function (e) {
- const extData = e.target.getExtData();
- let index = 0;
- let index2 = 0;
- for (let i = 0; i < addPoints.length; i++) {
- if (addPoints[i].id === extData.id && addPoints[i].imageHover) {
- addPoints[i].icon = addPoints[i].imageHover;
- e.target.setContent(content);
- index++;
- } else if (!!clickMarker) {
- const extData2 = clickMarker.getExtData();
- if (addPoints[i].id === extData2.id) {
- addPoints[i].icon = addPoints[i].image;
- clickMarker.setContent(content);
- index2++;
- }
- }
- if ((!!clickMarker && index === 1 && index2 === 1) || (!clickMarker && index === 1)) {
- break;
- }
- }
- addMarker(addPoints);
- clickMarker = e.target;
- options.onMarkerClick(extData);
- });
- };
- cluster = new AMap.MarkerCluster(
- map, //地图实例
- points, //海量点数据,数据中需包含经纬度信息字段 lnglat
- {
- gridSize: 30, //数据聚合计算时网格的像素大小
- renderClusterMarker: _renderClusterMarker, //上述步骤的自定义聚合点样式
- renderMarker: _renderMarker //上述步骤的自定义非聚合点样式
- }
- );
- points.forEach((item) => {
- markers['point'].push(item);
- });
- };
- // 清除所有标加
- const clearMarker = (id) => {
- if (!cluster || !markers[id]) return;
- cluster.setMap(null);
- markers[id] = [];
- };
- const handleHover = (extData, dataType) => {
- map.setZoom(18);
- map.setCenter([extData.lng, extData.lat]);
- setTimeout(() => {
- let index = 0;
- let index2 = 0;
- let data = {};
- for (let i = 0; i < addPoints.length; i++) {
- if (addPoints[i].id === extData.id.toString() && addPoints[i].dataType === dataType) {
- addPoints[i].icon = addPoints[i].imageHover;
- index++;
- data = addPoints[i];
- } else if (!!clickMarker) {
- const extData2 = clickMarker.getExtData ? clickMarker.getExtData() : clickMarker;
- if (addPoints[i].id === extData2.id) {
- addPoints[i].icon = addPoints[i].image;
- index2++;
- }
- }
- if ((!!clickMarker && index === 1 && index2 === 1) || (!clickMarker && index === 1)) {
- break;
- }
- }
- addMarker(addPoints);
- options.onMarkerClick(data);
- }, 2000);
- };
- const getMarkers = () => {
- return markers;
- };
- // 显示信息框
- let infoWindow;
- const showInfo = (content, position, isCustom) => {
- hideInfo();
- // 实例化InfoWindow
- infoWindow = new AMap.InfoWindow({
- // 完全自定义
- isCustom: isCustom,
- autoMove: false,
- offset: new AMap.Pixel(0, -20) // 信息窗体的偏移量
- // 可以根据需要设置其他InfoWindow的属性
- });
- const lnglat = new AMap.LngLat(position[0], position[1]);
- // 打开InfoWindow,并设置其内容和位置
- infoWindow.setContent(content);
- infoWindow.open(map, lnglat);
- // 解决2.0版本无法滚动问题
- infoWindow.on('mouseover', () => map.setStatus({ zoomEnable: false }));
- infoWindow.on('mouseout', () => map.setStatus({ zoomEnable: true }));
- };
- const hideInfo = (e) => {
- map.setStatus({ zoomEnable: true });
- if (!!infoWindow) {
- infoWindow.close();
- if (!!clickMarker && e) {
- const extData = clickMarker.getExtData ? clickMarker.getExtData() : clickMarker;
- for (let i = 0; i < addPoints.length; i++) {
- if (addPoints[i].id === extData.id) {
- addPoints[i].icon = addPoints[i].image;
- clickMarker = null;
- addMarker(addPoints);
- break;
- }
- }
- }
- }
- };
- let maskPolygon;
- const creatMask = (options, name = '茂名市') => {
- new AMap.DistrictSearch({
- extensions: 'all',
- subdistrict: 0
- }).search(name, function (status, result) {
- // 外多边形坐标数组和内多边形坐标数组
- const outer = [
- new AMap.LngLat(-360, 90, true),
- new AMap.LngLat(-360, -90, true),
- new AMap.LngLat(360, -90, true),
- new AMap.LngLat(360, 90, true)
- ];
- options.forEach((option) => {
- const holes = result.districtList[0].boundaries;
- const pathArray = [outer];
- pathArray.push.apply(pathArray, holes);
- maskPolygon = new AMap.Polygon({
- pathL: pathArray,
- strokeColor: option.strokeColor ? option.strokeColor : '#268ab9',
- strokeOpacity: option.strokeOpacity ? option.strokeOpacity : 1,
- strokeWeight: option.strokeWeight ? option.strokeWeight : 1,
- fillColor: option.fillColor ? option.fillColor : '#10243b',
- fillOpacity: option.fillOpacity ? option.fillOpacity : 0.65
- });
- maskPolygon.setPath(pathArray);
- map.add(maskPolygon);
- });
- });
- };
- const removeMask = () => {
- if (!!maskPolygon) {
- map.remove(maskPolygon);
- maskPolygon = null;
- }
- };
- let maskPolygon2 = [];
- const creatMask2 = (data, option) => {
- if (maskPolygon2 && maskPolygon2.length > 0) {
- maskPolygon2.forEach((polygon) => {
- polygon.show();
- });
- } else {
- data = convertCoordinates(data);
- // 遮罩部分
- // const outer = [
- // new AMap.LngLat(-180, 90, true),
- // new AMap.LngLat(-180, -90, true),
- // new AMap.LngLat(180, -90, true),
- // new AMap.LngLat(180, 90, true)
- // ];
- // const pathArray = [outer];
- // 合并区边界
- // const data2 = mergeGeoJsonPolygons(data);
- // data2.geometry.coordinates.forEach((coords) => {
- // pathArray.push(coords[0]);
- // });
- // const maskPolygon = new AMap.Polygon({
- // path: pathArray,
- // strokeColor: option.strokeColor ? option.strokeColor : '#268ab9',
- // strokeOpacity: 1,
- // strokeWeight: option.strokeWeight ? option.strokeWeight : 1,
- // fillColor: option.fillColor ? option.fillColor : '#10243b',
- // fillOpacity: option.fillOpacity ? option.fillOpacity : 0.65
- // });
- // maskPolygon2.push(maskPolygon);
- // map.add(maskPolygon);
- // 边界部分
- data.features.forEach((feature) => {
- if (feature.geometry.type === 'Polygon') {
- const polygonPath = feature.geometry.coordinates[0].map((coord) => {
- return [coord[0], coord[1]];
- });
- const polygon = new AMap.Polyline({
- path: polygonPath,
- strokeColor: option.strokeColor ? option.strokeColor : '#268ab9',
- strokeOpacity: option.strokeOpacity ? option.strokeOpacity : 1,
- strokeWeight: option.strokeWeight ? option.strokeWeight : 1,
- clickable: false
- });
- maskPolygon2.push(polygon);
- map.add(polygon);
- } else if (feature.geometry.type === 'MultiPolygon') {
- feature.geometry.coordinates.forEach((polygonCoords) => {
- const polygonPath = polygonCoords.map((ring) => {
- return ring.map((coord) => {
- return [coord[0], coord[1]];
- });
- });
- const outerPath = polygonPath[0];
- const innerPaths = polygonPath.slice(1);
- const polygon = new AMap.Polyline({
- path: outerPath,
- holes: innerPaths,
- strokeColor: option.strokeColor ? option.strokeColor : '#268ab9',
- strokeOpacity: option.strokeOpacity ? option.strokeOpacity : 1,
- strokeWeight: option.strokeWeight ? option.strokeWeight : 1,
- clickable: false
- });
- maskPolygon2.push(polygon);
- map.add(polygon);
- });
- }
- });
- }
- };
- const removeMask2 = (isHidden) => {
- if (maskPolygon2 && maskPolygon2.length > 0) {
- maskPolygon2.forEach((polygon) => {
- polygon.hide();
- });
- if (!isHidden) {
- maskPolygon2 = [];
- }
- }
- };
- let moveMarker, movePolyline, movePassedPolyline, timerId;
- const trackPlayback = (lineArr) => {
- if (timerId) {
- clearTimeout(timerId);
- }
- movePolyline?.remove();
- movePassedPolyline?.remove();
- moveMarker?.remove();
- let index = 0;
- const icon = new AMap.Icon({
- size: new AMap.Size(26, 52),
- image: 'https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png'
- });
- moveMarker = new AMap.Marker({
- map: map,
- position: [116.478935, 39.997761],
- icon: icon,
- offset: new AMap.Pixel(-13, -26)
- });
- // 绘制轨迹
- movePolyline = new AMap.Polyline({
- map: map,
- path: lineArr,
- showDir: true,
- strokeColor: '#28F', //线颜色
- // strokeOpacity: 1, //线透明度
- strokeWeight: 6 //线宽
- // strokeStyle: "solid" //线样式
- });
- movePassedPolyline = new AMap.Polyline({
- map: map,
- strokeColor: '#AF5', //线颜色
- strokeWeight: 6 //线宽
- });
- moveMarker.on('moving', function (e) {
- movePassedPolyline.setPath(e.passedPath);
- map.setCenter(e.target.getPosition(), true);
- });
- moveMarker.on('moveend', function (e) {
- index++;
- if (index === lineArr.length - 1) {
- timerId = setTimeout(() => {
- movePolyline.remove();
- movePassedPolyline.remove();
- moveMarker.remove();
- }, 5000);
- }
- });
- moveMarker.moveAlong(lineArr, {
- // 每一段的时长
- duration: 1000, //可根据实际采集时间间隔设置
- // JSAPI2.0 是否延道路自动设置角度在 moveAlong 里设置
- autoRotation: true
- });
- };
- const drawData = (data) => {
- const res = [];
- data.forEach((item) => {
- let graphic;
- if (['rectangle', 'polygon', 'anyLine'].includes(item.type)) {
- graphic = new AMap.Polygon({
- path: item.path,
- strokeColor: item.strokeColor,
- strokeOpacity: item.strokeOpacity,
- strokeWeight: item.strokeWeight,
- fillColor: item.fillColor,
- fillOpacity: item.fillOpacity
- });
- graphic._opts.extData = {
- id: item.id
- };
- map.add(graphic);
- res.push(graphic);
- } else if (item.type === 'circle') {
- graphic = new AMap.Circle({
- center: item.center,
- radius: item.radius,
- strokeColor: item.strokeColor,
- strokeOpacity: item.strokeOpacity,
- strokeWeight: item.strokeWeight,
- fillColor: item.fillColor,
- fillOpacity: item.fillOpacity
- });
- graphic._opts.extData = {
- id: item.id
- };
- map.add(graphic);
- res.push(graphic);
- } else if (item.type === 'straightLine') {
- graphic = new AMap.Polyline({
- path: item.path,
- strokeColor: item.strokeColor,
- strokeOpacity: item.strokeOpacity,
- strokeWeight: item.strokeWeight,
- strokeStyle: item.strokeStyle
- });
- graphic._opts.extData = {
- id: item.id
- };
- map.add(graphic);
- res.push(graphic);
- } else if (item.type === 'text') {
- const { text } = addText(item);
- res.push(text);
- } else if (item.type === 'measureArea') {
- graphic = new AMap.Polygon({
- path: item.path,
- strokeColor: item.strokeColor,
- strokeOpacity: item.strokeOpacity,
- strokeWeight: item.strokeWeight,
- fillColor: item.fillColor,
- fillOpacity: item.fillOpacity
- });
- graphic._opts.extData = {
- id: item.id
- };
- map.add(graphic);
- // 计算区域面积
- const area = Math.round(AMap.GeometryUtil.ringArea(item.path));
- const text = new AMap.Text({
- position: item.path[item.path.length - 1],
- text: '区域面积' + area + '平方米',
- offset: new AMap.Pixel(-20, -20)
- });
- text._opts.extData = {
- id: item.id
- };
- data.area = area;
- map.add([graphic, text]);
- // res.push(text);
- } else if (item.type === 'marker') {
- // 创建标注点
- const marker = new AMap.Marker({
- position: new AMap.LngLat(item.longitude, item.latitude), // 标注点的位置
- icon: new AMap.Icon({
- size: item.size, //图标所处区域大小
- image: item.icon
- }),
- size: item.size
- });
- marker._opts.extData = {
- id: item.id
- };
- marker.setLabel({
- content: '<div>' + item.title + '</div>',
- direction: 'top'
- });
- map.add(marker);
- res.push(marker);
- }
- });
- return res;
- };
- const addText = (options) => {
- // 文本覆盖物的样式
- const textStyle = {
- fontSize: options.fontSize,
- color: options.fontColor,
- borderColor: 'transparent',
- backgroundColor: 'transparent',
- borderWidth: 0,
- cursor: 'pointer' // 鼠标悬停时显示指针
- };
- // 创建文本覆盖物
- const text = new AMap.Text({
- text: options.text, // 文本内容,可以根据需要自定义
- position: options.lnglat, // 文本位置(经纬度)
- style: textStyle, // 文本样式
- zIndex: 100, // 文本层级
- draggable: false // 是否可拖动(可选)
- });
- // 将文本覆盖物添加到地图
- map.add(text);
- const id = nanoid();
- text._opts.extData = {
- id: id
- };
- const data: any = deepClone(options);
- data.id = id;
- return { text, data };
- };
- const convertCoordinates = (geoJson) => {
- const features = geoJson.features.map((feature) => {
- const geometry = feature.geometry;
- let newGeometry;
- if (geometry.type === 'Point') {
- const [x, y] = geometry.coordinates;
- const obj = wgs_gcj_encrypts([{ lng: x, lat: y }])[0];
- newGeometry = { ...geometry, coordinates: [obj.lng, obj.lat] };
- } else if (geometry.type === 'MultiPoint') {
- const newCoordinates = geometry.coordinates.map((coords) => {
- const [x, y] = coords;
- const obj = wgs_gcj_encrypts([{ lng: x, lat: y }])[0];
- return [obj.lng, obj.lat];
- });
- newGeometry = { ...geometry, coordinates: newCoordinates };
- } else if (geometry.type === 'LineString') {
- const newCoordinates = geometry.coordinates.map((coords) => {
- const [x, y] = coords;
- const obj = wgs_gcj_encrypts([{ lng: x, lat: y }])[0];
- return [obj.lng, obj.lat];
- });
- newGeometry = { ...geometry, coordinates: newCoordinates };
- } else if (geometry.type === 'MultiLineString') {
- const newCoordinates = geometry.coordinates.map((line) =>
- line.map((coords) => {
- const [x, y] = coords;
- const obj = wgs_gcj_encrypts([{ lng: x, lat: y }])[0];
- return [obj.lng, obj.lat];
- })
- );
- newGeometry = { ...geometry, coordinates: newCoordinates };
- } else if (geometry.type === 'Polygon') {
- const newCoordinates = geometry.coordinates.map((polygon) =>
- polygon.map((coords) => {
- const [x, y] = coords;
- const obj = wgs_gcj_encrypts([{ lng: x, lat: y }])[0];
- return [obj.lng, obj.lat];
- })
- );
- newGeometry = { ...geometry, coordinates: newCoordinates };
- } else if (geometry.type === 'MultiPolygon') {
- const newCoordinates = geometry.coordinates.map((polygon) =>
- polygon.map((ring) =>
- ring.map((coords) => {
- const [x, y] = coords;
- const obj = wgs_gcj_encrypts([{ lng: x, lat: y }])[0];
- return [obj.lng, obj.lat];
- })
- )
- );
- newGeometry = { ...geometry, coordinates: newCoordinates };
- }
- return { ...feature, geometry: newGeometry };
- });
- return { ...geoJson, features };
- };
- onMounted(() => {
- initMap(options);
- });
- return {
- getAMap,
- getMap,
- switchMap,
- addMarker,
- addSearchMarker,
- clearMarker,
- getMarkers,
- getScale,
- showInfo,
- hideInfo,
- handleHover,
- creatMask,
- removeMask,
- creatMask2,
- removeMask2,
- trackPlayback,
- drawData
- };
- }
|