feat: 优化上海街道地图展示并添加3D效果
- 将2D地图升级为3D地图展示,增强视觉效果 - 添加渐变炫彩边框样式提升UI美观度 - 修复类型检查错误并优化代码结构 - 更新vite配置允许特定主机访问 - 移除无用导入和注释代码
This commit is contained in:
parent
1241191f38
commit
be85d94ad7
4
.env
4
.env
@ -1,5 +1,5 @@
|
|||||||
# VITE_MAINURL=http://127.0.0.1:8081/
|
VITE_MAINURL=http://127.0.0.1:8081/
|
||||||
VITE_MAINURL=http://localhost:8081/
|
# VITE_MAINURL=https://6k4n616846.goho.co/
|
||||||
# VITE_MAINURL=http://192.168.1.12:8081/
|
# VITE_MAINURL=http://192.168.1.12:8081/
|
||||||
# VITE_MAINURL=http://6adad28a.r36.cpolar.top
|
# VITE_MAINURL=http://6adad28a.r36.cpolar.top
|
||||||
# VITE_MAINURL=https://10.86.138.22/shp/
|
# VITE_MAINURL=https://10.86.138.22/shp/
|
BIN
public/image/bg10.png
Normal file
BIN
public/image/bg10.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 503 KiB |
@ -1,4 +1,3 @@
|
|||||||
import { component } from '@nutui/nutui/dist/types/__VUE/grid/common'
|
|
||||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
|
@ -2763,8 +2763,8 @@ const initStreetChart = () => {
|
|||||||
map: "JiedaoMap", // 使用注册的地图名称
|
map: "JiedaoMap", // 使用注册的地图名称
|
||||||
geoIndex: 10, // 地理坐标系组件的索引
|
geoIndex: 10, // 地理坐标系组件的索引
|
||||||
zoom: 0.87, // 地图缩放等级
|
zoom: 0.87, // 地图缩放等级
|
||||||
left: streetLeft[districtValue.value], // 距离左侧10%
|
left: (streetLeft as any)[districtValue.value], // 距离左侧10%
|
||||||
top: streetTop[districtValue.value], //
|
top: (streetTop as any)[districtValue.value], //
|
||||||
// center: ["50%", "50%"], // 地图中心点坐标
|
// center: ["50%", "50%"], // 地图中心点坐标
|
||||||
showLegendSymbol: false, // 不显示图例标记
|
showLegendSymbol: false, // 不显示图例标记
|
||||||
label: {
|
label: {
|
||||||
|
@ -318,6 +318,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
// @ts-nocheck
|
||||||
import VueDraggableResizable from "vue-draggable-resizable/src/components/vue-draggable-resizable.vue";
|
import VueDraggableResizable from "vue-draggable-resizable/src/components/vue-draggable-resizable.vue";
|
||||||
import "vue-draggable-resizable/dist/VueDraggableResizable.css";
|
import "vue-draggable-resizable/dist/VueDraggableResizable.css";
|
||||||
import { onMounted, reactive, ref, watch, onBeforeUnmount } from "vue";
|
import { onMounted, reactive, ref, watch, onBeforeUnmount } from "vue";
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
|
|
||||||
<!-- <div class="w-full h-screen bg-gradient-to-tr from-green-300 via-cyan-500 to-blue-400"
|
<!-- <div class="w-full h-screen bg-gradient-to-tr from-green-300 via-cyan-500 to-blue-400"
|
||||||
:style="{ backgroundColor: basicOptions.backgroundColor }" id="mainContainer"> -->
|
:style="{ backgroundColor: basicOptions.backgroundColor }" id="mainContainer"> -->
|
||||||
<div class="w-full h-screen bg-gradient-to-b from-blue-800 to-gray-800 relative overflow-hidden" id="mainContainer">
|
<div class="w-full h-screen relative overflow-hidden bg-[url(/image/bg10.png)] m-0 bg-cover bg-no-repeat bg-center"
|
||||||
|
id="mainContainer">
|
||||||
<!-- 科技感背景元素 -->
|
<!-- 科技感背景元素 -->
|
||||||
<div class="absolute inset-0 w-full h-full overflow-hidden">
|
<div class="absolute inset-0 w-full h-full overflow-hidden">
|
||||||
<div
|
<div
|
||||||
@ -25,9 +26,9 @@
|
|||||||
class="absolute top-0 right-0 h-full w-[2px] bg-gradient-to-b from-transparent via-cyan-500 to-transparent opacity-70">
|
class="absolute top-0 right-0 h-full w-[2px] bg-gradient-to-b from-transparent via-cyan-500 to-transparent opacity-70">
|
||||||
</div>
|
</div>
|
||||||
<!-- 科技感图案 -->
|
<!-- 科技感图案 -->
|
||||||
<div class="absolute top-10 left-10 w-[200px] h-[200px] border-l-2 border-t-2 border-cyan-500 opacity-20"></div>
|
<!-- <div class="absolute top-10 left-10 w-[200px] h-[200px] border-l-2 border-t-2 border-cyan-500 opacity-20"></div> -->
|
||||||
<div class="absolute bottom-10 right-10 w-[200px] h-[200px] border-r-2 border-b-2 border-cyan-500 opacity-20">
|
<!-- <div class="absolute bottom-10 right-10 w-[200px] h-[200px] border-r-2 border-b-2 border-cyan-500 opacity-20">
|
||||||
</div>
|
</div> -->
|
||||||
<div
|
<div
|
||||||
class="absolute top-0 left-0 w-full h-full bg-[url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMCAwIDQwIDQwIj48ZyBmaWxsPSJub25lIiBzdHJva2U9IiMwYmI3ZmYiIHN0cm9rZS13aWR0aD0iMC4yIiBvcGFjaXR5PSIwLjIiPjxwYXRoIGQ9Ik0yMCAyMCBMMCAyMCBMMCA0MCIvPjxwYXRoIGQ9Ik0yMCAyMCBMNDAgMjAgTDQwIDQwIi8+PHBhdGggZD0iTTIwIDIwIEwwIDIwIEwwIDAiLz48cGF0aCBkPSJNMjAgMjAgTDQwIDIwIEw0MCAwIi8+PC9nPjwvc3ZnPg==')] bg-repeat opacity-5">
|
class="absolute top-0 left-0 w-full h-full bg-[url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMCAwIDQwIDQwIj48ZyBmaWxsPSJub25lIiBzdHJva2U9IiMwYmI3ZmYiIHN0cm9rZS13aWR0aD0iMC4yIiBvcGFjaXR5PSIwLjIiPjxwYXRoIGQ9Ik0yMCAyMCBMMCAyMCBMMCA0MCIvPjxwYXRoIGQ9Ik0yMCAyMCBMNDAgMjAgTDQwIDQwIi8+PHBhdGggZD0iTTIwIDIwIEwwIDIwIEwwIDAiLz48cGF0aCBkPSJNMjAgMjAgTDQwIDIwIEw0MCAwIi8+PC9nPjwvc3ZnPg==')] bg-repeat opacity-5">
|
||||||
</div>
|
</div>
|
||||||
@ -87,26 +88,30 @@
|
|||||||
<!-- 左1 -->
|
<!-- 左1 -->
|
||||||
<vue-draggable-resizable ref="refWoTe1" style="border: none; z-index: 999" :draggable="draggableBoolean"
|
<vue-draggable-resizable ref="refWoTe1" style="border: none; z-index: 999" :draggable="draggableBoolean"
|
||||||
:resizable="resizableBoolean">
|
:resizable="resizableBoolean">
|
||||||
<div class="flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
<div
|
||||||
|
class="fancy-border flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
||||||
ref="main1"></div>
|
ref="main1"></div>
|
||||||
</vue-draggable-resizable>
|
</vue-draggable-resizable>
|
||||||
<!-- 左2 -->
|
<!-- 左2 -->
|
||||||
<vue-draggable-resizable ref="refWoTe2" style="border: none; z-index: 999" :draggable="draggableBoolean"
|
<vue-draggable-resizable ref="refWoTe2" style="border: none; z-index: 999" :draggable="draggableBoolean"
|
||||||
:resizable="resizableBoolean">
|
:resizable="resizableBoolean">
|
||||||
<div class="flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
<div
|
||||||
|
class="fancy-border flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
||||||
ref="main2"></div>
|
ref="main2"></div>
|
||||||
</vue-draggable-resizable>
|
</vue-draggable-resizable>
|
||||||
<!-- 左3 -->
|
<!-- 左3 -->
|
||||||
<vue-draggable-resizable ref="refWoTe3" style="border: none; z-index: 999" :draggable="draggableBoolean"
|
<vue-draggable-resizable ref="refWoTe3" style="border: none; z-index: 999" :draggable="draggableBoolean"
|
||||||
:resizable="resizableBoolean">
|
:resizable="resizableBoolean">
|
||||||
<div class="flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
<div
|
||||||
|
class="fancy-border flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
||||||
ref="main3"></div>
|
ref="main3"></div>
|
||||||
</vue-draggable-resizable>
|
</vue-draggable-resizable>
|
||||||
|
|
||||||
<!-- 右1 -->
|
<!-- 右1 -->
|
||||||
<vue-draggable-resizable ref="refWoTe4" style="border: none; z-index: 999" :draggable="draggableBoolean"
|
<vue-draggable-resizable ref="refWoTe4" style="border: none; z-index: 999" :draggable="draggableBoolean"
|
||||||
:resizable="resizableBoolean">
|
:resizable="resizableBoolean">
|
||||||
<div class="flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
<div
|
||||||
|
class="fancy-border flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
||||||
ref="main4">
|
ref="main4">
|
||||||
<div class="flex justify-around text-white">
|
<div class="flex justify-around text-white">
|
||||||
<div class="p-2 flex flex-col font-semibold items-center">
|
<div class="p-2 flex flex-col font-semibold items-center">
|
||||||
@ -142,7 +147,8 @@
|
|||||||
<!-- 右2 -->
|
<!-- 右2 -->
|
||||||
<vue-draggable-resizable ref="refWoTe5" style="border: none; z-index: 999;" :draggable="draggableBoolean"
|
<vue-draggable-resizable ref="refWoTe5" style="border: none; z-index: 999;" :draggable="draggableBoolean"
|
||||||
:resizable="resizableBoolean">
|
:resizable="resizableBoolean">
|
||||||
<div class="flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
<div
|
||||||
|
class="fancy-border flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
||||||
ref="main5">
|
ref="main5">
|
||||||
<div class="scroll-wrapper" v-if="defaultShow">
|
<div class="scroll-wrapper" v-if="defaultShow">
|
||||||
<div class="scroll-header">
|
<div class="scroll-header">
|
||||||
@ -325,20 +331,20 @@
|
|||||||
<vue-draggable-resizable ref="refWoTe6" style="border: none; z-index: 999" :draggable="draggableBoolean"
|
<vue-draggable-resizable ref="refWoTe6" style="border: none; z-index: 999" :draggable="draggableBoolean"
|
||||||
:resizable="resizableBoolean" v-show="!relationShow && !isAnimating">
|
:resizable="resizableBoolean" v-show="!relationShow && !isAnimating">
|
||||||
<div
|
<div
|
||||||
class="flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500 overflow-hidden"
|
class="fancy-border flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
||||||
ref="main6">
|
ref="main6">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</vue-draggable-resizable>
|
</vue-draggable-resizable>
|
||||||
<!-- 右下角按钮 -->
|
<!-- 右下角按钮 -->
|
||||||
<div ref="fancyBtn"
|
<div ref="fancyBtn"
|
||||||
class=" fixed z-[9999] bottom-10 right-7 px-3 py-1 rounded-full bg-gradient-to-r from-blue-500 via-cyan-400 to-purple-500 shadow-lg text-white font-bold text-lg cursor-pointer transition-all duration-300 ease-in-out hover:scale-110 hover:shadow-2xl active:scale-95 active:brightness-90 ring-2 ring-white/30 ring-offset-2 ring-offset-black backdrop-blur-md overflow-hidden"
|
class=" fixed z-[9999] bottom-20 right-7 px-3 py-1 rounded-full bg-gradient-to-r from-blue-500 via-cyan-400 to-purple-500 shadow-lg text-white font-bold text-lg cursor-pointer transition-all duration-300 ease-in-out hover:scale-110 hover:shadow-2xl active:scale-95 active:brightness-90 ring-2 ring-white/30 ring-offset-2 ring-offset-black backdrop-blur-md overflow-hidden"
|
||||||
@click="handleFancyClick" style="user-select: none;">
|
@click="handleFancyClick" style="user-select: none;">
|
||||||
关联关系图
|
关联关系图
|
||||||
<span ref="ripple" class="ripple"></span>
|
<span ref="ripple" class="ripple"></span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500 overflow-hidden z-[999] fixed bottom-10 right-7"
|
class="fancy-border flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500 z-[999]"
|
||||||
ref="main9" :class="{
|
ref="main9" :class="{
|
||||||
'animate-popup': isAnimating && relationShow,
|
'animate-popup': isAnimating && relationShow,
|
||||||
'animate-shrink': isAnimating && !relationShow,
|
'animate-shrink': isAnimating && !relationShow,
|
||||||
@ -408,6 +414,7 @@ import { router } from "../router";
|
|||||||
import headMenu from "../components/headMenu.vue";
|
import headMenu from "../components/headMenu.vue";
|
||||||
import * as echarts from "echarts";
|
import * as echarts from "echarts";
|
||||||
import "echarts-wordcloud";
|
import "echarts-wordcloud";
|
||||||
|
import "echarts-gl";
|
||||||
import * as d3 from "d3";
|
import * as d3 from "d3";
|
||||||
|
|
||||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||||
@ -1859,7 +1866,7 @@ const echarts3 = () => {
|
|||||||
const echarts6_old = async () => {
|
const echarts6_old = async () => {
|
||||||
var myChart = echarts.init(main6.value);
|
var myChart = echarts.init(main6.value);
|
||||||
var option: EChartsOption;
|
var option: EChartsOption;
|
||||||
const timeValueMap = {
|
const timeValueMap: Record<string, number> = {
|
||||||
上三个月: -3,
|
上三个月: -3,
|
||||||
上二个月: -2,
|
上二个月: -2,
|
||||||
上一个月: -1,
|
上一个月: -1,
|
||||||
@ -2306,7 +2313,10 @@ const echarts6_old = async () => {
|
|||||||
// console.log('littlemonth.value', littlemonth.value);
|
// console.log('littlemonth.value', littlemonth.value);
|
||||||
// console.log('mockDataSou11', mockDataSou,"222",mockDataSource);
|
// console.log('mockDataSou11', mockDataSou,"222",mockDataSource);
|
||||||
console.log("mockDataSou", mockDataSou);
|
console.log("mockDataSou", mockDataSou);
|
||||||
const mockData = mockDataSou.timeScores.map((item) => item.scores);
|
if (!mockDataSou) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const mockData = mockDataSou.timeScores.map((item: any) => item.scores);
|
||||||
console.log("mockData", mockData);
|
console.log("mockData", mockData);
|
||||||
option = {
|
option = {
|
||||||
baseOption: {
|
baseOption: {
|
||||||
@ -2324,7 +2334,7 @@ const echarts6_old = async () => {
|
|||||||
"下三个月",
|
"下三个月",
|
||||||
],
|
],
|
||||||
currentIndex: 3,
|
currentIndex: 3,
|
||||||
label: { formatter: (s: string) => s },
|
label: { formatter: (value: string | number, index: number) => String(value) },
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: "axis",
|
trigger: "axis",
|
||||||
@ -2405,9 +2415,10 @@ const echarts6_old = async () => {
|
|||||||
myChart.setOption(option);
|
myChart.setOption(option);
|
||||||
|
|
||||||
// 保留时间轴变化监听
|
// 保留时间轴变化监听
|
||||||
myChart.on("timelinechanged", (params) => {
|
myChart.on("timelinechanged", (params: any) => {
|
||||||
const currentName = option.baseOption.timeline.data[params.currentIndex];
|
const dataArr = ((option as any).baseOption.timeline.data as string[]);
|
||||||
const clickValue = timeValueMap[currentName];
|
const currentName = dataArr[params.currentIndex] as string;
|
||||||
|
const clickValue = timeValueMap[currentName] ?? 0;
|
||||||
littlemonth.value = clickValue;
|
littlemonth.value = clickValue;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -2741,7 +2752,7 @@ const echartsYibiao = () => {
|
|||||||
const initTimelineChart = () => {
|
const initTimelineChart = () => {
|
||||||
var myChart = echarts.init(timeline.value);
|
var myChart = echarts.init(timeline.value);
|
||||||
var option: EChartsOption;
|
var option: EChartsOption;
|
||||||
const timeValueMap = {
|
const timeValueMap: Record<string, number> = {
|
||||||
上三个月: -3,
|
上三个月: -3,
|
||||||
上二个月: -2,
|
上二个月: -2,
|
||||||
上一个月: -1,
|
上一个月: -1,
|
||||||
@ -2768,8 +2779,8 @@ const initTimelineChart = () => {
|
|||||||
],
|
],
|
||||||
currentIndex: 3, // 默认选中第四个时间点
|
currentIndex: 3, // 默认选中第四个时间点
|
||||||
label: {
|
label: {
|
||||||
formatter: function (s) {
|
formatter: function (value: string | number, index: number) {
|
||||||
return s;
|
return String(value);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -2789,8 +2800,8 @@ const initTimelineChart = () => {
|
|||||||
type: "shadow",
|
type: "shadow",
|
||||||
label: {
|
label: {
|
||||||
show: true,
|
show: true,
|
||||||
formatter: function (params) {
|
formatter: function (params: any) {
|
||||||
return params.value.replace("\n", "");
|
return String(params.value).replace("\n", "");
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -2807,9 +2818,10 @@ const initTimelineChart = () => {
|
|||||||
myChart.setOption(option);
|
myChart.setOption(option);
|
||||||
|
|
||||||
// 监听时间轴的时间点变化事件
|
// 监听时间轴的时间点变化事件
|
||||||
myChart.on("timelinechanged", (params) => {
|
myChart.on("timelinechanged", (params: any) => {
|
||||||
const currentName = option.baseOption.timeline.data[params.currentIndex];
|
const dataArr = ((option as any).baseOption.timeline.data as string[]);
|
||||||
const clickValue = timeValueMap[currentName];
|
const currentName = dataArr[params.currentIndex] as string;
|
||||||
|
const clickValue = timeValueMap[currentName] ?? 0;
|
||||||
littlemonth.value = clickValue;
|
littlemonth.value = clickValue;
|
||||||
SelectBlur();
|
SelectBlur();
|
||||||
});
|
});
|
||||||
@ -3466,137 +3478,95 @@ const initStreetChart = () => {
|
|||||||
|
|
||||||
console.log("streetScore", streetScore);
|
console.log("streetScore", streetScore);
|
||||||
|
|
||||||
const streetOption = {
|
const streetOption3D: any = {
|
||||||
//网格布局
|
|
||||||
grid: {
|
|
||||||
right: "100%",
|
|
||||||
top: "10%",
|
|
||||||
// bottom: "10%",
|
|
||||||
width: "20%",
|
|
||||||
left: "12%", // 调整此属性以向右移动柱状图
|
|
||||||
},
|
|
||||||
//区间分数
|
|
||||||
visualMap: {
|
visualMap: {
|
||||||
pieces: scoreIntervals.map((interval) => ({
|
pieces: scoreIntervals.map((interval) => ({
|
||||||
gte: parseFloat(interval.min.toFixed(1)),
|
gte: parseFloat(interval.min.toFixed(1)),
|
||||||
lte: parseFloat(interval.max.toFixed(1)),
|
lte: parseFloat(interval.max.toFixed(1)),
|
||||||
color: interval.color,
|
color: interval.color,
|
||||||
})),
|
})),
|
||||||
show: true, // 视觉映射控件
|
show: true,
|
||||||
//定位区间
|
left: "83%",
|
||||||
left: "83%", // 距离容器左侧 10%
|
top: "5%",
|
||||||
top: "5%", // 垂直居中
|
orient: "vertical",
|
||||||
orient: "vertical", // 垂直方向
|
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: "#dbeafe",
|
color: "#dbeafe",
|
||||||
fontSize: 12, // 设置字体大小
|
fontSize: 12,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
type: "map", // 图表类型为地图
|
type: "map3D", // 图表类型为三维地图
|
||||||
map: "JiedaoMap", // 使用注册的地图名称
|
map: "JiedaoMap", // 使用注册的地图名称
|
||||||
geoIndex: 10, // 地理坐标系组件的索引
|
data: streetScore, // 地图数据,包含各街道的分数
|
||||||
zoom: districtValue.value === "上海市" ? 1.2 : 0.9, // 地图缩放等级
|
shading: "lambert", // 着色方式,lambert为漫反射
|
||||||
// left: '18%', // 距离左侧10%
|
|
||||||
// top: '15%', //
|
|
||||||
left: "center",
|
left: "center",
|
||||||
top: districtValue.value === "上海市" ? "12%" : "15%",
|
top: districtValue.value === "上海市" ? "-20%" : "0%",
|
||||||
right: "auto",
|
height: 'auto',
|
||||||
bottom: "auto",
|
|
||||||
// center: [121.52, 30.94],
|
|
||||||
showLegendSymbol: false, // 不显示图例标记
|
|
||||||
label: {
|
label: {
|
||||||
normal: {
|
show: true, // 是否显示标签
|
||||||
show: true, // 正常状态下显示标签
|
// formatter: (p: any) => `${p.name}\n${p?.data?.value ?? ""}`, // 标签内容格式化,显示街道名和分数
|
||||||
formatter: function (params: { name: any; data: { value: any } }) {
|
formatter: (p: any) => {
|
||||||
const name = params.name;
|
switch (p.name) {
|
||||||
const value = params.data ? params.data.value : "";
|
case '普陀区':
|
||||||
return `${name}\n${value}`;
|
return `普陀\n${p?.data?.value ?? ""}`
|
||||||
|
break;
|
||||||
|
case '静安区':
|
||||||
|
return `静安\n${p?.data?.value ?? ""}`
|
||||||
|
break;
|
||||||
|
case '虹口区':
|
||||||
|
return `虹口\n${p?.data?.value ?? ""}`
|
||||||
|
break;
|
||||||
|
case '杨浦区':
|
||||||
|
return `杨浦\n${p?.data?.value ?? ""}`
|
||||||
|
break;
|
||||||
|
case '长宁区':
|
||||||
|
return `长宁\n${p?.data?.value ?? ""}`
|
||||||
|
break;
|
||||||
|
case '黄浦区':
|
||||||
|
return `黄浦\n${p?.data?.value ?? ""}`
|
||||||
|
break;
|
||||||
|
case '徐汇区':
|
||||||
|
return `徐汇\n${p?.data?.value ?? ""}`
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return `${p.name}\n${p?.data?.value ?? ""}`
|
||||||
|
break;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
textStyle: {
|
textStyle: { color: "#fff", fontSize: 12, fontWeight: '700' }, // 标签文字样式
|
||||||
color: "#fff", // 标签文字颜色
|
|
||||||
fontSize: 11, // 标签文字大小
|
|
||||||
},
|
},
|
||||||
|
itemStyle: {
|
||||||
|
borderWidth: 0.5,
|
||||||
|
borderColor: "#FFFFFF", // 区域边界颜色
|
||||||
|
opacity: 1, // 区域透明度
|
||||||
},
|
},
|
||||||
emphasis: {
|
emphasis: {
|
||||||
show: true,
|
label: { show: true, textStyle: { color: "#fff" } }, // 高亮时的标签样式
|
||||||
textStyle: { color: "#fff" },
|
|
||||||
}, // 高亮状态下不显示标签,文本颜色为白色
|
|
||||||
},
|
},
|
||||||
roam: false, // 关闭鼠标缩放和平移漫游
|
regionHeight: 5, // 地图区域高度
|
||||||
itemStyle: {
|
viewControl: {
|
||||||
normal: { areaColor: "#031525", borderColor: "#FFFFFF" }, // 正常状态下区域颜色和边界颜色
|
distance: 135, // 视角距离(上海市时稍远一些,看起来更小)
|
||||||
emphasis: { areaColor: "#2B91B7" }, // 高亮状态下区域颜色
|
alpha: 45, // 视角俯仰角
|
||||||
|
beta: -15, // 视角旋转角
|
||||||
|
panMouseButton: "left", // 平移操作的鼠标按键
|
||||||
|
rotateMouseButton: "right", // 旋转操作的鼠标按键
|
||||||
},
|
},
|
||||||
animation: false, // 关闭动画
|
light: {
|
||||||
data: streetScore, // 地图数据
|
main: { intensity: 1.2 }, // 主光源强度
|
||||||
},
|
ambient: { intensity: 0.3 }, // 环境光强度
|
||||||
{
|
|
||||||
type: "bar",
|
|
||||||
data: streetScore.map((item) => 0),
|
|
||||||
barWidth: 10, // 设置柱子最大宽度为10px
|
|
||||||
barMaxWidth: 0, // 设置柱子最大宽度为0
|
|
||||||
barMinWidth: 0, // 设置柱子最小宽度为0
|
|
||||||
// 隐藏柱子核心配置
|
|
||||||
itemStyle: {
|
|
||||||
show: false,
|
|
||||||
color: "#dbeafe", //
|
|
||||||
borderColor: "transparent", // 同步隐藏边框
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
show: false,
|
|
||||||
position: "right",
|
|
||||||
color: "#dbeafe",
|
|
||||||
fontSize: 15,
|
|
||||||
distance: 10,
|
|
||||||
formatter: (params: { dataIndex: number }) =>
|
|
||||||
streetScore[params.dataIndex].value,
|
|
||||||
// 关键修复:强制标签显示
|
|
||||||
overflow: "truncate", // 文本溢出处理
|
|
||||||
// height: 50, // 设置标签最大高度
|
|
||||||
width: 50, // 设置标签最大宽度
|
|
||||||
align: "left", // 左对齐保证位置
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
xAxis: {
|
|
||||||
type: "value",
|
|
||||||
position: "top",
|
|
||||||
show: false,
|
|
||||||
// splitLine: { show: false },
|
|
||||||
// axisLabel: { show: false },
|
|
||||||
// axisLine: { show: false },
|
|
||||||
// axisTick: { show: false }
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
show: false,
|
|
||||||
type: "category",
|
|
||||||
data: streetScore.map((item) => item.name),
|
|
||||||
axisLabel: {
|
|
||||||
color: "#dbeafe", // 设置统一的颜色
|
|
||||||
formatter: function (value: string) {
|
|
||||||
if (value === "上海市奉贤区海湾旅游区") {
|
|
||||||
return "上海...旅游区";
|
|
||||||
} else if (value === "上海海港综合经济开发区") {
|
|
||||||
return "上海...开发区";
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
boundaryGap: true,
|
|
||||||
axisLine: { show: true },
|
|
||||||
axisTick: { show: true },
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
streetChart.setOption(streetOption);
|
streetChart.setOption(streetOption3D);
|
||||||
|
|
||||||
// 监听点击事件
|
// 监听点击事件
|
||||||
streetChart.on("click", function (params) {
|
streetChart.on("click", function (params) {
|
||||||
if (
|
if (
|
||||||
params.componentType === "series" &&
|
params.componentType === "series" &&
|
||||||
params.seriesType === "map" &&
|
params.seriesType === "map3D" &&
|
||||||
selectedStreet.value !== params.name
|
selectedStreet.value !== params.name
|
||||||
) {
|
) {
|
||||||
selectedStreet.value = params.name; // 设置选中的区域名称
|
selectedStreet.value = params.name; // 设置选中的区域名称
|
||||||
@ -3606,7 +3576,7 @@ const initStreetChart = () => {
|
|||||||
// 在这里可以添加更多的逻辑来处理高亮区域
|
// 在这里可以添加更多的逻辑来处理高亮区域
|
||||||
} else if (
|
} else if (
|
||||||
params.componentType === "series" &&
|
params.componentType === "series" &&
|
||||||
params.seriesType === "map" &&
|
params.seriesType === "map3D" &&
|
||||||
selectedStreet.value == params.name
|
selectedStreet.value == params.name
|
||||||
) {
|
) {
|
||||||
//重复点击某个区块(街道)
|
//重复点击某个区块(街道)
|
||||||
@ -3637,8 +3607,8 @@ const initRelationshipChart = () => {
|
|||||||
chartRelationship = echarts.init(chartDom);
|
chartRelationship = echarts.init(chartDom);
|
||||||
|
|
||||||
getRelationshipNetwork().then((res) => {
|
getRelationshipNetwork().then((res) => {
|
||||||
let nodes;
|
let nodes: any[];
|
||||||
let links;
|
let links: any[];
|
||||||
// 处理节点数据,为每个节点设置初始样式
|
// 处理节点数据,为每个节点设置初始样式
|
||||||
if (handleRowValue.value == "") {
|
if (handleRowValue.value == "") {
|
||||||
// 处理连线数据,为每条连线设置初始样式
|
// 处理连线数据,为每条连线设置初始样式
|
||||||
@ -3672,7 +3642,7 @@ const initRelationshipChart = () => {
|
|||||||
nodes = res.data.nodes
|
nodes = res.data.nodes
|
||||||
// 筛选出存在于任何连线中的节点
|
// 筛选出存在于任何连线中的节点
|
||||||
.filter((node: any) =>
|
.filter((node: any) =>
|
||||||
links.some(link =>
|
links.some((link: any) =>
|
||||||
link.target === node.name || link.source === node.name
|
link.target === node.name || link.source === node.name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -3759,7 +3729,7 @@ const initRelationshipChart = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 渲染图表
|
// 渲染图表
|
||||||
chartRelationship.setOption(option);
|
chartRelationship!.setOption(option as any);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 窗口变化时自适应
|
// 窗口变化时自适应
|
||||||
@ -3997,8 +3967,8 @@ const zhifaPinfaData = ref([
|
|||||||
// 新增:品发折线图渲染函数
|
// 新增:品发折线图渲染函数
|
||||||
const choujianEchartsPinfa = () => {
|
const choujianEchartsPinfa = () => {
|
||||||
// 销毁已有实例,防止重复渲染
|
// 销毁已有实例,防止重复渲染
|
||||||
if (main7.value && echarts.getInstanceByDom(main7.value)) {
|
if (main7.value && echarts.getInstanceByDom(main7.value as HTMLElement)) {
|
||||||
echarts.getInstanceByDom(main7.value).dispose();
|
echarts.getInstanceByDom(main7.value as HTMLElement)?.dispose();
|
||||||
}
|
}
|
||||||
var myChart = echarts.init(main7.value);
|
var myChart = echarts.init(main7.value);
|
||||||
const months = ["1月", "2月", "3月", "4月", "5月"];
|
const months = ["1月", "2月", "3月", "4月", "5月"];
|
||||||
@ -4061,14 +4031,13 @@ const choujianEchartsPinfa = () => {
|
|||||||
// },
|
// },
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
formatter: function (params) {
|
formatter: function (params: any[]) {
|
||||||
let ymonth = "";
|
let ymonth = "";
|
||||||
let result = '';
|
let result = '';
|
||||||
const dataMap = {};
|
const dataMap: Record<string, { value: number | null; prediction: number | null }> = {};
|
||||||
|
|
||||||
// 合并实线和虚线数据
|
// 合并实线和虚线数据
|
||||||
params.forEach(item => {
|
params.forEach((item: any) => {
|
||||||
// console.log(item);
|
|
||||||
const isPrediction = item.seriesName.includes('预测');
|
const isPrediction = item.seriesName.includes('预测');
|
||||||
const baseName = isPrediction ? item.seriesName.replace('预测', '') : item.seriesName;
|
const baseName = isPrediction ? item.seriesName.replace('预测', '') : item.seriesName;
|
||||||
|
|
||||||
@ -4077,22 +4046,20 @@ const choujianEchartsPinfa = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isPrediction) {
|
if (isPrediction) {
|
||||||
dataMap[baseName].prediction = item.value;
|
dataMap[baseName].prediction = item.value as number | null;
|
||||||
} else {
|
} else {
|
||||||
dataMap[baseName].value = item.value;
|
dataMap[baseName].value = item.value as number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ymonth = item.name;
|
ymonth = item.name;
|
||||||
// console.log(ymonth);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 构建tooltip内容
|
Object.keys(dataMap).forEach((name: string) => {
|
||||||
Object.keys(dataMap).forEach(name => {
|
|
||||||
const item = dataMap[name];
|
const item = dataMap[name];
|
||||||
if (item.prediction && ymonth == "5月") {
|
if (item.prediction != null && ymonth == "5月") {
|
||||||
result += `${name}: (预测: ${item.prediction}%)`;
|
result += `${name}: (预测: ${item.prediction}%)`;
|
||||||
} else {
|
} else {
|
||||||
result += `${name}: ${item.value || '0'}%`;
|
result += `${name}: ${item.value ?? 0}%`;
|
||||||
}
|
}
|
||||||
result += '<br/>';
|
result += '<br/>';
|
||||||
});
|
});
|
||||||
@ -4105,10 +4072,10 @@ const choujianEchartsPinfa = () => {
|
|||||||
top: 30,
|
top: 30,
|
||||||
textStyle: { color: "#fff" },
|
textStyle: { color: "#fff" },
|
||||||
// 只显示主线legend
|
// 只显示主线legend
|
||||||
selected: legendData.reduce((acc, cur) => {
|
selected: legendData.reduce((acc: Record<string, boolean>, cur: string) => {
|
||||||
acc[cur] = true;
|
acc[cur] = true;
|
||||||
return acc;
|
return acc;
|
||||||
}, {}),
|
}, {} as Record<string, boolean>),
|
||||||
},
|
},
|
||||||
grid: { left: 45, right: 30, top: 63, bottom: 45 },
|
grid: { left: 45, right: 30, top: 63, bottom: 45 },
|
||||||
xAxis: {
|
xAxis: {
|
||||||
@ -4130,8 +4097,8 @@ const choujianEchartsPinfa = () => {
|
|||||||
|
|
||||||
const zhifaEchartsPinfa = () => {
|
const zhifaEchartsPinfa = () => {
|
||||||
// 销毁已有实例,防止重复渲染
|
// 销毁已有实例,防止重复渲染
|
||||||
if (main8.value && echarts.getInstanceByDom(main8.value)) {
|
if (main8.value && echarts.getInstanceByDom(main8.value as HTMLElement)) {
|
||||||
echarts.getInstanceByDom(main8.value).dispose();
|
echarts.getInstanceByDom(main8.value as HTMLElement)?.dispose();
|
||||||
}
|
}
|
||||||
var myChart = echarts.init(main8.value);
|
var myChart = echarts.init(main8.value);
|
||||||
const months = ["1月", "2月", "3月", "4月", "5月"];
|
const months = ["1月", "2月", "3月", "4月", "5月"];
|
||||||
@ -4195,14 +4162,13 @@ const zhifaEchartsPinfa = () => {
|
|||||||
// },
|
// },
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
formatter: function (params) {
|
formatter: function (params: any[]) {
|
||||||
let ymonth = "";
|
let ymonth = "";
|
||||||
let result = '';
|
let result = '';
|
||||||
const dataMap = {};
|
const dataMap: Record<string, { value: number | null; prediction: number | null }> = {};
|
||||||
|
|
||||||
// 合并实线和虚线数据
|
// 合并实线和虚线数据
|
||||||
params.forEach(item => {
|
params.forEach((item: any) => {
|
||||||
// console.log(item);
|
|
||||||
const isPrediction = item.seriesName.includes('预测');
|
const isPrediction = item.seriesName.includes('预测');
|
||||||
const baseName = isPrediction ? item.seriesName.replace('预测', '') : item.seriesName;
|
const baseName = isPrediction ? item.seriesName.replace('预测', '') : item.seriesName;
|
||||||
|
|
||||||
@ -4211,22 +4177,20 @@ const zhifaEchartsPinfa = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isPrediction) {
|
if (isPrediction) {
|
||||||
dataMap[baseName].prediction = item.value;
|
dataMap[baseName].prediction = item.value as number | null;
|
||||||
} else {
|
} else {
|
||||||
dataMap[baseName].value = item.value;
|
dataMap[baseName].value = item.value as number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ymonth = item.name;
|
ymonth = item.name;
|
||||||
// console.log(ymonth);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 构建tooltip内容
|
Object.keys(dataMap).forEach((name: string) => {
|
||||||
Object.keys(dataMap).forEach(name => {
|
|
||||||
const item = dataMap[name];
|
const item = dataMap[name];
|
||||||
if (ymonth == "5月") {
|
if (ymonth == "5月") {
|
||||||
result += `${name}: (预测: ${item.prediction}%)`;
|
result += `${name}: (预测: ${item.prediction}%)`;
|
||||||
} else {
|
} else {
|
||||||
result += `${name}: ${item.value || '0'}%`;
|
result += `${name}: ${item.value ?? 0}%`;
|
||||||
}
|
}
|
||||||
result += '<br/>';
|
result += '<br/>';
|
||||||
});
|
});
|
||||||
@ -4239,10 +4203,10 @@ const zhifaEchartsPinfa = () => {
|
|||||||
top: 30,
|
top: 30,
|
||||||
textStyle: { color: "#fff" },
|
textStyle: { color: "#fff" },
|
||||||
// 只显示主线legend
|
// 只显示主线legend
|
||||||
selected: legendData.reduce((acc, cur) => {
|
selected: legendData.reduce((acc: Record<string, boolean>, cur: string) => {
|
||||||
acc[cur] = true;
|
acc[cur] = true;
|
||||||
return acc;
|
return acc;
|
||||||
}, {}),
|
}, {} as Record<string, boolean>),
|
||||||
},
|
},
|
||||||
grid: { left: 45, right: 30, top: 63, bottom: 45 },
|
grid: { left: 45, right: 30, top: 63, bottom: 45 },
|
||||||
xAxis: {
|
xAxis: {
|
||||||
@ -4320,6 +4284,7 @@ const jubaoPinfaData = ref([
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
const highlightGraphNodeByName = (nodeName: string) => {
|
const highlightGraphNodeByName = (nodeName: string) => {
|
||||||
|
if (!chartRelationship) return;
|
||||||
// 先取消所有高亮
|
// 先取消所有高亮
|
||||||
chartRelationship.dispatchAction({
|
chartRelationship.dispatchAction({
|
||||||
type: "downplay",
|
type: "downplay",
|
||||||
@ -4351,8 +4316,8 @@ const handleRowClick = (item: any, index: number) => {
|
|||||||
const fancyBtn = ref(null)
|
const fancyBtn = ref(null)
|
||||||
const ripple = ref(null)
|
const ripple = ref(null)
|
||||||
const handleFancyClick = (e: MouseEvent) => {
|
const handleFancyClick = (e: MouseEvent) => {
|
||||||
const btn = fancyBtn.value as HTMLElement
|
const btn = fancyBtn.value as unknown as HTMLElement
|
||||||
const span = ripple.value as HTMLElement
|
const span = ripple.value as unknown as HTMLElement
|
||||||
if (!btn || !span) return
|
if (!btn || !span) return
|
||||||
const rect = btn.getBoundingClientRect()
|
const rect = btn.getBoundingClientRect()
|
||||||
const size = Math.max(rect.width, rect.height)
|
const size = Math.max(rect.width, rect.height)
|
||||||
@ -4589,4 +4554,70 @@ const handleFancyClick = (e: MouseEvent) => {
|
|||||||
transform: scale(0) !important;
|
transform: scale(0) !important;
|
||||||
transition: none !important;
|
transition: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fancy-border {
|
||||||
|
position: relative;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||||
|
background: rgba(255, 255, 255, 0.04);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
box-shadow:
|
||||||
|
0 8px 24px rgba(0, 0, 0, 0.35),
|
||||||
|
inset 0 0 20px rgba(34, 211, 238, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fancy-border::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: -1px;
|
||||||
|
border-radius: inherit;
|
||||||
|
padding: 1px;
|
||||||
|
background: linear-gradient(90deg,
|
||||||
|
rgba(34, 211, 238, 0.6),
|
||||||
|
rgba(59, 130, 246, 0.6),
|
||||||
|
rgba(168, 85, 247, 0.6));
|
||||||
|
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
|
||||||
|
-webkit-mask-composite: xor;
|
||||||
|
mask-composite: exclude;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fancy-border:hover {
|
||||||
|
box-shadow:
|
||||||
|
0 10px 28px rgba(0, 0, 0, 0.45),
|
||||||
|
inset 0 0 26px rgba(34, 211, 238, 0.25);
|
||||||
|
transition: box-shadow 0.25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
fancy-border 相关 CSS 解释:
|
||||||
|
|
||||||
|
1. .fancy-border
|
||||||
|
- position: relative; // 设为相对定位,为伪元素定位提供参考
|
||||||
|
- border-radius: 12px; // 圆角边框
|
||||||
|
- border: 1px solid rgba(255, 255, 255, 0.15); // 半透明白色边框
|
||||||
|
- background: rgba(255, 255, 255, 0.04); // 非常浅的白色背景,几乎透明
|
||||||
|
- backdrop-filter: blur(4px); // 背景模糊效果,提升玻璃拟态质感
|
||||||
|
- box-shadow:
|
||||||
|
0 8px 24px rgba(0, 0, 0, 0.35), // 外部阴影,增加立体感
|
||||||
|
inset 0 0 20px rgba(34, 211, 238, 0.15); // 内部青色阴影,增加层次感
|
||||||
|
|
||||||
|
2. .fancy-border::before
|
||||||
|
- content: ""; // 生成一个空内容的伪元素
|
||||||
|
- position: absolute; // 绝对定位,覆盖在父元素上
|
||||||
|
- inset: -1px; // 四周扩展1px,确保边框完整
|
||||||
|
- border-radius: inherit; // 继承父元素圆角
|
||||||
|
- padding: 1px; // 内边距1px
|
||||||
|
- background: linear-gradient(90deg, ...); // 渐变色边框,青-蓝-紫
|
||||||
|
- -webkit-mask 与 mask-composite: // 利用遮罩实现只有边框区域显示渐变色,内容区透明
|
||||||
|
- pointer-events: none; // 伪元素不响应鼠标事件
|
||||||
|
|
||||||
|
3. .fancy-border:hover
|
||||||
|
- box-shadow:
|
||||||
|
0 10px 28px rgba(0, 0, 0, 0.45), // 悬浮时外部阴影更深
|
||||||
|
inset 0 0 26px rgba(34, 211, 238, 0.25); // 内部青色阴影更明显
|
||||||
|
- transition: box-shadow 0.25s ease; // 阴影变化有过渡动画
|
||||||
|
|
||||||
|
整体效果:实现了一个带有渐变炫彩边框、玻璃拟态背景、悬浮高亮的美观卡片样式。
|
||||||
|
*/
|
||||||
</style>
|
</style>
|
||||||
|
@ -6,6 +6,8 @@ export default defineConfig({
|
|||||||
plugins: [vue()],
|
plugins: [vue()],
|
||||||
server: {
|
server: {
|
||||||
//host: '0.0.0.0'
|
//host: '0.0.0.0'
|
||||||
|
allowedHosts: ['294a8d70.r23.cpolar.top']
|
||||||
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user