react实现鼠标悬停在SVG地图上某个区域时,其上方呈现柱形图

发布于:2025-04-10 ⋅ 阅读:(25) ⋅ 点赞:(0)

效果:

代码: 

import React, { useState } from 'react';

const NeimengMapWithCharts = () => {
  // 各城市的数据
  const cityData = {
    '呼和浩特市': [120, 90, 150, 80],
    '包头市': [90, 110, 130, 70],
    '乌海市': [60, 80, 100, 50],
    '赤峰市': [110, 95, 140, 85],
    '通辽市': [95, 105, 125, 75],
    '鄂尔多斯市': [130, 85, 160, 90],
    '巴彦淖尔市': [70, 100, 110, 60],
    '乌兰察布市': [85, 115, 135, 65],
    '兴安盟': [100, 90, 120, 80],
    '锡林郭勒盟': [115, 105, 145, 95],
    '阿拉善盟': [65, 75, 95, 55],
    '呼伦贝尔市': [140, 120, 170, 110]
  };

  const [hoveredCity, setHoveredCity] = useState(null);
  const [position, setPosition] = useState({ x: 0, y: 0 });

  const handleMouseEnter = (city, e) => {
    setHoveredCity(city);
    setPosition({
      x: e.clientX,
      y: e.clientY
    });
  };

  const handleMouseMove = (e) => {
    if (hoveredCity) {
      setPosition({
        x: e.clientX,
        y: e.clientY
      });
    }
  };

  const handleMouseLeave = () => {
    setHoveredCity(null);
  };

  // 计算柱形图的最大高度
  const maxValue = hoveredCity ? Math.max(...cityData[hoveredCity]) : 0;

  return (
    <div style={{ position: 'relative', width: '100%', height: '100%' }}>
      <svg
        viewBox="-122 -71 1463 856"
        style={{ width: '100%', height: 'auto' }}
        onMouseMove={handleMouseMove}
      >
        {/* 内蒙古自治区整体轮廓 */}
        <path
          d="M676 584L668 597L667 603L657 601L656 606L648 610L648 604L643 606L639 613L637 613L635 610L633 610L632 612L627 607L626 608L628 613L623 615L621 613L622 615L615 621L615 625L608 630L609 632L607 632L599 642L602 649L600 652L596 648L596 659L581 661L578 660L577 656L566 651L565 652L565 650L559 645L549 645L543 641L546 639L548 629L554 623L550 611L546 610L544 612L538 613L539 616L535 616L533 622L531 623L532 624L528 636L529 643L527 644L527 656L523 656L523 658L520 659L516 658L510 662L496 664L492 667L488 665L479 656L473 654L472 650L472 647L476 645L473 638L483 631L491 621L491 616L488 612L489 608L483 607L474 610L464 618L454 616L451 613L437 618L442 624L436 631L432 631L431 629L426 627L426 625L424 625L423 622L424 620L421 622L418 622L416 620L415 621L415 609L407 609L407 607L403 606L403 603L401 601L393 598L392 595L383 594L385 595L392 591L399 583L399 575L401 573L401 570L398 565L388 563L386 566L377 566L377 569L375 571L372 568L368 570L368 572L366 572L365 568L363 569L364 571L358 574L358 564L349 558L341 547L347 541L331 507L384 514L395 511L415 510L437 516L443 524L451 527L457 526L473 535L484 537L499 535L499 541L508 542L510 544L514 539L523 534L550 522L561 520L565 517L576 519L583 517L597 519L600 517L607 518L633 507L647 489L654 487L655 485L659 485L664 479L668 478L668 474L661 467L658 460L655 457L659 450L660 444L666 435L678 435L685 441L706 445L712 440L716 439L725 430L727 424L745 424L753 422L760 415L764 415L766 412L765 408L769 400L775 394L778 393L791 393L791 389L793 387L792 385L800 387L803 384L810 382L812 380L823 382L824 379L836 385L838 383L845 384L846 382L849 382L849 376L844 365L836 357L836 355L831 353L831 349L823 345L818 338L801 337L791 350L780 341L770 343L766 342L762 344L759 348L750 340L749 332L756 329L755 320L776 274L784 279L793 281L801 285L807 282L818 271L829 269L835 264L836 257L834 255L831 255L832 253L833 254L833 250L839 242L839 237L844 231L846 227L845 225L847 225L846 222L848 222L850 218L852 209L855 208L863 199L866 199L866 195L869 190L868 186L865 184L867 176L862 172L852 174L851 167L853 167L859 162L869 149L885 146L892 156L887 163L888 164L878 174L888 179L891 185L894 186L900 177L901 179L903 178L907 185L914 187L914 189L910 191L910 193L913 199L913 205L916 210L915 211L919 221L928 223L934 221L935 218L940 222L946 220L951 223L952 219L956 221L959 220L960 218L961 219L967 209L971 209L979 218L984 227L986 229L987 228L989 234L982 242L982 250L977 253L978 254L976 254L977 257L970 265L972 267L970 267L970 273L968 274L970 275L969 280L967 280L970 284L970 295L967 299L962 297L960 299L961 301L953 319L955 328L953 332L954 333L951 335L953 332L951 331L949 326L948 319L931 337L926 340L923 345L910 353L906 360L909 366L915 369L914 373L917 373L917 378L920 381L923 380L924 376L927 377L928 374L927 372L926 373L926 371L929 374L931 374L930 377L932 377L932 375L933 376L933 382L927 382L924 385L919 385L919 390L923 396L920 401L914 402L915 407L913 413L911 414L911 412L909 410L908 411L906 407L904 407L905 409L902 411L894 404L891 404L892 408L889 412L892 415L895 414L895 418L900 423L900 427L902 428L899 431L898 436L900 445L899 450L901 451L901 454L903 454L902 461L911 460L919 453L922 453L922 457L928 464L926 468L929 471L931 482L927 482L926 485L928 487L929 486L935 489L933 498L932 500L930 499L923 502L923 505L921 507L916 507L915 509L913 507L904 505L907 508L904 510L902 510L901 508L901 510L896 509L893 515L889 518L887 515L882 516L874 524L872 522L861 528L861 531L857 533L858 534L853 540L851 539L852 538L847 524L845 525L840 522L841 520L839 519L833 525L837 528L835 532L835 540L837 546L835 552L832 553L824 551L813 551L813 548L811 547L812 544L810 544L808 539L809 537L812 538L812 531L811 528L809 530L807 527L808 526L804 523L806 522L806 519L800 512L793 512L791 515L792 517L785 516L780 519L781 524L778 525L780 528L778 532L777 531L776 533L769 533L769 531L767 531L764 535L762 535L762 538L760 538L758 533L756 533L745 540L743 544L734 543L735 532L733 526L728 528L727 527L725 530L726 532L722 532L719 537L719 546L716 545L711 549L713 550L712 552L715 554L711 558L717 569L715 573L716 576L711 578L709 576L704 581L700 582L697 579L692 580L686 586L679 582L676 584zM949 262L950 255L952 255L952 249L944 248L941 250L942 253L940 255L938 252L937 255L941 262L942 260L948 260L948 262z"
          stroke="black"
          strokeWidth="2"
          fill="#fff"
          fillOpacity="0.2"
        />
        
        {/* 各城市区域 */}
        {Object.keys(cityData).map(city => (
          <path
            key={city}
            d={getPathData(city)}
            stroke="#333"
            strokeWidth="1"
            strokeDasharray="1,6"
            fill="#eee"
            fillOpacity="0.5"
            onMouseEnter={(e) => handleMouseEnter(city, e)}
            onMouseLeave={handleMouseLeave}
            style={{ cursor: 'pointer' }}
          />
        ))}
      </svg>

      {/* 悬停时显示的柱形图 */}
      {hoveredCity && (
        <div
          style={{
            position: 'fixed',
            left: `${position.x + 20}px`,
            top: `${position.y - 100}px`,
            backgroundColor: 'white',
            padding: '10px',
            borderRadius: '5px',
            boxShadow: '0 0 10px rgba(0,0,0,0.2)',
            zIndex: 1000,
            width: '200px',
            height: '150px',
            display: 'flex',
            justifyContent: 'space-around',
            alignItems: 'flex-end'
          }}
        >
          <div style={{ textAlign: 'center' }}>
            <div
              style={{
                height: `${(cityData[hoveredCity][0] / maxValue) * 100}px`,
                width: '30px',
                backgroundColor: '#4CAF50',
                margin: '0 5px'
              }}
            />
            <div>Q1</div>
          </div>
          <div style={{ textAlign: 'center' }}>
            <div
              style={{
                height: `${(cityData[hoveredCity][1] / maxValue) * 100}px`,
                width: '30px',
                backgroundColor: '#2196F3',
                margin: '0 5px'
              }}
            />
            <div>Q2</div>
          </div>
          <div style={{ textAlign: 'center' }}>
            <div
              style={{
                height: `${(cityData[hoveredCity][2] / maxValue) * 100}px`,
                width: '30px',
                backgroundColor: '#FFC107',
                margin: '0 5px'
              }}
            />
            <div>Q3</div>
          </div>
          <div style={{ textAlign: 'center' }}>
            <div
              style={{
                height: `${(cityData[hoveredCity][3] / maxValue) * 100}px`,
                width: '30px',
                backgroundColor: '#F44336',
                margin: '0 5px'
              }}
            />
            <div>Q4</div>
          </div>
          <div style={{ position: 'absolute', top: '-20px', left: '0', width: '100%', textAlign: 'center', fontWeight: 'bold' }}>
            {hoveredCity}
          </div>
        </div>
      )}
    </div>
  );
};

