|
1 | 1 | import React, { useEffect, useRef, useState } from 'react' |
2 | 2 | import { Button, message } from 'antd' |
3 | | -import { ZoomInOutlined, ZoomOutOutlined, SyncOutlined, DownloadOutlined } from '@ant-design/icons' |
| 3 | +import { |
| 4 | + ZoomInOutlined, |
| 5 | + ZoomOutOutlined, |
| 6 | + SyncOutlined, |
| 7 | + DownloadOutlined, |
| 8 | + FullscreenOutlined, |
| 9 | + FullscreenExitOutlined, |
| 10 | +} from '@ant-design/icons' |
4 | 11 |
|
5 | 12 | const defaultBg = '#1e1e1e' |
6 | 13 |
|
@@ -249,6 +256,98 @@ function SvgPreview({ |
249 | 256 | } |
250 | 257 | } |
251 | 258 |
|
| 259 | + // fullscreen handling |
| 260 | + const [isFullscreen, setIsFullscreen] = useState(false) |
| 261 | + |
| 262 | + useEffect(() => { |
| 263 | + const onFsChange = () => { |
| 264 | + try { |
| 265 | + const isFs = !!(document.fullscreenElement || document.webkitFullscreenElement || document.msFullscreenElement) |
| 266 | + // temporarily disable transform transitions to avoid layout/paint thrash when entering/exiting fullscreen |
| 267 | + try { |
| 268 | + const el = innerRef.current |
| 269 | + if (el) { |
| 270 | + const prev = el.style.transition |
| 271 | + el.style.transition = 'none' |
| 272 | + requestAnimationFrame(() => { |
| 273 | + // restore after frame to allow browser to finish fullscreen layout |
| 274 | + el.style.transition = prev || '' |
| 275 | + }) |
| 276 | + } |
| 277 | + } catch (e) { |
| 278 | + console.log('error', e.message) |
| 279 | + } |
| 280 | + setIsFullscreen(isFs) |
| 281 | + } catch (e) { |
| 282 | + console.log('error', e.message) |
| 283 | + } |
| 284 | + } |
| 285 | + document.addEventListener('fullscreenchange', onFsChange) |
| 286 | + document.addEventListener('webkitfullscreenchange', onFsChange) |
| 287 | + document.addEventListener('mozfullscreenchange', onFsChange) |
| 288 | + document.addEventListener('MSFullscreenChange', onFsChange) |
| 289 | + return () => { |
| 290 | + document.removeEventListener('fullscreenchange', onFsChange) |
| 291 | + document.removeEventListener('webkitfullscreenchange', onFsChange) |
| 292 | + document.removeEventListener('mozfullscreenchange', onFsChange) |
| 293 | + document.removeEventListener('MSFullscreenChange', onFsChange) |
| 294 | + } |
| 295 | + }, []) |
| 296 | + |
| 297 | + const enterFullscreen = async (el) => { |
| 298 | + if (!el) return |
| 299 | + const req = el.requestFullscreen || el.webkitRequestFullscreen || el.mozRequestFullScreen || el.msRequestFullscreen |
| 300 | + if (req) { |
| 301 | + try { |
| 302 | + await req.call(el) |
| 303 | + } catch (e) { |
| 304 | + console.log('error', e.message) |
| 305 | + } |
| 306 | + } |
| 307 | + } |
| 308 | + |
| 309 | + const exitFullscreen = async () => { |
| 310 | + const exit = |
| 311 | + document.exitFullscreen || |
| 312 | + document.webkitExitFullscreen || |
| 313 | + document.mozCancelFullScreen || |
| 314 | + document.msExitFullscreen |
| 315 | + if (exit) { |
| 316 | + try { |
| 317 | + await exit.call(document) |
| 318 | + } catch (e) { |
| 319 | + console.log('error', e.message) |
| 320 | + } |
| 321 | + } |
| 322 | + } |
| 323 | + |
| 324 | + const toggleFullscreen = async () => { |
| 325 | + try { |
| 326 | + const el = innerRef.current |
| 327 | + if (el) { |
| 328 | + const prev = el.style.transition |
| 329 | + el.style.transition = 'none' |
| 330 | + if (!isFullscreen) { |
| 331 | + await enterFullscreen(containerRef.current || document.documentElement) |
| 332 | + } else { |
| 333 | + await exitFullscreen() |
| 334 | + } |
| 335 | + requestAnimationFrame(() => { |
| 336 | + el.style.transition = prev || '' |
| 337 | + }) |
| 338 | + return |
| 339 | + } |
| 340 | + } catch (e) { |
| 341 | + console.log('error', e.message) |
| 342 | + } |
| 343 | + |
| 344 | + if (!isFullscreen) { |
| 345 | + await enterFullscreen(containerRef.current || document.documentElement) |
| 346 | + } else { |
| 347 | + await exitFullscreen() |
| 348 | + } |
| 349 | + } |
| 350 | + |
252 | 351 | return ( |
253 | 352 | <div style={{ height: '100%', position: 'relative' }}> |
254 | 353 | <div |
@@ -304,6 +403,12 @@ function SvgPreview({ |
304 | 403 | </div> |
305 | 404 | <Button icon={<ZoomInOutlined />} onClick={handleZoomIn} type="text" style={{ color: '#fff' }} /> |
306 | 405 | <Button icon={<SyncOutlined />} onClick={handleReset} type="text" style={{ color: '#fff' }} /> |
| 406 | + <Button |
| 407 | + icon={isFullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />} |
| 408 | + onClick={toggleFullscreen} |
| 409 | + type="text" |
| 410 | + style={{ color: '#fff' }} |
| 411 | + /> |
307 | 412 | <Button icon={<DownloadOutlined />} onClick={handleDownload} type="primary" size="small"> |
308 | 413 | 下载 |
309 | 414 | </Button> |
|
0 commit comments