| | |
| | | * 网格绘制 |
| | | */ |
| | | import { map } from './index_old'; |
| | | import calculate from './calculate'; |
| | | import { Legend } from '@/model/Legend'; |
| | | import { getHexColor, getColorBetweenTwoColors } from '../color'; |
| | | |
| | | /** |
| | | * 角度增减,确保角度处于0 - 360度之间 |
| | | * @param {number} angle 原角度 |
| | | * @param {number} offset 偏移量 |
| | | */ |
| | | function plusAngle(angle, offset) { |
| | | const result = angle + offset; |
| | | if (result > 360) { |
| | | return result - 360; |
| | | } else if (result < 0) { |
| | | return result + 360; |
| | | } else { |
| | | return result; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 根据网格中心点,生成正方形网格4个顶点的坐标 |
| | | * @param {Array} points 网格中心点经纬度数组 |
| | | */ |
| | | function parseGridPoint(points) { |
| | | if (points.length < 2) throw new Error('坐标点数量小于2'); |
| | | const p1 = points[0]; |
| | | const p2 = points[1]; |
| | | // 两中心点间的角度 |
| | | const angle = calculate.getAngle(p1[0], p1[1], p2[0], p2[1]); |
| | | // const angle = calculate.bearing( |
| | | // { latitude: p1[0], longitude: p1[1] }, |
| | | // { latitude: p2[0], longitude: p2[1] } |
| | | // ); |
| | | // 两中心点间的距离 |
| | | const dis = calculate.getDistance(p1[0], p1[1], p2[0], p2[1]); |
| | | // 网格正方形对角线的一半长度 |
| | | const halfDiagonal = Math.sqrt((dis / 2) * (dis / 2) * 2); |
| | | // 计算首个正方形各顶点相对于中心点的角度,得到正方形各顶点的坐标 |
| | | const angle1 = plusAngle(angle, 45); |
| | | const gp1 = calculate.getLatLon(p1, halfDiagonal, angle1); |
| | | const angle2 = plusAngle(angle1, 90); |
| | | const gp2 = calculate.getLatLon(p1, halfDiagonal, angle2); |
| | | const angle3 = plusAngle(angle2, 90); |
| | | const gp3 = calculate.getLatLon(p1, halfDiagonal, angle3); |
| | | const angle4 = plusAngle(angle3, 90); |
| | | const gp4 = calculate.getLatLon(p1, halfDiagonal, angle4); |
| | | // 计算4个顶点分别与中心点的经纬度差值 |
| | | const diff = { |
| | | diff1: { |
| | | dx: gp1[0] - p1[0], |
| | | dy: gp1[1] - p1[1] |
| | | }, |
| | | diff2: { |
| | | dx: gp2[0] - p1[0], |
| | | dy: gp2[1] - p1[1] |
| | | }, |
| | | diff3: { |
| | | dx: gp3[0] - p1[0], |
| | | dy: gp3[1] - p1[1] |
| | | }, |
| | | diff4: { |
| | | dx: gp4[0] - p1[0], |
| | | dy: gp4[1] - p1[1] |
| | | } |
| | | }; |
| | | |
| | | // 得到所有正方形网格的4个顶点信息 |
| | | return points.map((p) => { |
| | | return [ |
| | | [p[0] + diff.diff1.dx, p[1] + diff.diff1.dy], |
| | | [p[0] + diff.diff2.dx, p[1] + diff.diff2.dy], |
| | | [p[0] + diff.diff3.dx, p[1] + diff.diff3.dy], |
| | | [p[0] + diff.diff4.dx, p[1] + diff.diff4.dy] |
| | | ]; |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * 文本标记 |
| | | * 可修改position |
| | | */ |
| | | function textMaker({ position, text, anchor, type, color }) { |
| | | let style = {}; |
| | | if (type == 'data') { |
| | | style = { |
| | | 'font-size': '12px', |
| | | 'text-align': 'center', |
| | | 'font-weight': 600, |
| | | color: color ? color : 'white', |
| | | background: '#122b54a9', |
| | | // background: 'white', |
| | | 'text-shadow': 'black 1px 1px 1px', |
| | | border: '0px', |
| | | 'margin-top': '4px' |
| | | }; |
| | | } else if (type == 'rank') { |
| | | style = { |
| | | 'font-size': '14px', |
| | | 'text-align': 'center', |
| | | color: color ? color : 'white', |
| | | background: 'transparent', |
| | | 'text-shadow': 'black 2px 2px 2px', |
| | | 'border-radius': '2px', |
| | | border: '1px solid #122b54a9', |
| | | // border: '1px solid rgba(255, 255, 255, 0.62)', |
| | | 'margin-bottom': '4px' |
| | | }; |
| | | } |
| | | // eslint-disable-next-line no-undef |
| | | return new AMap.Text({ |
| | | text: text, |
| | | anchor, |
| | | position: position, |
| | | style: style |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * 海量文本标注 |
| | | */ |
| | | function textLabelMarker(position, text, direction, style) { |
| | | // eslint-disable-next-line no-undef |
| | | return new AMap.LabelMarker({ |
| | | position: position, |
| | | zooms: [10, 20], |
| | | opacity: 1, |
| | | zIndex: 2, |
| | | // icon: { |
| | | // image: 'https://a.amap.com/jsapi_demos/static/images/poi-marker.png', |
| | | // anchor: 'bottom-center', |
| | | // size: [25, 34], |
| | | // clipOrigin: [459, 92], |
| | | // clipSize: [50, 68] |
| | | // }, |
| | | text: { |
| | | // 注意内容格式必须是string |
| | | content: text ? text + '' : '', |
| | | direction: direction ? direction : 'center', |
| | | style: { |
| | | 'border-radius': '.25rem', |
| | | fontSize: 12, |
| | | fillColor: '#fff', |
| | | strokeColor: 'rgba(0, 0, 0, 1)', |
| | | strokeWidth: 4, |
| | | // backgroundColor: '#122b54a9', |
| | | padding: [3, 10], |
| | | // backgroundColor: 'yellow', |
| | | borderColor: '#ccc', |
| | | borderWidth: 30 |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * 计算每个网格颜色 |
| | | */ |
| | | function calGridColor({ factorName, data, isCustomColor }) { |
| | | let _colorList = []; |
| | | if (isCustomColor) { |
| | | var max, min; |
| | | data.forEach((t) => { |
| | | if (!t) return; |
| | | if (!max || t > max) { |
| | | max = t; |
| | | } |
| | | if (!min || t < min) { |
| | | min = t; |
| | | } |
| | | }); |
| | | data.forEach((d) => { |
| | | if (d) { |
| | | // 根据遥测数据计算网格颜色 |
| | | const { color, nextColor, range, nextRange } = |
| | | Legend.getCustomColorAndNext(d, min, max); |
| | | const ratio = (d - range) / (nextRange - range); |
| | | |
| | | const _color = getColorBetweenTwoColors( |
| | | color.map((v) => v * 255), |
| | | nextColor.map((v) => v * 255), |
| | | ratio |
| | | ); |
| | | _colorList.push(_color); |
| | | } else { |
| | | _colorList.push(undefined); |
| | | } |
| | | }); |
| | | } else { |
| | | data.forEach((d) => { |
| | | if (d) { |
| | | // 根据遥测数据计算网格颜色 |
| | | const { color, nextColor, range, nextRange } = |
| | | Legend.getStandardColorAndNext(factorName, d); |
| | | const ratio = (d - range) / (nextRange - range); |
| | | const _color = getColorBetweenTwoColors( |
| | | color.map((v) => v * 255), |
| | | nextColor.map((v) => v * 255), |
| | | ratio |
| | | ); |
| | | _colorList.push(_color); |
| | | } else { |
| | | _colorList.push(undefined); |
| | | } |
| | | }); |
| | | } |
| | | return _colorList; |
| | | } |
| | | |
| | | export default { |
| | | parseGridPoint, |
| | | |
| | | /** |
| | | * 绘制网格风险图 |
| | | * @param {*} points |
| | | */ |
| | | drawRectangle: function (points) { |
| | | drawRectangle(points) { |
| | | const gridViews = []; |
| | | points.forEach((p) => { |
| | | const { lb, rt, c } = p; |
| | | |
| | | // eslint-disable-next-line no-undef |
| | | let pList = [lb, rt].map((v) => new AMap.LngLat(v[0], v[1])); |
| | | let pList = [lb, rt].map((v) => { |
| | | // eslint-disable-next-line no-undef |
| | | return new AMap.LngLat(v[0], v[1]); |
| | | }); |
| | | // eslint-disable-next-line no-undef |
| | | var bounds = new AMap.Bounds(...pList); |
| | | // eslint-disable-next-line no-undef |
| | | var rectangle = new AMap.Rectangle({ |
| | | bounds: bounds, |
| | | // strokeColor: '#ffffffff', |
| | | strokeWeight: 0, |
| | | strokeOpacity: 0, |
| | | strokeColor: '#ffffffff', |
| | | strokeWeight: 1, |
| | | strokeOpacity: 1, |
| | | // strokeStyle还支持 solid |
| | | strokeStyle: 'solid', |
| | | fillColor: '990D0D', |
| | | fillColor: '#990D0D', |
| | | fillOpacity: 0.8, |
| | | cursor: 'pointer', |
| | | zIndex: 50 |
| | | }); |
| | | |
| | | // var text = new AMap.Text({ |
| | | // text: p.value, |
| | | // anchor: 'center', // 设置文本标记锚点 |
| | | // draggable: false, |
| | | // style: { |
| | | // 'background-color': 'transparent', |
| | | // 'border-width': 0, |
| | | // 'text-align': 'center', |
| | | // 'font-size': '12px', |
| | | // color: 'white' |
| | | // }, |
| | | // position: c |
| | | // }); |
| | | gridViews.push(rectangle); |
| | | // that.textView.push(text); |
| | | }); |
| | | map.add(gridViews); |
| | | map.setFitView(gridViews); |
| | | }, |
| | | |
| | | /** |
| | | * 绘制一组多边形 |
| | | * @param {Array} points 网格坐标点数组 |
| | | * @param {Boolean} draw 是否创建完成后同时绘制 |
| | | */ |
| | | drawPolylines({ points, draw, event }) { |
| | | const gridViews = []; |
| | | points.forEach((p) => { |
| | | //创建多边形 Polygon 实例 |
| | | // eslint-disable-next-line no-undef |
| | | var polygon = new AMap.Polygon({ |
| | | path: p.path, //路径 |
| | | fillColor: '#fff', //多边形填充颜色 |
| | | strokeWeight: 1, //线条宽度,默认为 2 |
| | | strokeColor: 'white', //线条颜色 |
| | | fillOpacity: 0, |
| | | extData: p.extData, |
| | | zIndex: 11 |
| | | }); |
| | | |
| | | if (typeof event === 'function') { |
| | | event(polygon); |
| | | } |
| | | gridViews.push(polygon); |
| | | }); |
| | | if (draw) { |
| | | map.add(gridViews); |
| | | map.setFitView(gridViews); |
| | | } |
| | | return gridViews; |
| | | }, |
| | | |
| | | drawGridText({ points, textViews, anchor, type, isCustomColor, useColor }) { |
| | | let colorList = []; |
| | | if (useColor) { |
| | | colorList = calGridColor({ |
| | | factorName: 'PM25', |
| | | data: points.map((p) => p.data), |
| | | isCustomColor: isCustomColor |
| | | }); |
| | | } |
| | | if (textViews) { |
| | | map.remove(textViews); |
| | | } |
| | | const _textViews = []; |
| | | points.forEach((p, i) => { |
| | | const m = textMaker({ |
| | | position: p.lnglat_GD, |
| | | text: p.data, |
| | | anchor, |
| | | type, |
| | | color: useColor ? colorList[i] : 'white' |
| | | }); |
| | | _textViews.push(m); |
| | | }); |
| | | // map.add(_textViews); |
| | | return { textViews: _textViews }; |
| | | }, |
| | | |
| | | drawGridTextLabel(points, textViews, labelsLayer, direction) { |
| | | if (textViews) { |
| | | points.forEach((p, i) => { |
| | | textViews[i].setPosition(p.lnglat_GD); |
| | | textViews[i].setText({ |
| | | content: p.data ? p.data + '' : '' |
| | | }); |
| | | }); |
| | | return { textViews, labelsLayer }; |
| | | } else { |
| | | // 创建一个 LabelsLayer 实例来承载 LabelMarker,[LabelsLayer 文档](https://lbs.amap.com/api/jsapi-v2/documentation#labelslayer) |
| | | // eslint-disable-next-line no-undef |
| | | const labelsLayer = new AMap.LabelsLayer({ |
| | | zooms: [12, 20], |
| | | zIndex: 1000, |
| | | // 开启标注避让,默认为开启,v1.4.15 新增属性 |
| | | collision: false, |
| | | // 开启标注淡入动画,默认为开启,v1.4.15 新增属性 |
| | | animation: false |
| | | }); |
| | | const _textViews = []; |
| | | points.forEach((p) => { |
| | | const m = textLabelMarker(p.lnglat_GD, p.data, direction); |
| | | _textViews.push(m); |
| | | // 将 LabelMarker 实例添加到 LabelsLayer 上 |
| | | labelsLayer.add(m); |
| | | }); |
| | | map.add(labelsLayer); |
| | | // map.on('zoomend', () => { |
| | | // console.log(map.getZoom()); |
| | | // }); |
| | | return { textViews: _textViews, labelsLayer }; |
| | | } |
| | | }, |
| | | |
| | | /** |
| | | * 根据遥测数据,设置对应网格的标准色,返回有数据的网格 |
| | | * @param {Array} gridViews 网格多边形对象数组 |
| | | * @param {Array} gridDataDetail 卫星遥测数据数组 |
| | | * @param {string} factorName 监测因子名称 |
| | | * @param {number} opacity 透明度 |
| | | */ |
| | | drawGridColor(gridViews, gridDataDetail, factorName, style) { |
| | | let { |
| | | strokeWeight = 1, |
| | | strokeColor = 'white', |
| | | opacity = 1, |
| | | zIndex = 11 |
| | | } = style; |
| | | const res = []; |
| | | // 遍历卫星遥测数据数组 |
| | | gridDataDetail.forEach((d, i) => { |
| | | if (d.pm25) { |
| | | const grid = gridViews[i]; |
| | | |
| | | // 根据遥测数据计算网格颜色 |
| | | const data = d.pm25; |
| | | const { color, nextColor, range, nextRange } = |
| | | Legend.getStandardColorAndNext(factorName, data); |
| | | const ratio = (data - range) / (nextRange - range); |
| | | const _color = getColorBetweenTwoColors( |
| | | color.map((v) => v * 255), |
| | | nextColor.map((v) => v * 255), |
| | | ratio |
| | | ); |
| | | |
| | | const _extData = grid.getExtData(); |
| | | grid.setOptions({ |
| | | strokeWeight, |
| | | strokeColor, |
| | | zIndex, |
| | | fillColor: _color, //多边形填充颜色 |
| | | fillOpacity: opacity, |
| | | extData: { |
| | | ..._extData, |
| | | gridData: d |
| | | } |
| | | }); |
| | | if (d.gridStyle && style.isMixGridHighlight) { |
| | | const _strokeWeight = d.gridStyle.strokeWeight; |
| | | const _strokeColor = d.gridStyle.strokeColor; |
| | | grid.setOptions({ |
| | | strokeWeight: _strokeWeight, //线条宽度,默认为 1 |
| | | strokeColor: _strokeColor //线条颜色 |
| | | }); |
| | | } |
| | | |
| | | res.push(grid); |
| | | } |
| | | }); |
| | | |
| | | return res; |
| | | }, |
| | | |
| | | drawGridColorCustom(gridViews, gridDataDetail) { |
| | | |
| | | var max, min; |
| | | gridDataDetail.forEach((t) => { |
| | | if (!t.pm25) return; |
| | | if (!max || t.pm25 > max) { |
| | | max = t.pm25; |
| | | } |
| | | if (!min || t.pm25 < min) { |
| | | min = t.pm25; |
| | | } |
| | | }); |
| | | const res = []; |
| | | // 遍历卫星遥测数据数组 |
| | | gridDataDetail.forEach((d, i) => { |
| | | if (d.pm25) { |
| | | const grid = gridViews[i]; |
| | | |
| | | // 根据遥测数据计算网格颜色 |
| | | const data = d.pm25; |
| | | const { color, nextColor, range, nextRange } = |
| | | Legend.getCustomColorAndNext(data, min, max); |
| | | const ratio = (data - range) / (nextRange - range); |
| | | |
| | | const _color = getColorBetweenTwoColors( |
| | | color.map((v) => v * 255), |
| | | nextColor.map((v) => v * 255), |
| | | ratio |
| | | ); |
| | | grid.setOptions({ |
| | | fillColor: _color, //多边形填充颜色 |
| | | // fillOpacity: style.opacity ? style.opacity : color[3] == 0 ? 0 : 1 |
| | | }); |
| | | |
| | | res.push(grid); |
| | | } |
| | | }); |
| | | |
| | | return res; |
| | | } |
| | | }; |