zoukankan      html  css  js  c++  java
  • [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({ // 尺寸
         defaultSize,
        height: defaultSize,
      });
    
      const [showAnnotations, setShowAnnotations] = useState(true); //是否显示注释
    
      const [keepAspect, setKeepAspect] = useState(true); // 是否保持比例
      const [aspectMultiplier, setAspectMultiplier] = useState({ // 比例尺寸
         1,
        height: 1,
      });
    
      const [viewportElement, setViewportElement] = useState(); // 视图元素
      const [viewportElementDimensions, setViewportElementDimensions] = useState({ //视口元素尺寸
         defaultSize,
        height: defaultSize,
      });
    
      const [downloadCanvas, setDownloadCanvas] = useState({ //下载画布
        ref: createRef(), //DOM关于回调 refs
        // ref: null, //DOM关于回调 refs
         defaultSize,
        height: defaultSize,
    
      });
    console.log(downloadCanvas.ref);
      const [viewportPreview, setViewportPreview] = useState({ //视图预览
        src: null,
         defaultSize,
        height: defaultSize,
      });
    
      const [error, setError] = useState({ // 错误信息
         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 = { // 错误信息
         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 {  scaledWidth, height: scaledHeight } = await loadImage( //载入图片
          activeViewport, // 活动视口
          viewportElement, // 视口元素
          dimensions.width,
          dimensions.height
        );
    
        toggleAnnotations(showAnnotations, viewportElement); // 是否显示注释,切换注释
    
        const scaledDimensions = { //比例尺
          height: validSize(scaledHeight), //校验是否为有效尺寸
           validSize(scaledWidth),//校验是否为有效尺寸
        };
    
        setViewportElementDimensions(scaledDimensions); // 设置视口元素尺寸
        setDownloadCanvas(state => ({ //设置下载画布
          ...state,
          ...scaledDimensions,
        }));
    
        const {
          dataUrl, //数据地址
           viewportElementWidth, //视口元素宽度
          height: viewportElementHeight,
        } = await updateViewportPreview( //更新视口预览
          viewportElement, //视口元素
          downloadCanvas.ref.current, //下载画布,访问 Refs
          fileType //文件类型
        );
    
        setViewportPreview(state => ({ // 设置视口预览
          ...state,
          src: dataUrl,
           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 < 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,
               viewportElementDimensions.width,
              position: 'absolute',
              left: '9999px',
            }}
            ref={ref => setViewportElement(ref)}
          >
            <canvas
              className={canvasClass} //cornerstone-canvas
              style={{
                height: downloadCanvas.height,
                 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;
     
  • 相关阅读:
    IG GROUP开源RESTdoclet项目
    Visual Studio 2012 Update 1抢先看
    使用 Windows Azure 移动服务将云添加到您的应用
    WMF 3.0 RTM(包含PowerShell 3.0 )业已发布
    Node.js 0.9.2 发布(非稳定版)
    vsftpd 3.0.1 正式版发布
    Piggydb 6.2 发布,个人知识库管理
    Apache Commons Codec 1.7 发布
    Notepad++ 6.1.8 正式版发布
    gWaei 3.6.0 发布,英日词典
  • 原文地址:https://www.cnblogs.com/landv/p/13283100.html
Copyright © 2011-2022 走看看