rii-mango / Papaya

A pure JavaScript medical research image viewer.
Other
539 stars 199 forks source link

React JS and Papaya #90

Closed Crisnil closed 7 years ago

Crisnil commented 7 years ago

Hi how can papaya integrated with reactjs? it always says "papaya requires javascript" then i try the iframe. how to pass params from react component to papaya viewer?

martinezmj-ims commented 7 years ago

I don't have experience with ReactJS, but since you are getting the "Papaya requires JavaScript" message, this suggests that papaya.Container.startPapaya() is not being called. My guess is that since this is set to be called in the window load event, that may not be compatible with ReactJS.

Try calling papaya.Container.startPapaya() somewhere in your code, I think that should fix the issue.

You may also find these other calls helpful: https://github.com/rii-mango/Papaya/wiki/API

Crisnil commented 7 years ago

thanks, that actually works calling papaya.Container.startPapaya(); im on to my next goal to send params in the compnent

pradeepism0492 commented 4 years ago

@Crisnil Have you build it in react ??

Crisnil commented 4 years ago

Hi, I had used papaya as plain javascript and run in reactjs as one component. I just test it and load some static dicom image and able to load the images. I will try to look at it again and share the code with you.

On Mon, Nov 25, 2019 at 4:17 PM pradeepism04 notifications@github.com wrote:

@Crisnil https://github.com/Crisnil Have you build it in react ??

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/rii-mango/Papaya/issues/90?email_source=notifications&email_token=ABZSJ2LU34FTU2V2WZEGJYTQVOCYFA5CNFSM4DGJWDLKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEFBQYBI#issuecomment-558042117, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABZSJ2NJRCX6MLEAJRDEILTQVOCYFANCNFSM4DGJWDLA .

Crisnil commented 4 years ago

please see sample code

import React from "react";

import '~/src/components/modality/components/papaya.css' import { Row, Col, Grid } from 'react-bootstrap'

class PapayaView extends React.Component{

loadpick =(e)=>{
    var params = [];
    params["showOrientation"] = true;
    params["expandable"] = true;
    params["showOrientation"] = true;
    params["worldSpace"] = true;
    params["showRuler"] = true;
    params["kioskMode"]=true;
    params["showControls"]=true;
    params["showControlBar"]=true;
    params["images"]=[["/papaya/sample/brain_001.dcm",
        "/papaya/sample/brain_002.dcm",
        "/papaya/sample/brain_003.dcm",
        "/papaya/sample/brain_004.dcm",
        "/papaya/sample/brain_005.dcm",
        "/papaya/sample/brain_006.dcm",
        "/papaya/sample/brain_007.dcm",
        "/papaya/sample/brain_008.dcm",
        "/papaya/sample/brain_009.dcm",
        "/papaya/sample/brain_010.dcm",
        "/papaya/sample/brain_011.dcm",
        "/papaya/sample/brain_012.dcm",
        "/papaya/sample/brain_013.dcm",
        "/papaya/sample/brain_014.dcm",
        "/papaya/sample/brain_015.dcm",
        "/papaya/sample/brain_016.dcm",
        "/papaya/sample/brain_017.dcm",
        "/papaya/sample/brain_018.dcm",
        "/papaya/sample/brain_020.dcm",
        "/papaya/sample/brain_019.dcm"
    ]];
    console.log("button was click",params);
    papaya.Container.addViewer("viewcontent", params);
    papaya.Container.resetViewer(0, params);
    papaya.Container.addImage(0, params["images"][0]);

};

render(){

    var load = require('load-script');

    load ('/papaya/papaya.js?build=1422', function (err, script){
        if (err) {
            console.log("not loaded");
        }
        else {
            console.log(script.src);// Prints 'foo'.js'
            papaya.Container.startPapaya();
        }
    });

    return(
             <Row>
                 <Col md={12} >
                    <Row>
                        <Col xs={12} md={2} >
                            <button

onClick={this.loadpick}>ShowViewer

                    </Row>
                 </Col>
            </Row>

    )
}

} export default PapayaView;

On Mon, Nov 25, 2019 at 5:01 PM Crisnil Acuyado cacuyado@gmail.com wrote:

Hi, I had used papaya as plain javascript and run in reactjs as one component. I just test it and load some static dicom image and able to load the images. I will try to look at it again and share the code with you.

On Mon, Nov 25, 2019 at 4:17 PM pradeepism04 notifications@github.com wrote:

@Crisnil https://github.com/Crisnil Have you build it in react ??

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/rii-mango/Papaya/issues/90?email_source=notifications&email_token=ABZSJ2LU34FTU2V2WZEGJYTQVOCYFA5CNFSM4DGJWDLKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEFBQYBI#issuecomment-558042117, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABZSJ2NJRCX6MLEAJRDEILTQVOCYFANCNFSM4DGJWDLA .

