引入geo数据

地图JSON数据来源:

在tsconfig.json中添加配置,允许TS中导入json文件

  1. "resolveJsonModule": true,

显示地图及Tooltip轮播

image.png

  1. import React, { useRef, useEffect, useState } from 'react'
  2. import XHData from '../geo/geoData.json'
  3. import * as echarts from 'echarts'
  4. import { createEchartsOptions } from '../shared/create-echart-options'
  5. export const Chart6 = () => {
  6. const divRef = useRef(null)
  7. useEffect(() => {
  8. let index = -1
  9. const myChart = echarts.init(divRef.current)
  10. // myChart.hideLoading()
  11. // @ts-ignore
  12. echarts.registerMap('XH', XHData)
  13. let mTime = null
  14. // 实现ToolTip高亮轮播
  15. function mapActive() {
  16. const dataLength = XHData.features.length
  17. // 用定时器控制高亮
  18. mTime = setInterval(() => {
  19. // 清除之前的高亮
  20. myChart.dispatchAction({
  21. type: 'downplay',
  22. seriesIndex: 0,
  23. dataIndex: index,
  24. })
  25. index++
  26. // 当前下标高亮
  27. myChart.dispatchAction({
  28. type: 'highlight',
  29. seriesIndex: 0,
  30. dataIndex: index,
  31. })
  32. myChart.dispatchAction({
  33. type: 'showTip',
  34. seriesIndex: 0,
  35. dataIndex: index,
  36. })
  37. if (index > dataLength) {
  38. index = 0
  39. }
  40. }, 2000)
  41. }
  42. mapActive()
  43. myChart.on('mouseover', () => {
  44. // 停止定时器,清除之前的高亮
  45. console.log('mouseover')
  46. clearInterval(mTime)
  47. mTime = null
  48. myChart.dispatchAction({
  49. type: 'downplay',
  50. seriesIndex: 0,
  51. dataIndex: index,
  52. })
  53. })
  54. // 鼠标划出重新定时器开始
  55. myChart.on('mouseout', () => {
  56. mapActive()
  57. })
  58. const option = {
  59. xAxis: { show: false },
  60. yAxis: { show: false },
  61. tooltip: {
  62. trigger: 'item',
  63. backgroundColor: 'rgba(0,0,0,0)',
  64. },
  65. visualMap: {
  66. show: false,
  67. min: 800,
  68. max: 50000,
  69. text: ['High', 'Low'],
  70. realtime: false,
  71. calculable: true,
  72. inRange: {
  73. color: ['lightskyblue', 'yellow', 'orangered'],
  74. },
  75. },
  76. series: [
  77. {
  78. tooltip: {
  79. trigger: 'item',
  80. // 自定义tooltip样式
  81. formatter: function (item) {
  82. var tipHtml = ''
  83. tipHtml = `<div style="padding: .6rem .8rem;font-size: .325rem;color:#fff;border-radius:4px;
  84. background-size: .08rem .3rem, .3rem .08rem;background-color:rgba(6, 79, 111,.6);">${item.data.name} <span style="color:#f9eb59;font-size:.4rem">${item.data.value}</span> </div>`
  85. return tipHtml
  86. },
  87. // borderWidth: 0,
  88. },
  89. label: { show: false },
  90. data: [],
  91. name: '西虹市地图',
  92. type: 'map',
  93. mapType: 'XH', // 自定义扩展图表类型
  94. aspectScale: 1,
  95. layoutCenter: ['49%', '47%'], //地图位置
  96. layoutSize: '90%', // 缩放比例
  97. itemStyle: {
  98. color: 'transparent', // 去除坐标小圆点
  99. emphasis: {
  100. label: {
  101. show: true,
  102. },
  103. },
  104. },
  105. },
  106. ],
  107. }
  108. option.series[0].data = XHData.features.map((item) => {
  109. // 显示窗口的数据转换
  110. return {
  111. value: (Math.random() * 5000).toFixed(0),
  112. name: item.properties.name,
  113. }
  114. })
  115. myChart.setOption(createEchartsOptions(option))
  116. return () => clearInterval(mTime)
  117. }, [])
  118. return (
  119. <div className="bordered 籍贯">
  120. <h2>全市案件侦破实时记录</h2>
  121. <div ref={divRef} className="chart" />
  122. </div>
  123. )
  124. }

参考文档

监控扫描动画

image.png

  1. <div className="scan-animation">
  2. <div className="ring">
  3. <div className="radar" />
  4. </div>
  5. <span>数据实时监控中</span>
  6. </div>
  1. > .scan-animation {
  2. position: absolute;
  3. bottom: px(20);
  4. left: px(24);
  5. display: flex;
  6. align-items: center;
  7. flex-direction: column;
  8. gap: px(10);
  9. > span {
  10. font-size: px(4);
  11. color: #a1d1f1;
  12. }
  13. > .ring {
  14. border: 1px solid #0c2939;
  15. width: px(96);
  16. height: px(96);
  17. border-bottom: none;
  18. border-radius: 50%;
  19. overflow: hidden;
  20. animation: spin infinite 5s linear;
  21. > .radar {
  22. border: 2px solid #103142;
  23. position: absolute;
  24. width: px(81);
  25. height: px(81);
  26. top: 50%;
  27. left: 50%;
  28. transform: translate(-50%, -50%);
  29. border-radius: 50%;
  30. &::before {
  31. content: '';
  32. position: absolute;
  33. top: 50%;
  34. left: 50%;
  35. transform: translate(-50%, -50%);
  36. width: px(42);
  37. height: px(42);
  38. border: 2px solid #082132;
  39. border-radius: 50%;
  40. }
  41. &::after {
  42. content: '';
  43. position: absolute;
  44. top: 0;
  45. left: 50%;
  46. transform: translateX(-50%);
  47. width: px(3);
  48. height: px(36);
  49. z-index: 1;
  50. background: #007cc0;
  51. border-radius: 50%;
  52. box-shadow: 0 0 5px 1px #0094e4, -3px -10px 5px 1px #0094e4,
  53. -7px -15px 10px 1px #0094e4, -3px -3px 10px 1px #0094e4,
  54. -7px -7px 20px 1px #0094e4, -11px -11px 30px 1px #0094e4,
  55. -11px -11px 40px 1px #0094e4, -11px -11px 30px 1px #0094e4,
  56. -11px -11px 30px 1px #0094e4;
  57. }
  58. }
  59. }
  60. @keyframes spin {
  61. from {
  62. transform: rotate(0);
  63. }
  64. to {
  65. transform: rotate(360deg);
  66. }
  67. }
  68. }
  69. }

显示访问数量

  • 重点是要在 useEffect 中返回清除函数,清除掉上一个 setInterval, 否则每次重新渲染都会新增一个 setInterval
  • 使用 number.toLocaleString() 将数字格式化,每三位显示一个逗号,也可以使用 toLocaleString('en-US')

image.png

  1. import React, { useRef, useEffect, useState } from 'react'
  2. export const Chart6 = () => {
  3. const [count, setCount] = useState(325920)
  4. useEffect(() => {
  5. const timer = setInterval(() => {
  6. setCount(count + 1)
  7. }, 500)
  8. return () => {
  9. clearInterval(timer)
  10. }
  11. }, [count])
  12. return (
  13. <div className="bordered note">
  14. <span>{count.toLocaleString()}</span>
  15. <span>接待访客</span>
  16. </div>
  17. )
  18. }

[

](https://gitee.com/vergil_lu/bid-data-project/blob/27d67f0db578ea23d40457517533568f42aa10e1/src/views/LU-DA-PING/components/map/index.vue)