介绍
- 本文以
react
来举例,其他的框架大差不差。 - 功能介绍:
(1)给定一张图片,在这个图片上有小车或其他动态点位需要以固定线路移动。
(2)echarts默认支持SVG图片格式
或JSON地图格式
。本文会转译其他图片为svg(目前仅仅简单转译,如果有其他好的方法直接替换就行了),然后支持echarts调用。
实现
- @/components/ImgLine/index.ts组件代码
import { useEffect, useState } from 'react'
import * as echarts from 'echarts/core';
import {
TooltipComponent,
TooltipComponentOption,
GeoComponent,
GeoComponentOption
} from 'echarts/components';
import { LinesChart, LinesSeriesOption } from 'echarts/charts';
import { CanvasRenderer } from 'echarts/renderers';
import { svgFn, getBase64 } from './utils/index';
echarts.use([TooltipComponent, GeoComponent, LinesChart, CanvasRenderer]);
type EChartsOption = echarts.ComposeOption<
TooltipComponentOption | GeoComponentOption | LinesSeriesOption
>;
let option: EChartsOption;
const ImgLine = () => {
const [myChart, setMyChart] = useState<any>(null)
const renderFn = () => {
let chartDom = document.getElementById('main')!;
let myChart = echarts.init(chartDom);
getBase64('http://localhost:8081/images/public_bg.png').then((config: any) => {
echarts.registerMap('ksia-ext-plan', { svg: svgFn(config) });
option = {
tooltip: {},
geo: {
map: 'ksia-ext-plan',
roam: true,
layoutCenter: ['50%', '50%'],
layoutSize: '100%'
},
series: [
{
name: 'Route',
type: 'lines',
coordinateSystem: 'geo',
geoIndex: 0,
emphasis: {
label: {
show: false
}
},
polyline: true,
lineStyle: {
color: '#c46e54',
width: 0
},
effect: {
show: true,
period: 8,
color: '#a10000',
trailLength: 0,
symbolSize: [12, 30],
symbol:
'path://M87.1667 3.8333L80.5.5h-60l-6.6667 3.3333L.5 70.5v130l10 10h80l10 -10v-130zM15.5 190.5l15 -20h40l15 20zm75 -65l-15 5v35l15 15zm-80 0l15 5v35l-15 15zm65 0l15 -5v-40l-15 20zm-50 0l-15 -5v-40l15 20zm 65,-55 -15,25 c -15,-5 -35,-5 -50,0 l -15,-25 c 25,-15 55,-15 80,0 z'
},
z: 100,
data: [
{
effect: {
color: '#fff',
constantSpeed: 100,
delay: 0
},
coords: [
[50.875133928571415, 242.66287667410717],
[62.03696428571425, 264.482421875],
[72.63357421874997, 273.62779017857144],
[92.78291852678569, 285.869140625],
[113.43637834821425, 287.21854073660717],
[141.44788783482142, 288.92947823660717],
[191.71686104910714, 289.5507114955357],
[198.3060072544643, 294.0673828125],
[204.99699497767858, 304.60288783482144],
[210.79177734375003, 316.7373046875],
[212.45179408482142, 329.3656529017857],
[210.8885267857143, 443.3925083705358],
[215.35936941964286, 453.00634765625],
[224.38761997767858, 452.15087890625],
[265.71490792410714, 452.20179966517856],
[493.3408844866072, 453.77525111607144],
[572.8892940848216, 448.77992466517856],
[608.9513755580358, 448.43366350446433],
[619.99099609375, 450.8778599330358],
[624.2479715401787, 456.2194475446429],
[628.1434095982145, 463.9899553571429],
[629.8492550223216, 476.0276227678571],
[631.2750362723216, 535.7322126116071],
[624.6757059151787, 546.6496233258929],
[617.1801702008929, 552.6480887276786],
[603.7269056919645, 554.5066964285714],
[588.0178515625, 557.5517578125],
[529.4386104910716, 556.2991071428571],
[422.1994921875001, 551.38525390625],
[291.66921875, 552.5767996651786],
[219.4279380580357, 547.4949079241071],
[209.53912667410714, 541.5931919642858],
[206.70793247767858, 526.1947544642858],
[206.70793247767858, 507.4049944196429],
[206.12234375000003, 468.7663225446429],
[204.48778738839286, 459.44782366071433],
[197.56256417410714, 452.8943219866071],
[170.31995814732142, 456.27546037946433],
[1.8078906249999704, 460.5935407366071]
]
},
{
effect: {
color: '#f60',
constantSpeed: 100,
delay: 0
},
coords: [
[1920.1, 287.98756],
[689.1, 291.0477],
[301.16, 290.49717],
[229.12, 291.73856],
[220.13, 297.4043],
[214.13, 308.52144],
[213.13, 421.35],
[213.18, 443.0571],
[222.16, 455.95433],
[271.15, 454.37856],
[359.16, 455.9358],
[580.1, 448.11233],
[627.1, 460.7469],
[632.1, 536.6388],
[628.1, 548.4776],
[612.1, 556.8234],
[543.1, 555.4743],
[429.1, 551.9404],
[293.16, 551.2158],
[226.15, 556.0686],
[215.14, 562.7229],
[213.14, 591.6058],
[212.16, 625.6729],
[197.16, 645.0786],
[187.16, 647.0871],
[101.16, 649.029],
[69.91, 650.161],
[56.41, 656.826],
[51.11, 1080.254]
]
},
{
effect: {
color: '#ff0',
constantSpeed: 60,
delay: 0
},
coords: [
[2.5920703124999704, 450.66908482142856],
[204.0651450892857, 453.13364955357144],
[378.72844029017864, 453.13874162946433],
[551.1817745535716, 456.1532505580358],
[578.3734598214287, 456.91196986607144],
[601.2317885044645, 458.9895368303571],
[614.1503850446429, 462.1669921875],
[618.99294921875, 479.68882533482144],
[620.0826534598216, 513.5969587053571],
[615.6932840401787, 528.7306082589286],
[608.4829045758929, 533.2625558035714],
[592.7127455357145, 534.9582170758929],
[583.09890625, 527.5492466517858],
[578.6535239955358, 516.4077845982143],
[578.6535239955358, 498.36146763392856],
[577.9966462053571, 477.0613141741071],
[575.3691350446429, 469.1940569196429],
[569.0753292410716, 462.63037109375],
[553.9518638392858, 460.6444614955358],
[298.10051060267864, 465.61432756696433],
[193.49908761160714, 460.1759905133929],
[116.40505859374997, 465.78236607142856],
[3.5137360491071092, 463.47565569196433]
]
}
]
}
]
};
myChart.setOption(option);
setMyChart(myChart)
})
}
useEffect(() => {
renderFn();
}, [])
return <div>
<div id='main' style={{ width: '500px', height: '500px' }}></div>
</div>
}
export default ImgLine
- @/components/ImgLine/utils/index.ts
export const svgFn = ({ src, width, height }: any) => `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="${width}px" height="${height}px" viewBox="0 0 ${width} ${height}" enable-background="new 0 0 ${width} ${height}" xml:space="preserve"> <image id="image0" width="${width}" height="${height}" x="0" y="0"
href="${src}" />
</svg>
`
export const getBase64: any = (imgUrl: any) => new Promise((resolve) => {
const xhr: any = new XMLHttpRequest();
xhr.open("get", imgUrl, true);
xhr.responseType = "blob";
xhr.onload = function () {
if (this.status !== 200) return;
const blob: any = this.response;
console.log("blob", blob)
const fileReader = new FileReader();
fileReader.onloadend = function (e: any) {
const base64 = e.target.result;
console.log("base64:", base64)
const img = new Image();
img.src = base64;
img.onload = () => resolve({ src: base64, width: img.width, height: img.height })
};
fileReader.readAsDataURL(blob);
}
xhr.send();
})
使用
- 调用代码
import styles from './index.less';
import ImgLine from '@/components/ImgLine';
const HomePage = () => {
return (
<div className={styles.container}>
<div style={{ width: '1000px', height: '400px' }}>
<ImgLine />
</div >
</div>
);
};
export default HomePage;
- 效果介绍
(1)路线本文是使用的1080 x 1920 路线(像素)
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/c51c32ff047845cd8ee6b54d560bbed2.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/1a0da94aafade8d0f53d26783d636883.png)
参考资料
- echarts示例