首先需要写一个组件:
import React, { useState, useEffect, useRef } from 'react';
import ChinaMap from 'moment';
import * as d3 from 'd3';
import chinaGeoJson from 'china-geojson/src/geojson/china.json';const MyMapToShowResult = ({ realData }) => {const [data, setData] = useState({});const [loading, setLoading] = useState(true);const svgRef = useRef(null);const [hoveredProvince, setHoveredProvince] = useState(null);useEffect(() => {const backgroundColor = 'blue';const svg = d3.select(svgRef.current);svg.style('background-color', backgroundColor);let isMounted = true;const width = 780;const height = 580;const projection = d3.geoMercator().center([105, 38]).scale(600).translate([width / 2, height / 2]);const path = d3.geoPath().projection(projection);const features = JSON.parse(JSON.stringify(chinaGeoJson.features));//const realData = [// { province: '北京', emission: 500 },// { province: '上海', emission: 200 },// { province: '台湾', emission: 400 },// { province: '青海', emission: 200 },// { province: '辽宁', emission: 300 },// { province: '黑龙江', emission: 100 },//];features.forEach((feature, i) => {// 在 realData 中查找对应省份的数据const provinceData = realData.find(data => data.province === feature.properties.name);// 如果找到对应省份的数据,则将真实的数量赋给 emission 属性if (provinceData) {feature.properties.emission = provinceData.emission;} else {feature.properties.emission = 0;}});console.log('== 省份数据:', features);svg.selectAll('*').remove();svg.append('g').attr('transform', `translate(${width / 2},${height / 2})`).call(projection);svg.selectAll('path').data(features).join('path').attr('d', path).transition().attr('fill-opacity', 0.8).style('stroke', 'black').style('stroke-width', '1px').attr('data-tip', (d, i) => { return d.properties.name + " : " + d.properties.emission; }).attr('fill', (d, i) => {const colorScale = d3.scaleSequential().interpolator(d3.interpolateRgb('#ffffff', '#008000')).domain([0, d3.max(features, d => d.properties.emission)]);return colorScale(d.properties.emission);});// 创建比色卡const legendWidth = 200;const legendHeight = 20;const legendPadding = 10;const legend = svg.append('g').attr('transform', `translate(${width - legendWidth - legendPadding},${height - legendHeight - legendPadding})`);const colorScale = d3.scaleSequential().interpolator(d3.interpolateRgb('#ffffff', '#008000')).domain([0, d3.max(features, d => d.properties.emission)]);console.log('== 比色卡前,省份数据:', features);const legendXScale = d3.scaleLinear().domain([0, d3.max(features, d => d.properties.emission)]).range([0, legendWidth]);// 根据需要设置刻度数量const legendXAxis = d3.axisBottom(legendXScale).ticks(5);legend.append('g').attr('class', 'legend-axis').attr('transform', `translate(0, ${legendHeight})`).call(legendXAxis);const legendGradient = legend.append('linearGradient').attr('id', 'legend-gradient').attr('gradientUnits', 'userSpaceOnUse').attr('x1', 0).attr('x2', legendWidth).selectAll('stop').data(colorScale.ticks().map((t, i, n) => ({offset: `${100 * i / n.length}%`,color: colorScale(t)}))).join('stop').attr('offset', d => d.offset).attr('stop-color', d => d.color);legend.append('rect').attr('x', 0).attr('y', -legendHeight / 2).attr('width', legendWidth).attr('height', legendHeight).style('fill', 'url(#legend-gradient)');}, [data]);return (<div><svg ref={svgRef} width="800" height="600"></svg><div id="tooltip" style={{ display: 'none', position: 'absolute', backgroundColor: 'white', padding: '5px', borderRadius: '5px', boxShadow: '0 2px 5px rgba(0, 0, 0, 0.3)', zIndex: '999' }}></div>{hoveredProvince && (<div id="tooltip" style={{ display: 'block', position: 'absolute', backgroundColor: 'white', padding: '5px', borderRadius: '5px', boxShadow: '0 2px 5px rgba(0, 0, 0, 0.3)', zIndex: '999', left: '10px', top: '10px' }}>{hoveredProvince}</div>)}</div>);
};export default MyMapToShowResult;
然后在页面进行引用,并且传递数据给组件:
引入:
import MyMapToShowResult from "@/compontens/MyMapToShowResult";
渲染:(注意需要把realData声明赋值)
<MyMapToShowResult realData={realData}/
在循环中使用:
{data.map((item, index) => (<div key={index}><p>map{index}</p><MyMapToShowResult realData={realData}/></div>
))}