From 801ad6a268bae66c84bebd221b69e30d7efc5723 Mon Sep 17 00:00:00 2001 From: chenqiang Date: Wed, 27 Dec 2023 17:07:53 +0800 Subject: [PATCH] =?UTF-8?q?fix():=20=E8=A7=A3=E5=86=B3=E5=A4=A7=E5=B1=8F?= =?UTF-8?q?=E9=A5=BC=E5=9B=BE=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MapComponets/MarkCenter/index.jsx | 2 +- .../MapComponets/ParkViewCirMar/index.jsx | 4 +- .../DataAnalysisPrediction/ParkingOverview/Map.jsx | 15 +- .../ParkingOverview/index.scss | 2 +- .../ParkingOverview/loadable.jsx | 572 +++++++++++++++++---- 5 files changed, 488 insertions(+), 107 deletions(-) diff --git a/src/components/MapComponets/MarkCenter/index.jsx b/src/components/MapComponets/MarkCenter/index.jsx index 6fe59dd..ae8e94e 100644 --- a/src/components/MapComponets/MarkCenter/index.jsx +++ b/src/components/MapComponets/MarkCenter/index.jsx @@ -44,7 +44,7 @@ function Markers(props) { let marker = new AMap.Marker({ position: new AMap.LngLat(data.lng, data.lat), content: markerContent, - offset: new AMap.Pixel(-13, -30), + offset: new AMap.Pixel(-8, -23), }); map.add(marker); // .bindTooltip(`${data.name}`, { diff --git a/src/components/MapComponets/ParkViewCirMar/index.jsx b/src/components/MapComponets/ParkViewCirMar/index.jsx index ecff619..d2fdeba 100644 --- a/src/components/MapComponets/ParkViewCirMar/index.jsx +++ b/src/components/MapComponets/ParkViewCirMar/index.jsx @@ -81,8 +81,9 @@ function Markers(props) { content: retext(elem.type), name: elem.text, id: elem.roadId || elem.id, + // title: `${elem.text} (${elem?.userTotal}/${elem?.berthTotal})`, option: elem, - offset: new AMap.Pixel(-15, -15), + offset: new AMap.Pixel(-15, -30), }); mark.on("click", function (e) { clickCb(e.target.w.option); @@ -92,6 +93,7 @@ function Markers(props) { // clearTimeout(timer); Mapmove.setPosition(e.target.getPosition()); Mapmove.setLabel({ + offset: new AMap.Pixel(22, 2), content: `${data.name} (${data?.option?.userTotal}/${data?.option?.berthTotal})`, }); }); diff --git a/src/pages/DataAnalysisPrediction/ParkingOverview/Map.jsx b/src/pages/DataAnalysisPrediction/ParkingOverview/Map.jsx index 8c34a9a..228b296 100644 --- a/src/pages/DataAnalysisPrediction/ParkingOverview/Map.jsx +++ b/src/pages/DataAnalysisPrediction/ParkingOverview/Map.jsx @@ -1,5 +1,6 @@ import React, { useState, useEffect, useRef } from "react"; import { EnvironmentOutlined, SearchOutlined } from "@ant-design/icons"; +import mgreen from "@/assets/images/equip/home/mark_green.png"; function BaseMap(props) { const { id = "map", @@ -10,7 +11,12 @@ function BaseMap(props) { Option = "", setOption = [], } = props; - + const retext = (val) => { + var str = mgreen; + return `
+ +
`; + }; const mapConfig = { center: sysConfig.map.center, zoom: sysConfig.map.zoom, @@ -46,6 +52,13 @@ function BaseMap(props) { if (onClick) { _map.on("click", function (info) { onClick(info); + // console.log(info); + // let mark = new AMap.Marker({ + // position: [info.lnglat.lng, info.lnglat.lat], + // content: retext(), + // offset: new AMap.Pixel(-15, -30), + // }); + // _map.add(mark); }); } mapRef.current = map; diff --git a/src/pages/DataAnalysisPrediction/ParkingOverview/index.scss b/src/pages/DataAnalysisPrediction/ParkingOverview/index.scss index c41819d..d6ac85c 100644 --- a/src/pages/DataAnalysisPrediction/ParkingOverview/index.scss +++ b/src/pages/DataAnalysisPrediction/ParkingOverview/index.scss @@ -451,7 +451,7 @@ $color-primary : var(--color-primary); } .right_home { - z-index: 1000; + z-index: 1001; position: absolute; top: 90px; right: 50px; diff --git a/src/pages/DataAnalysisPrediction/ParkingOverview/loadable.jsx b/src/pages/DataAnalysisPrediction/ParkingOverview/loadable.jsx index e623d2a..8faf02d 100644 --- a/src/pages/DataAnalysisPrediction/ParkingOverview/loadable.jsx +++ b/src/pages/DataAnalysisPrediction/ParkingOverview/loadable.jsx @@ -60,6 +60,8 @@ const ParkingOverview = connect(function mapStateToProps(state) { }; })((props) => { const navigate = useNavigate(); + let selectedIndex = ""; + let hoveredIndex = ""; //地图数据展示is const MapS = [ { @@ -89,7 +91,7 @@ const ParkingOverview = connect(function mapStateToProps(state) { //右侧时间选择 const Dayfour = [ { - text: "昨日", + text: "当日", value: "1", }, @@ -98,11 +100,11 @@ const ParkingOverview = connect(function mapStateToProps(state) { value: "2", }, { - text: "近7日", + text: "近7天", value: "3", }, { - text: "近30日", + text: "近30天", value: "4", }, ]; @@ -616,7 +618,333 @@ const ParkingOverview = connect(function mapStateToProps(state) { return 0; } } + const getPie3D = (pieData, internalDiameterRatio) => { + //internalDiameterRatio:透明的空心占比 + let series = []; + let sumValue = 0; + let startValue = 0; + let endValue = 0; + let k = 1; + let legendData = []; + pieData.sort((a, b) => { + return b.value - a.value; + }); + // 为每一个饼图数据,生成一个 series-surface 配置 + for (let i = 0; i < pieData.length; i++) { + sumValue += pieData[i].value; + let seriesItem = { + name: + typeof pieData[i].name === "undefined" + ? `series${i}` + : pieData[i].name, + type: "surface", + parametric: true, + wireframe: { + show: false, + }, + pieData: pieData[i], + pieStatus: { + selected: false, + hovered: false, + k: k, + }, + radius: "50%", + center: ["10%", "10%"], + }; + + if (typeof pieData[i].itemStyle != "undefined") { + let itemStyle = {}; + typeof pieData[i].itemStyle.color != "undefined" + ? (itemStyle.color = pieData[i].itemStyle.color) + : null; + typeof pieData[i].itemStyle.opacity != "undefined" + ? (itemStyle.opacity = pieData[i].itemStyle.opacity) + : null; + seriesItem.itemStyle = itemStyle; + } + series.push(seriesItem); + } + + // 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数, + // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。 + + // for (let i = 0; i < series.length; i++) { + // endValue = startValue + series[i].pieData.value; + // series[i].pieData.startRatio = startValue / sumValue; + // series[i].pieData.endRatio = endValue / sumValue; + // series[i].parametricEquation = getParametricEquation( + // series[i].pieData.startRatio, + // series[i].pieData.endRatio, + // false, + // false, + // k, + // series[i].pieData.value + // ); + // startValue = endValue; + // } + for (let i = 0; i < series.length; i++) { + endValue = startValue + series[i].pieData.value; + + series[i].pieData.startRatio = startValue / sumValue; + series[i].pieData.endRatio = endValue / sumValue; + series[i].parametricEquation = getParametricEquation( + series[i].pieData.startRatio, + series[i].pieData.endRatio, + false, + false, + k, + series[i].pieData.value + ); + + startValue = endValue; + + legendData.push(series[i].name); + } + + let boxHeight = getHeight3D(series, 25); //通过传参设定3d饼/环的高度,26代表26px + // 准备待返回的配置项,把准备好的 legendData、series 传入。 + let option = { + // backgroundColor: "#203598", + // labelLine: { + // show: true, + // lineStyle: { + // color: "#fff", + // }, + // }, + legend: { + selectedMode: false, + data: legendData, + // formatter: function (name) { + // return `${name}:\n{|1000}}`; + // }, + textStyle: { + color: "#fff", + }, + }, + label: { + show: true, + position: "outside", + formatter: "{b|{b}}\n{c|{c}%}", + rich: { + b: { + fontSize: 16, + lineHeight: 16, + // fontWeight: "bold", + color: "#fff", + }, + c: { + fontSize: 12, + color: "#fff", + }, + }, + }, + tooltip: { + backgroundColor: "#fff", + formatter: (params) => { + if ( + params.seriesName !== "mouseoutSeries" && + params.seriesName !== "pie2d" + ) { + let bfb = ( + (option.series[params.seriesIndex].pieData.endRatio - + option.series[params.seriesIndex].pieData.startRatio) * + 100 + ).toFixed(2); + return ( + `${params.seriesName}
` + + `` + + `${bfb}%` + ); + } + }, + }, + xAxis3D: { + min: -1, + max: 1, + }, + yAxis3D: { + min: -1, + max: 1, + }, + zAxis3D: { + min: -1, + max: 1, + }, + grid3D: { + show: false, + boxHeight: boxHeight, //圆环的高度 + left: 0, + top: 0, //3d饼图的位置 + viewControl: { + //3d效果可以放大、旋转等,请自己去查看官方配置 + alpha: 30, //角度 + distance: 250, //调整视角到主体的距离,类似调整zoom + rotateSensitivity: 0, //设置为0无法旋转 + zoomSensitivity: 0, //设置为0无法缩放 + panSensitivity: 0, //设置为0无法平移 + autoRotate: false, //自动旋转 + }, + }, + series: series, + }; + return option; + }; + + //获取3d丙图的最高扇区的高度 + const getHeight3D = (series, height) => { + series.sort((a, b) => { + return b.pieData.value - a.pieData.value; + }); + return (height * 25) / series[0].pieData.value; + }; + // 生成扇形的曲面参数方程,用于 series-surface.parametricEquation + const getParametricEquation = ( + startRatio, + endRatio, + isSelected, + isHovered, + k, + h + ) => { + // 计算 + let midRatio = (startRatio + endRatio) / 2; + let startRadian = startRatio * Math.PI * 2; + let endRadian = endRatio * Math.PI * 2; + let midRadian = midRatio * Math.PI * 2; + // 如果只有一个扇形,则不实现选中效果。 + if (startRatio === 0 && endRatio === 1) { + isSelected = true; + } + // 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3) + k = typeof k !== "undefined" ? k : 1 / 3; + // 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0) + let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0; + let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0; + // 计算高亮效果的放大比例(未高亮,则比例为 1) + let hoverRate = isHovered ? 1.05 : 1; + // 返回曲面参数方程 + return { + u: { + min: -Math.PI, + max: Math.PI * 3, + step: Math.PI / 32, + }, + v: { + min: 0, + max: Math.PI * 2, + step: Math.PI / 20, + }, + x: function (u, v) { + if (u < startRadian) { + return ( + offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate + ); + } + if (u > endRadian) { + return ( + offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate + ); + } + return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate; + }, + y: function (u, v) { + if (u < startRadian) { + return ( + offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate + ); + } + if (u > endRadian) { + return ( + offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate + ); + } + return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate; + }, + z: function (u, v) { + if (u < -Math.PI * 0.5) { + return Math.sin(u); + } + if (u > Math.PI * 2.5) { + return Math.sin(u) * h * 0.1; + } + return Math.sin(v) > 0 ? 1 * h * 0.1 : -1; + }, + }; + }; + const onEvents = { + mouseover: (params) => { + // 从 option.series 中读取重新渲染扇形所需的参数,将是否选中取反。 + // 准备重新渲染扇形所需的参数 + let option = RightTwo; + let isSelected; + let isHovered; + let startRatio; + let endRatio; + let k; + + // 如果触发 mouseover 的扇形当前已高亮,则不做操作 + if (hoveredIndex === params.seriesIndex) { + return; + + // 否则进行高亮及必要的取消高亮操作 + } else { + // 如果当前有高亮的扇形,取消其高亮状态(对 option 更新) + if (hoveredIndex !== "") { + // 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 false。 + isSelected = option.series[hoveredIndex].pieStatus.selected; + isHovered = false; + startRatio = option.series[hoveredIndex].pieData.startRatio; + endRatio = option.series[hoveredIndex].pieData.endRatio; + k = option.series[hoveredIndex].pieStatus.k; + + // 对当前点击的扇形,执行取消高亮操作(对 option 更新) + option.series[hoveredIndex].parametricEquation = + getParametricEquation( + startRatio, + endRatio, + isSelected, + isHovered, + k, + option.series[hoveredIndex].pieData.value + ); + option.series[hoveredIndex].pieStatus.hovered = isHovered; + + // 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空 + hoveredIndex = ""; + } + + // 如果触发 mouseover 的扇形不是透明圆环,将其高亮(对 option 更新) + if (params.seriesName !== "mouseoutSeries") { + // 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 true。 + isSelected = option.series[params.seriesIndex].pieStatus.selected; + isHovered = true; + startRatio = option.series[params.seriesIndex].pieData.startRatio; + endRatio = option.series[params.seriesIndex].pieData.endRatio; + k = option.series[params.seriesIndex].pieStatus.k; + + // 对当前点击的扇形,执行高亮操作(对 option 更新) + option.series[params.seriesIndex].parametricEquation = + getParametricEquation( + startRatio, + endRatio, + isSelected, + isHovered, + k, + option.series[params.seriesIndex].pieData.value + 5 + ); + option.series[params.seriesIndex].pieStatus.hovered = isHovered; + + // 记录上次高亮的扇形对应的系列号 seriesIndex + hoveredIndex = params.seriesIndex; + } + + // 使用更新后的 option,渲染图表 + setRightTwo(option); + } + }, + // 其他事件处理程序也可以在这里添加 + }; const getRingOption = ( datas = [ { @@ -626,92 +954,65 @@ const ParkingOverview = connect(function mapStateToProps(state) { ] ) => { // 获取所有地区名称 - - const arrRight = + const data = datas.map((ele) => { return { name: ele.key, value: ele.value, + startRatio: 0.7, + endRatio: 1, }; }) || []; - setRightTwo({ - title: { - text: "{a|" + sum(datas.map((ele) => ele.value)).toFixed(2) + "}", - x: "center", - y: "center", - subtext: "营业收入", - subtextStyle: { - color: "#fff", - fontSize: 14, - }, - textStyle: { - rich: { - a: { - fontSize: 30, - color: "#4DC3FF", - }, - c: { - fontSize: 14, - color: "#4DC3FF", - // padding: [5,0] - }, - }, - }, + let option = getPie3D(data, 0.8); + // 是否需要label指引线,如果要就添加一个透明的2d饼状图并调整角度使得labelLine和3d的饼状图对齐,并再次setOption + option.series.push({ + // name: "pie2d", + // type: "pie", + // labelLine: { + // length: 10, + // length2: 10, + // }, + // startAngle: -25, //起始角度,支持范围[0, 360]。 + // clockwise: false, //饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式 + // radius: ["65%", "65%"], + // center: ["55%", "48%"], //指示线的位置 + // data: data, + // itemStyle: { + // opacity: 0, + // }, + name: "mouseoutSeries", + type: "surface", + parametric: true, + wireframe: { + show: false, }, - tooltip: { - trigger: "item", - formatter: (params) => { - return `
${params.marker} ${params.name} ${params.value} ${params.percent}%
`; - }, + itemStyle: { + opacity: 0, }, - legend: { - type: "scroll", - //right: "5%", - top: "bottom", - bottom: "center", - //data: areaNames, - data: datas.map((ele) => ele.key), - itemWidth: 18, - itemHeight: 12, - textStyle: { - fontSize: 14, - color: "white", + parametricEquation: { + u: { + min: 0, + max: Math.PI * 2, + step: Math.PI / 20, }, - }, - - // color: ["#34F3B6", "#4DC3FF"], - //series: seriesData, - series: [ - { - // name: 'Access From', - type: "pie", - radius: ["58%", "70%"], - avoidLabelOverlap: false, - label: { - show: false, - position: "center", - }, - // emphasis: { - // label: { - // show: true, - // fontSize: 40, - // fontWeight: "bold", - // }, - // }, - labelLine: { - show: false, - }, - data: arrRight, + v: { + min: 0, + max: Math.PI, + step: Math.PI / 20, + }, + x: function (u, v) { + return Math.sin(v) * Math.sin(u) + Math.sin(u); + }, + y: function (u, v) { + return Math.sin(v) * Math.cos(u) + Math.cos(u); + }, + z: function (u, v) { + return Math.cos(v) > 0 ? 0.1 : -0.1; }, - ], - grid: { - x: 20, - y: 25, - x2: 20, - y2: 50, }, }); + setRightTwo(option); }; //右下 const getRevenueOption = ( @@ -735,8 +1036,9 @@ const ParkingOverview = connect(function mapStateToProps(state) { trigger: "axis", formatter: (params) => { return `
- ${params[0].axisValue} ${params[0].seriesName} ${params[0].value} -
`; +
${params[0].marker}${params[0].axisValue} ${params[0].seriesName} ${params[0].value}
+
${params[1].marker}${params[1].axisValue} ${params[1].seriesName} ${params[1].value}
+ `; }, }, legend: { @@ -767,6 +1069,37 @@ const ParkingOverview = connect(function mapStateToProps(state) { }, }, }, + dataZoom: [ + { + type: "slider", + height: 10, + textStyle: { + color: "B5BAC2", + }, + handleIcon: + "path://M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z", + dataBackground: { + areaStyle: { + color: "#72afff", + }, + lineStyle: { + opacity: 0.8, + color: "#72afff", + }, + // brushSelect: false, + }, + borderColor: "#3974D6", + start: 46, + end: 100, + // minSpan: flowMountType == "year" ? 0 : 46, + bottom: 20, + }, + { + type: "inside", + // moveOnMousewheel: true, // + // moveonMouseMove: true, //鼠标 + }, + ], yAxis: { type: "value", name: "金额(元)", @@ -797,21 +1130,45 @@ const ParkingOverview = connect(function mapStateToProps(state) { //series: seriesData, series: [ { - name: "停车收入", + name: "应收", type: "line", areaStyle: { //color: '#94C9EC' color: "rgba(13,225,250, .31)", }, + showSymbol: false, + lineStyle: { + color: "rgba(13,225,250, 1)", + }, + itemStyle: { + color: "rgba(13,225,250, 1)", // 设置曲线上的点的颜色为蓝色 + }, data: data.map((ele) => ele.value), }, + { + name: "实收", + type: "line", + areaStyle: { + //color: 'red' + + color: "rgba(235, 39, 39,.31)", + }, + showSymbol: false, + lineStyle: { + color: "rgba(235, 39, 39,1)", + }, + itemStyle: { + color: "rgba(235, 39, 39,1)", // 设置曲线上的点的颜色为蓝色 + }, + data: data.map((ele) => ele.value + 100), + }, ], grid: { x: 50, y: 35, x2: 30, - y2: 30, + y2: 50, }, }); }; @@ -1618,50 +1975,59 @@ const ParkingOverview = connect(function mapStateToProps(state) {
{CarRoad[CarShow]?.type == 2 ? "实时收入占比" : "路段收费率排行榜"}
-
- {CarRoad[CarShow]?.type != 2 - ? Dayfour.map((ele) => { - return ( - SelectDay(2, ele.value)} - > - {ele.text} - - ); - }) - : ""} -
+ + {CarRoad[CarShow]?.type != 2 ? ( +
+ {Dayfour.map((ele) => { + return ( + SelectDay(2, ele.value)} + > + {ele.text} + + ); + })} +
+ ) : ( + "" + )} + {CarRoad[CarShow]?.type == 1 ? (
{/* */} TOP2 -

周转率{Cartop[1]?.rate || 0}

+

+ {Cartop[1]?.rate || 0}/{Cartop[1]?.rate || 0} +

{Cartop[1]?.name || ""}
{/* */} TOP1 -

周转率{Cartop[0]?.rate || 0}

+

+ {Cartop[0]?.rate || 0}/{Cartop[0]?.rate || 0} +

{Cartop[0]?.name || ""}
{/* */} TOP3 -

周转率{Cartop[2]?.rate || 0}

+

+ {Cartop[2]?.rate || 0}/{Cartop[2]?.rate || 0} +

{Cartop[2]?.name || ""}
) : ( )}