@ -79,6 +79,11 @@
< / div >
< div class = "map-stage" >
image . png < img
class = "map-world-bg"
src = "/images/世界地图背景.png"
alt = ""
/ >
< div ref = "chartRef" class = "chart-container" > < / div >
< div class = "map-legend" aria -hidden = " true " >
< img class = "map-legend-bg" :src ="LEGEND_BG" alt = "" / >
@ -117,11 +122,17 @@ const currentMode = ref('outflow')
let chartInstance = null
let sourceChartInstance = null
let salesChartInstance = null
let resizeObserver = null
let chinaMapData = null
let tradingData = null
let mapSystemConfig = null
let cachedOutlineKey = ''
let cachedOutlinePaths = [ ]
let unitedMapKey = ''
let mapBgImage = null
let mapBgImagePromise = null
let mapSurfaceTexture = null
let mapSurfaceTextureKey = ''
/ / 浮 动 面 板 状 态
const showSourcePanel = ref ( false )
@ -143,47 +154,50 @@ const modes = [
const BTN _NORMAL = '/images/按钮.png'
const BTN _ACTIVE = '/images/按钮选中.png'
const LEGEND _BG = '/images/图例bg.png'
const GEO _DATA _INDEX = 2
const WIREFRAME _GEO _INDEX = 3
const GEO _DATA _INDEX = 4
const WIREFRAME _GEO _INDEX = 5
const MAP _ASPECT _SCALE = 0.82
const MAP _ZOOM _FACTOR = 0.97
const MAP _LAYOUT _SIZE = '84%'
const MAP _ANCHOR _CENTER = [ 104.8 , 37.2 ]
const MAP _ANCHOR _ZOOM = 1.05
const MAP _GLOBAL _OFFSET _LNG = 1.45
const MAP _GLOBAL _OFFSET _LAT = 0.9
const MAP _GLOBAL _LAYOUT _X = - 2.8
const MAP _GLOBAL _LAYOUT _Y = 3.6
const MAP _SHADOW _OFFSET _FAR = 1.25
const MAP _SHADOW _OFFSET _NEAR = 0.75
const MAP _SHADOW _OFFSET _LNG = - 0.45
const MAP _ZOOM _FACTOR = 1
const MAP _LAYOUT _SIZE = '88%'
const MAP _ANCHOR _CENTER = [ 105.2 , 36.8 ]
const MAP _ANCHOR _ZOOM = 1.08
const MAP _GLOBAL _OFFSET _LNG = 1.2
const MAP _GLOBAL _OFFSET _LAT = 0.85
const MAP _GLOBAL _LAYOUT _X = - 2.2
const MAP _GLOBAL _LAYOUT _Y = 2.8
const MAP _SHADOW _OFFSET _FAR = 1.85
const MAP _SHADOW _OFFSET _MID = 1.2
const MAP _SHADOW _OFFSET _NEAR = 0.62
const MAP _SHADOW _OFFSET _LNG = - 0.42
const MAP _SHADOW _OFFSET _FAR _LOCAL = 5
const MAP _SHADOW _OFFSET _NEAR _LOCAL = 3
const MAP _SHADOW _OFFSET _MID _LOCAL = 3.5
const MAP _SHADOW _OFFSET _NEAR _LOCAL = 2.2
const MAP _SHADOW _OFFSET _LNG _LOCAL = - 2
const MAP _WIREFRAME _OFFSET = - 0.65
const MAP _WIREFRAME _OFFSET _LNG = 0.12
const MAP _WIREFRAME _OFFSET = - 0.72
const MAP _WIREFRAME _OFFSET _LNG = 0.1
const MAP _WIREFRAME _OFFSET _LOCAL = - 3.5
const MAP _WIREFRAME _OFFSET _LNG _LOCAL = 0.6
const MAP _FILL _WEST = [ 45 , 181 , 181 ]
const MAP _FILL _EAST = [ 12 , 123 , 176 ]
const MAP _GRADIENT _MIN _LNG = 73
const MAP _GRADIENT _MAX _LNG = 135
const MAP _GRADIENT _MIN _LAT = 18
const MAP _GRADIENT _MAX _LAT = 54
const MAP _WIREFRAME _COLOR = '#f8feff'
const MAP _INNER _BORDER = 'rgba(6, 38, 62, 0.62)'
const MAP _INNER _BORDER _WIDTH = 0.8
const MAP _SHADOW _FAR = '#000000'
const MAP _SHADOW _NEAR = '#000000'
const MAP _WIREFRAME _COLOR = '#f2fdff'
const MAP _INNER _BORDER = 'rgba(4, 32, 52, 0.28)'
const MAP _INNER _BORDER _WIDTH = 0.45
const MAP _SHADOW _FILL _FAR = '#010204'
const MAP _SHADOW _FILL _MID = '#020408'
const MAP _SHADOW _FILL _NEAR = '#030a12'
const MAP _LABEL _COLOR = '#ffffff'
const MAP _FILL _OPACITY = 0.88
const MAP _TEXTURE _SIZE = 128
/ / 世 界 地 图 背 景 源 图 ( 4 3 1 8 × 1 0 7 8 ) 中 中 国 区 域 裁 剪 , 用 于 烘 焙 进 地 图 纹 理
const MAP _BG _IMAGE = '/images/世界地图背景.png'
const MAP _BG _NATIVE _WIDTH = 4318
const MAP _BG _NATIVE _HEIGHT = 1078
const MAP _BG _CROP _CHINA = { x : 1160 , y : 108 , width : 2000 , height : 828 }
const MAP _BG _CROP _LOCAL = { x : 1860 , y : 332 , width : 820 , height : 520 }
const MAP _SURFACE _TEXTURE _WIDTH = 1536
const MAP _SURFACE _TEXTURE _HEIGHT = 1152
const MAP _SURFACE _FALLBACK = 'rgb(92, 202, 206)'
const MAP _SURFACE _COLOR = 'rgba(0, 0, 0, 0)'
/ / p a t h 符 号 需 朝 上 绘 制 , E C h a r t s 会 沿 路 径 切 线 自 动 旋 转
const METEOR _EFFECT _PATH = 'path://M0.5,0 L0.56,0.14 L0.52,1 L0.48,1 L0.44,0.14 Z'
const mapTextureCache = new Map ( )
/ / 获 取 当 前 模 式 对 应 的 地 图 文 件 路 径
const getMapFilePath = ( mode ) => {
switch ( mode ) {
@ -269,9 +283,12 @@ const loadData = async (mapMode = 'china') => {
/ / 注 册 地 图
const mapName = getMapName ( mapMode )
echarts . registerMap ( mapName , chinaMapData )
unitedMapKey = ''
registerUnitedMap ( mapMode )
mapSurfaceTexture = null
mapSurfaceTextureKey = ''
cachedOutlineKey = ''
cachedOutlinePaths = [ ]
mapTextureCache . clear ( )
return true
} catch ( error ) {
@ -669,8 +686,6 @@ const calculateMapBounds = () => {
}
}
const clamp = ( value , min , max ) => Math . min ( max , Math . max ( min , value ) )
const getFeatureCenter = ( feature ) => {
const cp = feature ? . properties ? . cp || feature ? . properties ? . center
if ( Array . isArray ( cp ) && cp . length >= 2 ) {
@ -682,91 +697,201 @@ const getFeatureCenter = (feature) => {
return [ 104 , 35 ]
}
const getRegionAreaColor = ( lng , lat , minLng , maxLng , minLat , maxLat ) => {
const { r , g , b } = blendDesignColor ( lng , lat , minLng , maxLng , minLat , maxLat )
const cacheKey = ` ${ r } , ${ g } , ${ b } , ${ MAP _FILL _OPACITY } `
const getUnitedMapName = ( mode = currentMode . value ) => ` ${ getMapName ( mode ) } -united `
if ( ! mapTextureCache . has ( cacheKey ) ) {
mapTextureCache . set ( cacheKey , createRegionTextureCanvas ( r , g , b , MAP _FILL _OPACITY ) )
const buildUnitedGeoJson = ( geojson ) => {
if ( ! geojson ? . features ? . length ) {
return geojson
}
const coordinates = [ ]
geojson . features . forEach ( ( feature ) => {
const geom = feature . geometry
if ( ! geom ) {
return
}
if ( geom . type === 'Polygon' ) {
coordinates . push ( geom . coordinates )
} else if ( geom . type === 'MultiPolygon' ) {
geom . coordinates . forEach ( ( polygon ) => coordinates . push ( polygon ) )
}
} )
return {
image : mapTextureCache . get ( cacheKey ) ,
repeat : 'repeat'
type : 'FeatureCollection' ,
features : [ {
type : 'Feature' ,
properties : { name : 'united' } ,
geometry : {
type : 'MultiPolygon' ,
coordinates
}
} ]
}
}
const createRegionTextureCanvas = ( r , g , b , alpha ) => {
if ( typeof document === 'undefined' ) {
return null
const registerUnitedMap = ( mapMode = currentMode . value ) => {
const unitedName = getUnitedMapName ( mapMode )
const key = ` ${ unitedName } - ${ chinaMapData ? . features ? . length || 0 } `
if ( unitedMapKey !== key ) {
echarts . registerMap ( unitedName , buildUnitedGeoJson ( chinaMapData ) )
unitedMapKey = key
mapSurfaceTexture = null
mapSurfaceTextureKey = ''
}
return unitedName
}
const getMapBgCrop = ( ) => (
currentMode . value === 'local' ? MAP _BG _CROP _LOCAL : MAP _BG _CROP _CHINA
)
const loadMapBgImage = ( ) => {
if ( mapBgImage ) {
return Promise . resolve ( mapBgImage )
}
if ( mapBgImagePromise ) {
return mapBgImagePromise
}
mapBgImagePromise = new Promise ( ( resolve , reject ) => {
if ( typeof Image === 'undefined' ) {
reject ( new Error ( 'Image is not available' ) )
return
}
const image = new Image ( )
image . decoding = 'async'
image . onload = ( ) => {
mapBgImage = image
resolve ( image )
}
image . onerror = ( ) => {
mapBgImagePromise = null
reject ( new Error ( ` Failed to load ${ MAP _BG _IMAGE } ` ) )
}
image . src = MAP _BG _IMAGE
} )
return mapBgImagePromise
}
const paintMapSurfaceTexture = ( ctx , width , height , image , crop ) => {
ctx . clearRect ( 0 , 0 , width , height )
/ / 1 . 地 形 纹 理 打 底 ( 略 提 亮 对 比 , 保 证 纹 路 可 见 )
ctx . filter = 'brightness(1.28) contrast(1.18)'
ctx . drawImage (
image ,
crop . x ,
crop . y ,
crop . width ,
crop . height ,
0 ,
0 ,
width ,
height
)
ctx . filter = 'none'
/ / 2 . o v e r l a y 青 蓝 染 色 : G / B 均 衡 , 介 于 青 色 与 蓝 色 之 间
ctx . globalCompositeOperation = 'overlay'
const tintGradient = ctx . createRadialGradient (
width * 0.44 ,
height * 0.48 ,
0 ,
width * 0.44 ,
height * 0.48 ,
Math . max ( width , height ) * 0.86
)
tintGradient . addColorStop ( 0 , 'rgba(158, 236, 228, 0.94)' )
tintGradient . addColorStop ( 0.42 , 'rgba(108, 212, 214, 0.90)' )
tintGradient . addColorStop ( 0.78 , 'rgba(82, 194, 200, 0.86)' )
tintGradient . addColorStop ( 1 , 'rgba(68, 180, 188, 0.82)' )
ctx . fillStyle = tintGradient
ctx . fillRect ( 0 , 0 , width , height )
/ / 3 . s o f t - l i g h t 补 一 层 青 蓝 , 提 亮 暗 部
ctx . globalCompositeOperation = 'soft-light'
ctx . fillStyle = 'rgba(118, 218, 214, 0.36)'
ctx . fillRect ( 0 , 0 , width , height )
/ / 4 . s c r e e n 中 心 高 光
ctx . globalCompositeOperation = 'screen'
const glowGradient = ctx . createRadialGradient (
width * 0.43 ,
height * 0.46 ,
0 ,
width * 0.43 ,
height * 0.46 ,
Math . max ( width , height ) * 0.58
)
glowGradient . addColorStop ( 0 , 'rgba(205, 248, 242, 0.34)' )
glowGradient . addColorStop ( 0.55 , 'rgba(175, 235, 228, 0.14)' )
glowGradient . addColorStop ( 1 , 'rgba(175, 235, 228, 0)' )
ctx . fillStyle = glowGradient
ctx . fillRect ( 0 , 0 , width , height )
ctx . globalCompositeOperation = 'source-over'
}
const size = MAP _TEXTURE _SIZE
const createMapSurfaceTexture = ( image ) => {
const width = MAP _SURFACE _TEXTURE _WIDTH
const height = MAP _SURFACE _TEXTURE _HEIGHT
const canvas = document . createElement ( 'canvas' )
canvas . width = size
canvas . height = size
canvas . width = width
canvas . height = height
const ctx = canvas . getContext ( '2d' )
if ( ! ctx ) {
return null
}
ctx . fillStyle = ` rgba( ${ r } , ${ g } , ${ b } , ${ alpha } ) `
ctx . fillRect ( 0 , 0 , size , size )
for ( let i = 0 ; i < 420 ; i += 1 ) {
const x = Math . random ( ) * size
const y = Math . random ( ) * size
const radius = Math . random ( ) * 1.6 + 0.3
ctx . fillStyle = ` rgba(255, 255, 255, ${ Math . random ( ) * 0.1 + 0.02 } ) `
ctx . beginPath ( )
ctx . arc ( x , y , radius , 0 , Math . PI * 2 )
ctx . fill ( )
paintMapSurfaceTexture ( ctx , width , height , image , getMapBgCrop ( ) )
return canvas
}
for ( let i = 0 ; i < 260 ; i += 1 ) {
const x = Math . random ( ) * size
const y = Math . random ( ) * size
const radius = Math . random ( ) * 2.4 + 0.6
ctx . fillStyle = ` rgba(8, 45, 72, ${ Math . random ( ) * 0.08 + 0.02 } ) `
ctx . beginPath ( )
ctx . arc ( x , y , radius , 0 , Math . PI * 2 )
ctx . fill ( )
const ensureMapSurfaceTexture = async ( ) => {
const key = currentMode . value
if ( mapSurfaceTexture && mapSurfaceTextureKey === key ) {
return mapSurfaceTexture
}
for ( let i = 0 ; i < 6 ; i += 1 ) {
const x = Math . random ( ) * size
const y = Math . random ( ) * size
const radius = Math . random ( ) * 28 + 18
const gradient = ctx . createRadialGradient ( x , y , 0 , x , y , radius )
gradient . addColorStop ( 0 , ` rgba(255, 255, 255, ${ Math . random ( ) * 0.06 + 0.02 } ) ` )
gradient . addColorStop ( 1 , 'rgba(255, 255, 255, 0)' )
ctx . fillStyle = gradient
ctx . beginPath ( )
ctx . arc ( x , y , radius , 0 , Math . PI * 2 )
ctx . fill ( )
const image = await loadMapBgImage ( )
mapSurfaceTexture = createMapSurfaceTexture ( image )
mapSurfaceTextureKey = key
return mapSurfaceTexture
}
return canvas
const getMapSurfaceAreaStyle = ( ) => {
if ( mapSurfaceTexture ) {
return {
areaColor : {
image : mapSurfaceTexture ,
repeat : 'no-repeat'
}
}
}
const blendDesignColor = ( lng , lat , minLng , maxLng , minLat , maxLat ) => {
const lngRatio = clamp ( ( lng - minLng ) / ( maxLng - minLng ) , 0 , 1 )
const latRatio = clamp ( ( lat - minLat ) / ( maxLat - minLat ) , 0 , 1 )
let r = MAP _FILL _WEST [ 0 ] + ( MAP _FILL _EAST [ 0 ] - MAP _FILL _WEST [ 0 ] ) * lngRatio
let g = MAP _FILL _WEST [ 1 ] + ( MAP _FILL _EAST [ 1 ] - MAP _FILL _WEST [ 1 ] ) * lngRatio
let b = MAP _FILL _WEST [ 2 ] + ( MAP _FILL _EAST [ 2 ] - MAP _FILL _WEST [ 2 ] ) * lngRatio
return { areaColor : MAP _SURFACE _FALLBACK }
}
const northBoost = ( 0.62 - latRatio ) * 16
const southDepth = ( latRatio - 0.38 ) * 10
r = clamp ( r + northBoost - southDepth * 0.35 , 0 , 255 )
g = clamp ( g + northBoost * 0.95 - southDepth * 0.25 , 0 , 255 )
b = clamp ( b + northBoost * 0.55 - southDepth * 0.15 , 0 , 255 )
const refreshMapSurfaceTexture = async ( ) => {
if ( ! chartInstance ) {
return
}
return {
r : Math . round ( r ) ,
g : Math . round ( g ) ,
b : Math . round ( b )
try {
await ensureMapSurfaceTexture ( )
const mapBounds = calculateMapBounds ( )
const mapName = getMapName ( currentMode . value )
const unitedMapName = registerUnitedMap ( currentMode . value )
chartInstance . setOption ( {
geo : buildGeoLayers ( mapName , unitedMapName , mapBounds )
} , {
replaceMerge : [ 'geo' ]
} )
} catch ( error ) {
console . warn ( '地图纹理生成失败:' , error )
}
}
@ -898,49 +1023,6 @@ const getWireframePaths = () => {
return cachedOutlinePaths
}
const buildRegionFillData = ( ) => {
if ( ! chinaMapData ? . features ? . length ) {
return [ ]
}
let minLng = MAP _GRADIENT _MIN _LNG
let maxLng = MAP _GRADIENT _MAX _LNG
let minLat = MAP _GRADIENT _MIN _LAT
let maxLat = MAP _GRADIENT _MAX _LAT
if ( currentMode . value === 'local' ) {
const centers = chinaMapData . features . map ( getFeatureCenter )
const lngs = centers . map ( ( center ) => center [ 0 ] )
const lats = centers . map ( ( center ) => center [ 1 ] )
minLng = Math . min ( ... lngs )
maxLng = Math . max ( ... lngs )
minLat = Math . min ( ... lats )
maxLat = Math . max ( ... lats )
if ( maxLng - minLng < 0.001 ) {
maxLng = minLng + 1
}
if ( maxLat - minLat < 0.001 ) {
maxLat = minLat + 1
}
}
return chinaMapData . features . map ( ( feature ) => {
const name = feature . properties ? . name
if ( ! name ) {
return null
}
const [ lng , lat ] = getFeatureCenter ( feature )
return {
name ,
itemStyle : {
areaColor : getRegionAreaColor ( lng , lat , minLng , maxLng , minLat , maxLat ) ,
borderColor : MAP _INNER _BORDER ,
borderWidth : MAP _INNER _BORDER _WIDTH
}
}
} ) . filter ( Boolean )
}
const getMapProjection = ( mapBounds , latOffset = 0 , lngOffset = 0 ) => {
const isLocal = currentMode . value === 'local'
if ( isLocal ) {
@ -965,41 +1047,59 @@ const getMapProjection = (mapBounds, latOffset = 0, lngOffset = 0) => {
}
}
const buildGeoLayers = ( mapName , mapBounds ) => {
const isLocal = currentMode . value === 'local'
const shadowFarOffset = isLocal ? MAP _SHADOW _OFFSET _FAR _LOCAL : MAP _SHADOW _OFFSET _FAR
const shadowNearOffset = isLocal ? MAP _SHADOW _OFFSET _NEAR _LOCAL : MAP _SHADOW _OFFSET _NEAR
const shadowLngOffset = isLocal ? MAP _SHADOW _OFFSET _LNG _LOCAL : MAP _SHADOW _OFFSET _LNG
const wireframeOffset = isLocal ? MAP _WIREFRAME _OFFSET _LOCAL : MAP _WIREFRAME _OFFSET
const wireframeLngOffset = isLocal ? MAP _WIREFRAME _OFFSET _LNG _LOCAL : MAP _WIREFRAME _OFFSET _LNG
return [
{
map : mapName ,
const buildShadowFillGeo = ( unitedMapName , mapBounds , latOffset , lngOffset , areaColor , z ) => ( {
map : unitedMapName ,
roam : false ,
... getMapProjection ( mapBounds , shadowFarOffset , shadowL ngOffset) ,
... getMapProjection ( mapBounds , latOffset , lngOffset ) ,
silent : true ,
zlevel : 0 ,
z : 1 ,
z ,
label : { show : false } ,
itemStyle : {
areaColor : MAP _SHADOW _FAR ,
borderColor : MAP _SHADOW _FAR ,
areaColor ,
borderColor : 'transparent' ,
borderWidth : 0
}
} ,
emphasis : {
disabled : true
}
} )
const getShadowOffsets = ( ) => {
const isLocal = currentMode . value === 'local'
return {
far : isLocal ? MAP _SHADOW _OFFSET _FAR _LOCAL : MAP _SHADOW _OFFSET _FAR ,
mid : isLocal ? MAP _SHADOW _OFFSET _MID _LOCAL : MAP _SHADOW _OFFSET _MID ,
near : isLocal ? MAP _SHADOW _OFFSET _NEAR _LOCAL : MAP _SHADOW _OFFSET _NEAR ,
lng : isLocal ? MAP _SHADOW _OFFSET _LNG _LOCAL : MAP _SHADOW _OFFSET _LNG
}
}
const buildGeoLayers = ( mapName , unitedMapName , mapBounds ) => {
const isLocal = currentMode . value === 'local'
const wireframeOffset = isLocal ? MAP _WIREFRAME _OFFSET _LOCAL : MAP _WIREFRAME _OFFSET
const wireframeLngOffset = isLocal ? MAP _WIREFRAME _OFFSET _LNG _LOCAL : MAP _WIREFRAME _OFFSET _LNG
const { far , mid , near , lng } = getShadowOffsets ( )
return [
buildShadowFillGeo ( unitedMapName , mapBounds , far , lng , MAP _SHADOW _FILL _FAR , 1 ) ,
buildShadowFillGeo ( unitedMapName , mapBounds , mid , lng , MAP _SHADOW _FILL _MID , 2 ) ,
buildShadowFillGeo ( unitedMapName , mapBounds , near , lng , MAP _SHADOW _FILL _NEAR , 3 ) ,
{
map : mapName ,
map : unitedM apName,
roam : false ,
... getMapProjection ( mapBounds , shadowNearOffset , shadowLngOffset ) ,
... getMapProjection ( mapBounds , 0 ) ,
silent : true ,
zlevel : 0 ,
zlevel : 1 ,
z : 2 ,
label : { show : false } ,
itemStyle : {
areaColor : MAP _SHADOW _NEAR ,
borderColor : MAP _SHADOW _NEAR ,
... getMapSurfaceAreaStyle ( ) ,
borderColor : 'transparent' ,
borderWidth : 0
} ,
emphasis : {
disabled : true
}
} ,
{
@ -1047,6 +1147,7 @@ const getChartOption = () => {
const effectScatterData = generateEffectScatterData ( )
const mapBounds = calculateMapBounds ( )
const mapName = getMapName ( currentMode . value )
const unitedMapName = registerUnitedMap ( currentMode . value )
const mapLayout = getMapProjection ( mapBounds , 0 )
const outlinePaths = getWireframePaths ( )
const wireframeData = outlinePaths . map ( ( coords ) => ( { coords } ) )
@ -1113,7 +1214,7 @@ const getChartOption = () => {
return params . name
}
} ,
geo : buildGeoLayers ( mapName , mapBounds ) ,
geo : buildGeoLayers ( mapName , unitedMapName , mapBounds ) ,
series : [
{
name : 'mapFill' ,
@ -1124,18 +1225,18 @@ const getChartOption = () => {
zlevel : 2 ,
silent : true ,
selectedMode : false ,
data : buildRegionFillData ( ) ,
itemStyle : {
areaColor : MAP _SURFACE _COLOR ,
borderColor : MAP _INNER _BORDER ,
borderWidth : MAP _INNER _BORDER _WIDTH
} ,
label : {
show : true ,
color : MAP _LABEL _COLOR ,
fontSize : 11 ,
fontSize : 12 ,
fontFamily : 'Microsoft YaHei, sans-serif' ,
fontWeight : 'bold' ,
textBorderColor : 'rgba(0, 0, 0, 0.4 5)' ,
textBorderColor : 'rgba(0, 0, 0, 0.5)' ,
textBorderWidth : 2
} ,
emphasis : {
@ -1153,12 +1254,12 @@ const getChartOption = () => {
data : wireframeData ,
lineStyle : {
color : MAP _WIREFRAME _COLOR ,
width : 3 .2,
opacity : 0.96 ,
width : 4 .2,
opacity : 0.98 ,
cap : 'round' ,
join : 'round' ,
shadowBlur : 16 ,
shadowColor : 'rgba(120, 230, 255, 0.6 )'
shadowBlur : 22 ,
shadowColor : 'rgba(130, 245, 255, 0.78 )'
}
} ,
{
@ -1200,12 +1301,12 @@ const getChartOption = () => {
zlevel : 6 ,
data : linesData ,
lineStyle : {
color : '#7ee8 ff' ,
width : 1.2 ,
opacity : 0.75 ,
curveness : 0.28 ,
shadowBlur : 8 ,
shadowColor : 'rgba(110, 232, 255, 0.5 5)'
color : '#a8f6 ff' ,
width : 1.5 ,
opacity : 0.82 ,
curveness : 0.3 2 ,
shadowBlur : 10 ,
shadowColor : 'rgba(120, 240, 255, 0.6 5)'
} ,
emphasis : {
lineStyle : {
@ -1226,17 +1327,17 @@ const getChartOption = () => {
data : linesData ,
effect : {
show : true ,
constantSpeed : 50 ,
constantSpeed : 55 ,
symbol : METEOR _EFFECT _PATH ,
symbolSize : [ 5 , 20 ] ,
trailLength : 0.14 ,
symbolSize : [ 5 , 22 ] ,
trailLength : 0.16 ,
loop : true ,
color : '#ffff ff'
color : '#e8fb ff'
} ,
lineStyle : {
width : 0 ,
opacity : 0 ,
curveness : 0.28
curveness : 0.3 2
}
} ,
{
@ -1292,9 +1393,12 @@ const reloadMapData = async (mapMode) => {
const mapName = getMapName ( mapMode )
echarts . registerMap ( mapName , chinaMapData )
unitedMapKey = ''
registerUnitedMap ( mapMode )
mapSurfaceTexture = null
mapSurfaceTextureKey = ''
cachedOutlineKey = ''
cachedOutlinePaths = [ ]
mapTextureCache . clear ( )
return true
} catch ( error ) {
@ -1303,6 +1407,10 @@ const reloadMapData = async (mapMode) => {
}
}
const handleChartResize = ( ) => {
chartInstance ? . resize ( )
}
/ / 初 始 化 图 表
const initChart = async ( ) => {
if ( ! chartRef . value ) return
@ -1312,6 +1420,7 @@ const initChart = async () => {
chartInstance = echarts . init ( chartRef . value )
chartInstance . setOption ( getChartOption ( ) )
await refreshMapSurfaceTexture ( )
/ / 添 加 鼠 标 事 件 监 听
chartInstance . on ( 'mouseover' , ( params ) => {
@ -1333,9 +1442,17 @@ const initChart = async () => {
}
} )
/ / 监 听 窗 口 大 小 变 化
window . addEventListener ( 'resize' , ( ) => {
chartInstance ? . resize ( )
window . addEventListener ( 'resize' , handleChartResize )
const mountPoint = chartRef . value . parentElement
if ( mountPoint ) {
resizeObserver = new ResizeObserver ( handleChartResize )
resizeObserver . observe ( mountPoint )
}
await nextTick ( )
requestAnimationFrame ( ( ) => {
handleChartResize ( )
setTimeout ( handleChartResize , 160 )
} )
}
@ -1351,6 +1468,9 @@ const updateChart = async (needReloadMap = false) => {
notMerge : false ,
replaceMerge : [ 'geo' , 'series' ]
} )
await refreshMapSurfaceTexture ( )
await nextTick ( )
handleChartResize ( )
}
}
@ -1371,6 +1491,9 @@ onMounted(() => {
} )
onUnmounted ( ( ) => {
window . removeEventListener ( 'resize' , handleChartResize )
resizeObserver ? . disconnect ( )
resizeObserver = null
if ( chartInstance ) {
chartInstance . dispose ( )
}
@ -1388,12 +1511,15 @@ onUnmounted(() => {
position : relative ;
width : 100 % ;
height : 100 % ;
min - height : 0 ;
overflow : hidden ;
background : transparent ;
}
. map - card : deep ( . card - content ) {
position : relative ;
height : 100 % ;
min - height : 0 ;
padding : 0 ;
}
@ -1473,15 +1599,31 @@ onUnmounted(() => {
position : absolute ;
inset : 0 ;
overflow : hidden ;
background : transparent ;
}
. map - world - bg {
position : absolute ;
width : var ( -- screen - width , 5120 px ) ;
height : var ( -- screen - height , 1440 px ) ;
left : 50 % ;
top : 50 % ;
transform : translate ( - 50 % , - 50 % ) ;
object - fit : fill ;
pointer - events : none ;
user - select : none ;
z - index : 0 ;
}
. chart - container {
position : absolute ;
inset : 0 ;
width : 100 % ;
height : 100 % ;
width : 100 % ! important ;
height : 100 % ! important ;
min - width : 0 ;
min - height : 0 ;
z - index : 1 ;
transform : translate ( - 1.2 % , 1.6 % ) ;
transform : translate ( - 0.4 % , 0 .6% ) ;
}
. map - legend {