index.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import { AimOutlined, CompressOutlined, ExpandOutlined, MinusOutlined, PlusOutlined, QuestionCircleFilled } from "@ant-design/icons";
  2. import { Button, ConfigProvider, Divider, Slider, Tooltip } from "antd";
  3. import React, { useEffect, useRef, useState } from "react";
  4. import { useFullscreen } from "ahooks";
  5. import { useModel } from "umi";
  6. import { MiniMap } from '@antv/x6-plugin-minimap';
  7. import insertCss from 'insert-css';
  8. insertCss(`
  9. .navigation-view {
  10. position: absolute;
  11. bottom: 32px;
  12. right: 32px;
  13. width: 330px;
  14. height: 210px;
  15. background-color: #fff;
  16. border: 1px solid #e9edf2;
  17. border-radius: 8px 8px 0 0;
  18. overflow: hidden;
  19. z-index: 1;
  20. box-shadow: 0 4px 10px 1px rgba(0, 0, 0, .1);
  21. }`);
  22. export default function Footer() {
  23. const [isFullscreen, { toggleFullscreen }] = useFullscreen(document.body);
  24. const navigationViewRef = useRef(null);
  25. const { graph, selectedCell } = useModel("flowchartModel");
  26. const [showNavigation, setShowNavigation] = useState(false);
  27. const [countCell, setCountCell] = useState(0);
  28. const [scale, setScale] = useState(100);
  29. useEffect(() => {
  30. if(!graph || !navigationViewRef.current) return;
  31. graph.use(
  32. new MiniMap({
  33. container: navigationViewRef.current,
  34. width: 330,
  35. height: 210,
  36. padding: 10,
  37. }),
  38. )
  39. }, [graph, navigationViewRef.current]);
  40. useEffect(() => {
  41. graph?.on('cell:change:*', () => {
  42. const count = graph?.getCells().length || 0;
  43. setCountCell(count > 0 ? count - 1 : 0)
  44. });
  45. graph?.on('scale', (scaleInfo) => {
  46. setScale(parseInt(scaleInfo.sx * 100 + ''));
  47. })
  48. }, [graph]);
  49. const handleZoom = (value: number) => {
  50. graph?.zoomTo(value / 100)
  51. }
  52. const handleZoomFit = () => {
  53. graph?.zoomToFit({ })
  54. }
  55. const handleOnChange = (value: number) => {
  56. setScale(Math.round(value));
  57. handleZoom(value)
  58. }
  59. return (
  60. <ConfigProvider componentSize="small">
  61. <div className="h-24px bg-white flex justify-between items-center px-16px relative">
  62. <div className="footer-left"></div>
  63. <div className="footer-right flex items-center">
  64. <div>图形:{selectedCell?.length}/{countCell}</div>
  65. <Divider type="vertical" />
  66. {/* <Tooltip title="模板">
  67. <Button type="text" icon={<i className="iconfont icon-buju" />} />
  68. </Tooltip> */}
  69. <Tooltip title="聚焦">
  70. {/* <Button type="text" icon={<i className="iconfont icon-buju" />} /> */}
  71. <Button type="text" icon={<AimOutlined />} onClick={handleZoomFit}/>
  72. </Tooltip>
  73. <Tooltip title={showNavigation ? "关闭视图导航" : "显示视图导航"}>
  74. <Button type="text" icon={<i className="iconfont icon-map" />} onClick={() => setShowNavigation(!showNavigation)}/>
  75. </Tooltip>
  76. <div className="navigation-view" style={{display: showNavigation ? 'block' : 'none'}} ref={navigationViewRef}></div>
  77. <Button type="text" icon={<MinusOutlined/>} onClick={() => handleZoom( scale - 2)}/>
  78. <Slider min={20} max={200} className="w-120px m-0 mx-8px" tooltip={{formatter: (val) => `${val}%`}} value={scale} onChange={handleOnChange}/>
  79. <Button type="text" icon={<PlusOutlined/>} onClick={() => handleZoom( scale + 2)}/>
  80. <Tooltip title="重置缩放">
  81. <div className="cursor-pointer mx-8px w-40px" onClick={handleZoomFit}>{scale}%</div>
  82. </Tooltip>
  83. {
  84. isFullscreen
  85. ? <Button type="text" icon={<CompressOutlined/>} onClick={toggleFullscreen}/>
  86. : <Button type="text" icon={<ExpandOutlined/>} onClick={toggleFullscreen}/>
  87. }
  88. <Divider type="vertical" />
  89. <Button type="text" icon={<QuestionCircleFilled/>} />
  90. </div>
  91. </div>
  92. </ConfigProvider>
  93. );
  94. }