// 辅助函数:根据城市名称获取对应的SVG路径数据
function getPathData(city) {
  const pathDataMap = {
    '呼和浩特市': 'M647 583L654 588L656 593L654 600L666 603L668 597L676 584L674 581L675 580L670 575L670 572L672 570L671 569L673 567L663 552L658 551L651 554L642 550L636 551L639 560L637 562L638 564L640 564L639 567L641 569L641 573L648 580L647 582z',
    '包头市': 'M656 552L656 545L647 537L641 526L640 517L631 508L621 511L609 517L613 526L607 535L611 546L615 547L616 552L614 553L617 557L616 560L619 561L621 565L618 569L610 570L610 576L613 575L616 577L624 575L629 576L638 582L641 582L641 584L647 583L648 579L642 575L643 574L641 573L641 569L639 567L640 564L638 564L637 562L639 560L638 556L635 553L636 551L638 552L640 550L645 552L646 551L651 554L654 552z',
    '乌海市': 'M549 596L550 601L546 605L549 608L550 615L555 620L558 613L556 614L554 612L552 601L552 597L554 595L553 594L550 597L550 595z',
    '赤峰市': 'M871 523L864 514L859 501L859 498L868 487L860 488L864 487L873 480L866 468L868 465L865 461L861 460L851 444L836 429L836 434L833 432L833 437L831 437L833 439L829 441L832 444L826 446L828 448L827 452L820 455L819 454L814 459L811 458L807 466L803 465L800 468L798 468L798 466L793 461L787 462L782 468L782 476L784 477L778 481L778 485L774 484L768 493L769 497L775 504L773 513L778 513L780 515L780 518L785 516L792 517L793 512L800 512L806 519L807 522L804 523L808 526L808 530L811 528L812 530L812 538L808 538L810 544L812 544L811 547L813 548L814 552L822 552L824 550L825 552L834 552L837 547L835 541L835 532L837 528L834 525L834 523L839 520L841 520L840 522L843 524L847 524L847 528L850 532L852 540L864 526L870 523L871 524z',
    '通辽市': 'M871 523L872 522L874 524L882 516L887 515L889 518L896 509L901 510L901 508L902 510L904 510L907 508L904 506L906 505L913 507L915 509L916 507L918 508L924 505L923 503L925 500L931 500L933 498L935 489L933 489L930 486L928 487L926 484L927 482L929 483L929 481L931 482L929 474L930 473L926 468L928 464L922 457L922 453L919 453L913 457L912 460L900 461L891 455L883 444L883 442L874 437L873 431L866 427L862 422L854 418L851 418L851 420L849 421L849 419L846 419L841 416L835 422L834 427L843 434L845 439L853 446L861 460L863 460L866 463L866 468L873 480L864 487L860 488L868 487L859 497L861 508L868 520z',
    '鄂尔多斯市': 'M554 619L554 623L548 629L546 639L543 641L554 646L559 645L565 650L565 652L566 651L570 654L577 656L577 658L581 661L590 659L592 660L595 659L596 648L599 652L602 648L599 645L599 642L602 637L607 632L609 632L608 631L612 626L615 625L615 621L620 617L621 618L622 615L620 613L622 615L628 613L626 609L627 607L632 612L636 610L637 613L640 612L643 606L648 604L648 609L654 608L656 606L656 602L654 600L656 594L654 588L647 583L641 584L641 582L636 581L627 575L617 577L614 575L610 576L610 578L606 576L596 574L595 575L595 573L591 572L592 571L588 568L583 567L582 565L574 565L570 569L569 568L564 572L561 572L561 574L559 574L559 580L549 590L549 596L550 595L550 597L553 594L554 595L552 597L554 611L556 614L558 613L557 619L555 620z',
    '巴彦淖尔市': 'M552 586L559 580L559 574L560 575L561 572L564 572L569 568L570 569L572 567L571 566L582 565L592 571L591 572L600 576L604 575L606 577L610 577L611 569L618 569L621 565L619 561L616 560L617 557L614 553L616 550L615 547L610 545L608 539L609 538L607 535L613 526L609 517L601 517L597 519L590 517L576 519L566 517L562 518L561 520L550 522L523 534L514 541L514 549L517 555L518 562L527 568L538 571L539 574L543 575L543 577L538 575L537 576L540 581L543 582L544 580L551 580L548 584L552 586z',
    '乌兰察布市': 'M676 584L679 582L686 586L692 580L697 579L699 582L704 581L709 577L711 578L713 576L716 576L715 573L717 569L710 558L715 554L713 554L713 550L711 549L715 545L719 546L719 537L722 533L726 532L725 530L727 527L728 528L733 526L731 524L730 525L728 522L723 525L725 528L723 528L723 526L721 525L717 527L717 532L716 531L713 533L712 529L700 527L693 533L688 527L685 527L683 522L684 521L678 519L669 513L663 501L657 495L651 492L649 488L631 508L639 517L641 526L647 537L656 545L656 552L663 552L673 566L671 572L670 571L670 574L674 578L675 582z',
    '兴安盟': 'M902 461L903 454L901 454L899 450L900 444L897 440L899 432L902 428L900 427L900 423L896 420L895 414L892 415L888 412L891 411L891 404L893 404L902 411L904 407L906 407L908 411L909 410L911 414L913 414L913 410L915 407L914 402L920 401L923 396L919 390L919 385L924 385L927 382L933 382L933 376L932 375L932 377L930 377L931 374L929 374L926 371L926 373L928 373L927 377L924 376L923 380L920 381L917 378L917 373L914 372L916 369L910 367L906 360L898 365L892 362L889 363L887 366L883 365L882 367L879 368L876 366L873 368L865 363L867 358L863 353L861 353L857 349L851 353L850 352L845 357L839 360L844 365L849 375L850 384L850 391L847 392L848 400L846 410L843 415L841 415L846 419L847 418L849 421L851 421L851 419L854 418L859 420L863 423L863 425L873 431L872 433L874 437L883 442L883 444L892 456L894 456L900 461L901 460z',
    '锡林郭勒盟': 'M733 526L736 536L734 537L734 543L742 544L745 543L744 540L756 533L758 533L760 538L762 538L762 536L767 531L769 531L769 533L776 533L780 530L778 525L781 524L780 516L774 513L775 504L769 497L768 493L774 484L778 485L778 482L784 477L782 476L782 469L785 463L793 461L797 464L797 467L800 468L803 465L807 466L811 458L814 459L819 454L820 455L827 452L828 448L826 446L832 444L830 439L833 440L831 434L833 432L835 434L836 432L836 429L834 427L835 422L841 417L841 415L844 414L846 410L848 400L847 392L850 391L849 383L846 382L846 384L843 385L838 383L836 385L824 379L823 381L818 382L812 380L806 384L803 384L801 387L792 385L793 387L791 389L791 393L778 392L777 394L773 395L766 405L766 412L764 415L760 415L753 422L745 424L727 424L725 430L716 439L712 440L706 445L685 441L679 435L670 434L666 435L663 438L658 453L655 457L658 460L661 467L668 474L668 477L664 479L659 485L650 488L651 492L657 495L663 501L669 512L678 519L684 521L683 522L685 527L687 527L693 533L695 533L700 527L708 527L709 529L712 529L713 533L716 532L716 527L719 527L721 525L723 526L723 528L725 528L725 526L723 525L727 522L730 523L730 525L732 525z',
    '阿拉善盟': 'M515 539L510 544L508 542L499 541L499 535L489 537L473 535L457 526L451 527L443 524L437 516L415 510L395 511L384 514L331 507L347 541L341 547L349 558L358 564L358 574L364 571L363 569L365 568L368 573L368 570L372 568L374 571L376 570L377 566L386 566L388 563L397 564L401 570L401 573L399 575L399 583L396 585L393 591L390 591L385 595L383 594L392 595L393 598L401 601L403 603L403 606L407 609L415 609L414 619L421 622L424 620L423 622L426 625L425 627L431 629L432 631L436 631L443 624L437 618L451 613L454 616L463 618L474 610L483 607L489 608L488 612L491 616L490 623L483 631L473 638L476 645L472 647L472 650L473 654L478 656L491 667L506 662L510 662L516 658L523 659L523 656L527 656L527 644L529 643L528 636L532 624L531 623L533 622L535 616L539 616L538 613L544 613L549 608L546 606L550 602L548 594L552 586L548 584L551 581L540 581L537 577L543 577L543 575L538 571L525 567L518 562L517 555L514 549L514 541z',
    '呼伦贝尔市': 'M906 360L898 365L892 362L889 363L887 366L883 365L882 367L879 368L876 366L873 368L865 363L867 358L863 353L861 353L857 349L851 353L848 353L845 357L839 360L836 357L836 355L831 353L831 349L823 345L818 338L813 337L801 337L791 350L780 341L770 343L766 342L762 344L759 348L750 340L749 332L756 329L755 320L776 274L784 279L793 281L801 285L807 282L818 271L829 269L835 264L836 257L834 255L831 255L832 253L833 254L833 250L839 242L839 237L844 231L846 227L845 225L847 225L846 222L848 222L850 218L852 209L855 208L863 199L866 199L866 195L869 190L868 186L865 184L867 176L862 172L852 174L851 167L853 167L859 162L869 149L876 147L879 148L881 146L885 146L892 156L887 163L888 164L878 174L888 179L891 185L894 186L900 177L901 179L903 178L907 185L914 187L914 189L910 191L910 193L913 199L913 205L916 210L915 211L919 221L928 223L934 221L935 218L940 222L946 220L951 223L952 219L956 221L959 220L960 218L961 219L967 209L971 209L979 218L984 227L986 229L987 228L989 234L982 242L982 250L977 253L978 254L976 254L977 257L970 265L972 267L970 267L970 273L968 274L970 275L969 280L967 280L970 284L970 295L967 299L962 297L960 299L961 301L953 319L955 328L953 332L954 333L951 335L953 332L951 331L949 326L948 319L931 337L926 340L923 345L910 353L908 358zM949 262L950 255L952 255L952 249L944 248L941 250L942 253L940 255L938 252L937 255L941 262L942 260L948 260L948 262z'
  };
  
  return pathDataMap[city] || '';
}

export default NeimengMapWithCharts;


网站公告

今日签到

点亮在社区的每一天
去签到