pradeepism0492 commented 4 years ago

@Crisnil thanks for reply, still it's saying papaya script required, once i refresh the page script was loaded on index.html page and also saying Line 88:5: 'papaya' is not defined no-undef

Crisnil commented 4 years ago

take note of this

var load = require('load-script');

    load ('/papaya/papaya.js?build=1422', function (err, script){
        if (err) {
            console.log("not loaded");
        }
        else {
            console.log(script.src);// Prints 'foo'.js'
            papaya.Container.startPapaya();
        }
    });

On Wed, Nov 27, 2019 at 2:24 PM pradeepism04 notifications@github.com wrote:

@Crisnil https://github.com/Crisnil thanks for reply, still it's saying papaya script required, once i refresh the page script was loaded on index.html page and also saying Line 88:5: 'papaya' is not defined no-undef

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/rii-mango/Papaya/issues/90?email_source=notifications&email_token=ABZSJ2KWI7NS4T4ZLKYB4DLQVYHA7A5CNFSM4DGJWDLKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEFIODGI#issuecomment-558948761, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABZSJ2M3DRHXMOPWRWYHJXDQVYHA7ANCNFSM4DGJWDLA .

pradeepism0492 commented 4 years ago

@crisnil var load = require("load-script");

load("papaya.js", function(err, script) {
  if (err) {
    console.log("not loaded");
  } else {
    console.log(script.src); // Prints 'foo'.js'
    // console.log("papaya", script, papaya);
    papaya.Container.startPapaya();**----->Getting error here** 
  }
});

papaya.js store at component location and but not able to get the papaya.Container And getting the same error 'papaya' is not defined no-undef

Crisnil commented 4 years ago

Did you add load-script in npm?

On Wed, Nov 27, 2019, 4:27 PM pradeepism04 notifications@github.com wrote:

var load = require("load-script");

