1. 程式人生 > 實用技巧 >[OHIF-Viewers]醫療數字閱片-醫學影像-ViewportDownloadForm.js

[OHIF-Viewers]醫療數字閱片-醫學影像-ViewportDownloadForm.js

ViewportDownloadForm.js

原始碼還是得一行一行閱讀,好多自定義的函式,得找到相應的用法

import React, {
  useRef,
  useCallback,
  useEffect,
  useState,
  createRef,
} from 'react';
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';

import './ViewportDownloadForm.styl';
import { TextInput, Select, Icon } 
from '@ohif/ui'; import classnames from 'classnames'; const FILE_TYPE_OPTIONS = [ { key: 'jpg', value: 'jpg', }, { key: 'png', value: 'png', }, ]; const DEFAULT_FILENAME = 'image'; const REFRESH_VIEWPORT_TIMEOUT = 1000; const ViewportDownloadForm = ({ activeViewport, onClose, updateViewportPreview, enableViewport, disableViewport, toggleAnnotations, loadImage, downloadBlob, defaultSize, minimumSize, maximumSize, canvasClass, })
=> { const [t] = useTranslation('ViewportDownloadForm'); const [filename, setFilename] = useState(DEFAULT_FILENAME); //檔名字,初始值image const [fileType, setFileType] = useState('jpg'); // 檔案型別 const [dimensions, setDimensions] = useState({ // 尺寸 width: defaultSize, height: defaultSize, });
const [showAnnotations, setShowAnnotations] = useState(true); //是否顯示註釋 const [keepAspect, setKeepAspect] = useState(true); // 是否保持比例 const [aspectMultiplier, setAspectMultiplier] = useState({ // 比例尺寸 width: 1, height: 1, }); const [viewportElement, setViewportElement] = useState(); // 檢視元素 const [viewportElementDimensions, setViewportElementDimensions] = useState({ //視口元素尺寸 width: defaultSize, height: defaultSize, }); const [downloadCanvas, setDownloadCanvas] = useState({ //下載畫布 ref: createRef(), //DOM關於回撥 refs // ref: null, //DOM關於回撥 refs width: defaultSize, height: defaultSize, }); console.log(downloadCanvas.ref); const [viewportPreview, setViewportPreview] = useState({ //檢視預覽 src: null, width: defaultSize, height: defaultSize, }); const [error, setError] = useState({ // 錯誤資訊 width: false, height: false, filename: false, //檔名 }); const hasError = Object.values(error).includes(true); //有錯誤,判斷error裡面是否包含true /** * useRef 返回一個可變的 ref 物件,其 .current 屬性被初始化為傳入的引數(initialValue)。返回的 ref 物件在元件的整個生命週期內保持不變。 * @type {React.MutableRefObject<null>} */ const refreshViewport = useRef(null); //重新整理檢視 const downloadImage = () => { //下載圖片 downloadBlob( filename || DEFAULT_FILENAME, fileType, viewportElement, downloadCanvas.ref.current ); }; /** * @param {object} event - Input change event * @param {object}事件-輸入更改事件 * @param {string} dimension - "height" | "width" * @param {string}尺寸-“高度” | “寬度” */ // 關於尺寸變化 const onDimensionsChange = (event, dimension) => { const oppositeDimension = dimension === 'height' ? 'width' : 'height'; const sanitizedTargetValue = event.target.value.replace(/\D/, ''); const isEmpty = sanitizedTargetValue === ''; //是否為空 const newDimensions = { ...dimensions }; const updatedDimension = isEmpty ? '' : Math.min(sanitizedTargetValue, maximumSize); if (updatedDimension === dimensions[dimension]) { return; } newDimensions[dimension] = updatedDimension; if (keepAspect && newDimensions[oppositeDimension] !== '') { newDimensions[oppositeDimension] = Math.round( newDimensions[dimension] * aspectMultiplier[oppositeDimension] ); } // In current code, keepAspect is always `true` 在當前程式碼中,keepAspect始終為true。 // And we always start w/ a square width/height 我們總是以/一個正方形的寬度/高度開始 setDimensions(newDimensions); //設定尺寸 // Only update if value is non-empty //僅在值非空時更新 if (!isEmpty) { setViewportElementDimensions(newDimensions); //設定視口元素尺寸 setDownloadCanvas(state => ({ //設定下載畫布 ...state, ...newDimensions, //新尺寸 })); } }; const error_messages = { // 錯誤資訊 width: t('minWidthError'), height: t('minHeightError'), filename: t('emptyFilenameError'), }; const renderErrorHandler = errorType => { // 渲染錯誤處理程式 if (!error[errorType]) { return null; } return <div className="input-error">{error_messages[errorType]}</div>; }; const onKeepAspectToggle = () => { //保持縱橫切換 const { width, height } = dimensions; const aspectMultiplier = { ...aspectMultiplier }; if (!keepAspect) { const base = Math.min(width, height); aspectMultiplier.width = width / base; aspectMultiplier.height = height / base; setAspectMultiplier(aspectMultiplier); } setKeepAspect(!keepAspect); }; const validSize = value => (value >= minimumSize ? value : minimumSize); // 有效尺寸 const loadAndUpdateViewports = useCallback(async () => { // 載入並更新視口 const { width: scaledWidth, height: scaledHeight } = await loadImage( //載入圖片 activeViewport, // 活動視口 viewportElement, // 視口元素 dimensions.width, dimensions.height ); toggleAnnotations(showAnnotations, viewportElement); // 是否顯示註釋,切換註釋 const scaledDimensions = { //比例尺 height: validSize(scaledHeight), //校驗是否為有效尺寸 width: validSize(scaledWidth),//校驗是否為有效尺寸 }; setViewportElementDimensions(scaledDimensions); // 設定視口元素尺寸 setDownloadCanvas(state => ({ //設定下載畫布 ...state, ...scaledDimensions, })); const { dataUrl, //資料地址 width: viewportElementWidth, //視口元素寬度 height: viewportElementHeight, } = await updateViewportPreview( //更新視口預覽 viewportElement, //視口元素 downloadCanvas.ref.current, //下載畫布,訪問 Refs fileType //檔案型別 ); setViewportPreview(state => ({ // 設定視口預覽 ...state, src: dataUrl, width: validSize(viewportElementWidth), //驗證寬度是否有效 height: validSize(viewportElementHeight), })); }, [ //inputs 變化檢測 activeViewport,//活動檢視 viewportElement,//視口元素 showAnnotations,//顯示註釋 loadImage,//載入圖片 toggleAnnotations,//切換註釋 updateViewportPreview,//更新視口預覽 fileType,//檔案型別 downloadCanvas.ref,//下載畫布資源,Ref minimumSize,//最小尺寸 maximumSize,//最大尺寸 viewportElementDimensions,//視口元素尺寸 ]); /** * 通過使用這個 Hook,你可以告訴 React 元件需要在渲染後執行某些操作。React 會儲存你傳遞的函式(我們將它稱之為 “effect”),並且在執行 DOM 更新之後呼叫它。在這個 effect 中,我們設定了 document 的 title 屬性,不過我們也可以執行資料獲取或呼叫其他命令式的 API。 */ useEffect(() => { enableViewport(viewportElement);//啟用視口 return () => { disableViewport(viewportElement);//禁用視口 useEffect 可以在元件渲染後實現各種不同的副作用。有些副作用可能需要清除,所以需要返回一個函式: }; }, [disableViewport, enableViewport, viewportElement]);//這裡是檢測 useEffect(() => { if (refreshViewport.current !== null) { clearTimeout(refreshViewport.current); } refreshViewport.current = setTimeout(() => { refreshViewport.current = null; loadAndUpdateViewports(); }, REFRESH_VIEWPORT_TIMEOUT);//重新整理視口超時時間 }, [ //檢測 activeViewport, viewportElement, showAnnotations, dimensions, loadImage, toggleAnnotations, updateViewportPreview, fileType, downloadCanvas.ref, minimumSize, maximumSize, ]); useEffect(() => { //Effect Hook 可以讓你在函式元件中執行副作用操作 const { width, height } = dimensions; // 尺寸 const hasError = { //錯誤資訊 width: width < minimumSize, //小於最小尺寸 height: height < minimumSize, filename: !filename, }; setError({ ...hasError });//設定錯誤資訊 物件的擴充套件運算子(...)用於取出引數物件的所有可遍歷屬性,拷貝到當前物件之中。 }, [dimensions, filename, minimumSize]); return ( console.log(viewportPreview.src), console.log(viewportElement), // console.log(activeViewport), // console.log(downloadCanvas.ref), <div className="ViewportDownloadForm" > <div style={{ height: viewportElementDimensions.height, width: viewportElementDimensions.width, position: 'absolute', left: '9999px', }} ref={ref => setViewportElement(ref)} > <canvas className={canvasClass} //cornerstone-canvas style={{ height: downloadCanvas.height, width: downloadCanvas.width, display: 'block', }} width={downloadCanvas.width} height={downloadCanvas.height} ref={downloadCanvas.ref} ></canvas> </div> {viewportPreview.src ? ( <div className="preview" data-cy="image-preview"> <div className="preview-header"> {t('imagePreview')}</div> <img className="viewport-preview" src={viewportPreview.src} alt={t('imagePreview')} data-cy="image-preview" data-cy="viewport-preview-img" /> </div> ) : ( <div className="loading-image"> <Icon name="circle-notch" className="icon-spin" /> {t('loadingPreview')} </div> )} <div className="actions"> <div className="action-save"> <button disabled={hasError} onClick={downloadImage} className="btn btn-primary" data-cy="download-btn" > {t('Buttons:Download')} </button> </div> </div> </div> ); }; ViewportDownloadForm.propTypes = { onClose: PropTypes.func.isRequired, activeViewport: PropTypes.object, updateViewportPreview: PropTypes.func.isRequired, enableViewport: PropTypes.func.isRequired, disableViewport: PropTypes.func.isRequired, toggleAnnotations: PropTypes.func.isRequired, loadImage: PropTypes.func.isRequired, downloadBlob: PropTypes.func.isRequired, /** A default width & height, between the minimum and maximum size */ defaultSize: PropTypes.number.isRequired, minimumSize: PropTypes.number.isRequired, maximumSize: PropTypes.number.isRequired, canvasClass: PropTypes.string.isRequired, }; export default ViewportDownloadForm;