load("papaya.js", function(err, script) { if (err) { console.log("not loaded"); } else { console.log(script.src); // Prints 'foo'.js' // console.log("papaya", script, papaya); papaya.Container.startPapaya();----->Getting error here } });

papaya.js store at component location and but not able to get the papaya.Container And getting the same error 'papaya' is not defined no-undef

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/rii-mango/Papaya/issues/90?email_source=notifications&email_token=ABZSJ2IZDNPXNABARDGMP53QVYVOFA5CNFSM4DGJWDLKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEFIWN7Y#issuecomment-558982911, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABZSJ2NFZFWKPEQYUOIWMKDQVYVOFANCNFSM4DGJWDLA .

pradeepism0492 commented 4 years ago

@Crisnil Yes, and also when i click viewPapaya then papaya.js is not loaded, But when i refresh the page then it's loaded.

Crisnil commented 4 years ago

I think I provided you all with what have done. Maybe you do solve and share your solution.

On Wed, Nov 27, 2019, 6:15 PM pradeepism04 notifications@github.com wrote:

@Crisnil https://github.com/Crisnil Yes

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/rii-mango/Papaya/issues/90?email_source=notifications&email_token=ABZSJ2LMR47F6TVPGPLHSYTQVZCDVA5CNFSM4DGJWDLKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEFJAFQI#issuecomment-559022785, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABZSJ2MO6GBQBJOYW2TRGNDQVZCDVANCNFSM4DGJWDLA .

arindas commented 2 years ago

Here's a solution, complete with react functional components and react hooks: https://github.com/arindas/papaya-react

Edwin18 commented 1 year ago

I also struggled with papaya and did this, perhaps it will be useful to someone.

UPDATED

Its only for proper work with React, if you will run it as recomender all fine you will have no problem with sizes and positioning of buttons.

I splited in to 2 files:

  1. papaya configuration file
  2. React Functional Component -- where we have some type declaration -- + i override couple functions getViewerDimensions and resizeViewer

I did in this way cuz we have SPA + i use another viewer niivue so basicly user can choose viewer + it should rerender/update when we change patient without any reload

papaya configuration file

// eslint-disable-next-line import/no-anonymous-default-export
export default (visitId: number) => {
  window.PAPAYA_PADDING = 0;
  window.PAPAYA_SPACING = 3;
  window.PAPAYA_CONTAINER_PADDING_TOP = 0;

  const setViewAngle = (an: number) => {
    // prettier-ignore
    window.papayaContainers[0].viewer.surfaceView.mouseRotCurrent = [
      -Math.cos(an),         0, Math.sin(an),          0,
       Math.sin(an),         0, Math.cos(an),          0,
                  0,         1,            0,          0,
                  0,         0,            0,          1,
    ];
  };
  const setFrameRotation = () => {
    setViewAngle(((Date.now() / 100) % 360) * (3.1415 / 180));
    window.papayaContainers[0].viewer.surfaceView.draw();
    window.papayaContainers[0].viewer.drawViewer();
  };
  const toggleAnimRotating = () => {
    if (window.papayaContainers[0].viewer.anim_rotating != null) {
      clearInterval(window.papayaContainers[0].viewer.anim_rotating);
      window.papayaContainers[0].viewer.anim_rotating = null;
    } else {
      window.papayaContainers[0].viewer.anim_rotating = setInterval(setFrameRotation, 70);
    }
  };

  window.params = {
    showControlBar: false,
    kioskMode: true,
    mainView: 'coronal',
    fullScreenPadding: true,
    showOrientation: false,
    orthogonalTall: false,
    radiological: true,
    smoothDisplay: true,
    worldSpace: true,
    ignoreNiftiTransforms: false,
    images: [
      window.api.getMriObjects('main_mri', visitId),
      window.api.getMriObjects('hippo_masks', visitId),
    ],
    surfaces: [
      window.api.getMriObjects('head.surf.gii', visitId),
      window.api.getMriObjects('hippo_mask.surf.gii', visitId),
    ],
    loadingComplete: () => {
      window.papayaContainers[0].viewer.surfaceView.backgroundColor = [0.0, 0.0, 0.0];
      // prettier-ignore
      window.papayaContainers[0].viewer.surfaceView.mouseRotCurrent = [
        -0.682,         0.105,         -0.724,         0,
        -0.726,        -0.204,          0.656,         0,
        -0.078,         0.973,          0.215,         0,
             0,             0,              0,         1,
      ];
      window.papayaContainers[0].viewer.surfaceView.showSurfacePlanes = false;
      window.papaya.Container.showImage(0, 0);
      toggleAnimRotating();
    },

    // Specific file configuration
    main_mri: { interpolation: false, min: 0, max: 170 },
    hippo_masks: { min: 192, max: 270, lut: 'Red Overlay', alpha: 0.7 },
    'head.surf.gii': { alpha: 0.6 },
    'hippo_mask.surf.gii': { color: [1, 0.9, 0.2], alpha: 1 },
  };
};

React Functional Component

import { TGlobalDataSet } from '@ts-types/types';
import Papaya from '@ts/brain-viewer/papaya';
import React, { FC, useEffect } from 'react';
import { useTranslation } from 'react-i18next';

type TBrainViewerPapaya = {
  id: number;
};
interface PapayaContainer {
  containerHtml: any;
  fullScreenPadding: boolean;
  orthogonal: boolean;
  hasSurface: () => boolean;
  orthogonalTall: boolean;
  collapsable: boolean;
  kioskMode: boolean;
  nestedViewer: boolean;
  showControlBar: boolean;
}
interface Image {
  screenDim: number;
}

interface Container {
  showControls: boolean;
  containerIndex: number;
}

interface Viewer {
  canvas: HTMLCanvasElement;
  initialized: boolean;
  mainImage: Image;
  container: Container;
  calculateScreenSliceTransforms: () => void;
  drawViewer: (force?: boolean) => void;
}

const papayaRoundFast = (val: number) => {
  if (val > 0) {
    return (val + 0.5) | 0;
  }

  return (val - 0.5) | 0;
};

const BrainViewerPapaya: FC<TGlobalDataSet & TBrainViewerPapaya> = ({ id }) => {
  const { t } = useTranslation();

  useEffect(() => {
    const papayaScript = document.createElement('script');

    papayaScript.src = '/static/my-page/js/papaya.js';
    papayaScript.async = true;
    papayaScript.defer = true;
    papayaScript.onload = () => {
      // Override getViewerDimensions method
      // https://github.com/rii-mango/Papaya/blob/64a82432dca03591870295a7a12a342480e04f6d/src/js/main.js#L679
      window.papaya.Container.prototype.getViewerDimensions = function (this: PapayaContainer): [number, number] {
        let parentWidth: number, height: number, width: number, ratio: number;

        parentWidth = this.containerHtml.parent().width() - (this.fullScreenPadding ? 2 * window.PAPAYA_PADDING : 0);
        ratio = this.orthogonal ? (this.hasSurface() ? 1.333 : 1.5) : 1;

        if (this.orthogonalTall || !this.orthogonal) {
          width = parentWidth;
          height = papayaRoundFast(width * ratio);
        } else {
          width = parentWidth;
          height = papayaRoundFast(width / ratio);
        }

        return [width, height];
      };

      // Override resizeViewer method
      // https://github.com/rii-mango/Papaya/blob/64a82432dca03591870295a7a12a342480e04f6d/src/js/viewer/viewer.js#L2418
      window.papaya.viewer.Viewer.prototype.resizeViewer = function (this: Viewer, dims: number[]) {
        const PAPAYA_PADDING_FOR_CONTROLS = 16;
        const halfPadding = PAPAYA_PADDING_FOR_CONTROLS / 2;
        let offsetTop: number, offsetLeft: number;
        let swapButton: HTMLElement | null, originButton: HTMLElement | null;
        let incButton: HTMLElement | null, decButton: HTMLElement | null, centerButton: HTMLElement | null;

        this.canvas.width = dims[0];
        this.canvas.height = dims[1];

        if (this.initialized) {
          this.calculateScreenSliceTransforms();
          this.canvas.getBoundingClientRect();
          this.drawViewer(true);

          if (this.container.showControls) {
            offsetTop = this.canvas.offsetTop;
            offsetLeft = this.canvas.offsetLeft;

            incButton = document.getElementById(window.PAPAYA_CONTROL_MAIN_INCREMENT_BUTTON_CSS + this.container.containerIndex);
            if (incButton) {
              incButton.style.top = `${offsetTop + halfPadding}px`;
              incButton.style.left = `${offsetLeft + this.mainImage.screenDim - incButton.offsetWidth - halfPadding}px`;
              incButton.style.position = 'absolute';
            }

            decButton = document.getElementById(window.PAPAYA_CONTROL_MAIN_DECREMENT_BUTTON_CSS + this.container.containerIndex);
            if (decButton) {
              decButton.style.top = `${offsetTop + decButton.offsetHeight + PAPAYA_PADDING_FOR_CONTROLS}px`;
              decButton.style.left = `${offsetLeft + this.mainImage.screenDim - decButton.offsetWidth - halfPadding}px`;
              decButton.style.position = 'absolute';
            }

            swapButton = document.getElementById(window.PAPAYA_CONTROL_MAIN_SWAP_BUTTON_CSS + this.container.containerIndex);
            if (swapButton) {
              swapButton.style.top = `${offsetTop + this.mainImage.screenDim - swapButton.offsetHeight - halfPadding}px`;
              swapButton.style.left = `${offsetLeft + this.mainImage.screenDim - swapButton.offsetWidth - halfPadding}px`;
              swapButton.style.position = 'absolute';
              swapButton.innerText = t('スワップ・ビュー');
            }

            centerButton = document.getElementById(window.PAPAYA_CONTROL_MAIN_GOTO_CENTER_BUTTON_CSS + this.container.containerIndex);
            if (centerButton) {
              centerButton.style.top = `${offsetTop + this.mainImage.screenDim - centerButton.offsetHeight - halfPadding}px`;
              centerButton.style.left = `${offsetLeft + halfPadding}px`;
              centerButton.style.position = 'absolute';
              centerButton.innerText = t('センターへ');
            }

            originButton = document.getElementById(window.PAPAYA_CONTROL_MAIN_GOTO_ORIGIN_BUTTON_CSS + this.container.containerIndex);
            if (originButton) {
              originButton.style.top = `${offsetTop + this.mainImage.screenDim - originButton.offsetHeight - halfPadding}px`;
              originButton.style.left = `${offsetLeft + halfPadding * 2 + (centerButton?.offsetWidth || 0)}px`;
              originButton.style.position = 'absolute';
              originButton.innerText = t('原点へ');
            }
          }
        }
      };
      // Setup our settings
      Papaya(id);
      // Run papaya
      window.papaya.Container.startPapaya();
    };

    document.body.appendChild(papayaScript);

    return () => {
      // Clear rotation interval
      if (window.papayaContainers[0]?.viewer?.anim_rotating) clearInterval(window.papayaContainers[0].viewer.anim_rotating);
      // Clear all previous listeners
      // TODO: Find all other events and remove them otherwise its leak of memory!
      window.removeEventListener('resize', window.papaya.Container.resizePapaya, !1);
      window.removeEventListener('orientationchange', window.papaya.Container.reorientPapaya, !1);
      window.removeEventListener('load', window.papaya.Container.startPapaya, !1);
      // Remove script
      document.body.removeChild(papayaScript);
      // Clear all variable
      window.params = undefined;
      window.papayaContainers = undefined;
      window.papaya = undefined;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [id]);

  return <div className='home-brain-viewer-papaya papaya' data-params='params' />;
};

export default BrainViewerPapaya;