Compare commits

..
237 Commits
Author SHA1 Message Date
Erik Ziegler 571dd5848f fix(ViewerRouting): Fix routing failures for /study/x/series/y (#617)
re #614
2019-07-08 18:27:08 +02:00
David Wire 2d48d0aa37 feat(StudyList): Add QIDO style query parameters to set initial filters (#543)
This pull request adds the ability to use query parameters to pass filters into the StudyList from
the url. These parameters are of the same form used by the QIDO requests to apply the filters. This
solution seemed to me to be the most obvious way to manage them. There's one open question however,
around what to do with the parameters after the initial load. For now, the URL parameters are
overridden the moment the user tries to add another filter. Depending on review feedback it seems
like it may make more sense for those query parameter filters to be "permanent" and so any further
filtering would augment those parameters rather than replace them.
2019-07-08 18:15:06 +02:00
Erik Ziegler 562d63fa74 fix(package.json): Update @ohif/extension-dicom-microscopy to fix resizing behaviour
fix #550
2019-07-08 14:31:23 +02:00
biharck 1a6246f99b @ohif/extension-dicom-microscopy: Add resize call when the container has resized (0.0.9) 2019-07-08 14:31:23 +02:00
Erik Ziegler ce1a62a961 chore(gitattributes): Fix gitattributes handling of .fig files 2019-07-08 13:49:56 +02:00
Evren Ozkan dd6acb2d03 feat(extension-cornerstone): Add additional tools: Magnify, ROI Window, Probe, Ellipse, Rectangle, Invert, Rotate Right, Flip H, Flip V, Clear 2019-07-08 13:49:56 +02:00
Danny Brown 5ac9048ef0 feat: extension panels
* Snapshot -- Switching branches
* fix classes and hooks for panel componet
* Restore button functionality
* feat: support for expandableToolMenu
* Shift cornerstoneTools config up a layer, and use globalToolSync
* Remaining initCornerstoneTools changes
* Pull in Segmentation Plugin
* Shift MeasurementsPanel to an extension
* Note regarding where data is coming from
* Make sure measurement callback is available
* Bump core version
* Shift MeasurementsTable to a local extensions directory
* Register appCommands as an extension
* Update package dependencies and yarn lock
* Support for panel width
* Ability to pass props to our panel component
* Add a safety check around calling our tacked on method for tool options
* Left sidebar plugins + fix activeIndex prop passed to sidebar.
* fix: viewer height
Now in a shared container w/ top bar, so we need to factor that in when calculating height
* lock file latest
* Update thumbnails if studies has changes
* bump cornerstone version to resolve globalToolSynch history issue
* Default panel to open; studies optional
* Bump minor version for ohif-cornestone-extension
* Simplify button logic
* Accommodate odd roundedButtonGroup value change emit
* Map viewers + selectedViewport instead of pulling off the window
2019-07-04 14:09:13 -04:00
Danny Brown 514609708d chore: set codecov commit status threshold (#623)
* chore: set codecov commit status threshold

* Test new code doesn't fail threshold

* Turn off patch status

* Undo test threshold code
2019-07-02 22:18:50 -04:00
Erik Ziegler c30b88d48a docs(translating.md): Add Locize logo for their open source sponsorship (#612) 2019-07-01 12:10:56 +02:00
João Felipe de Medeiros Moreira 4f1505de3c docs(README) Changes README related to cypress to use the new commands (#610) 2019-07-01 12:01:18 +02:00
Erik Ziegler 57d2ae23ae ci(package.json): Change settings for viewer.ohif.org to use Locize CDN 2019-06-30 23:40:03 +02:00
Erik Ziegler fd6ec04514 feat(package.json): Update i18n approach to optionally use Locize CDN depending on config. Bump @ohif/extension-vtk @ohif/i18n 2019-06-30 23:10:43 +02:00
Erik Ziegler 6a98550c43 @ohif/extension-vtk 0.1.3: Wait for i18n to be initialized before adding resources 2019-06-30 23:10:43 +02:00
Erik Ziegler e2ec11c83e @ohif-i18n 0.2.2: Expose the promise tracking i18next initialization 2019-06-30 23:10:43 +02:00
Erik Ziegler d2c773196f @ohif-i18n 0.2.1: Prevent crashing when window.config is undefined 2019-06-30 15:41:34 +02:00
Erik Ziegler 1b7625affd @ohif/i18n - Setup optional link to Locize translation, and script to pull and store translations 2019-06-30 14:37:07 +02:00
Erik Ziegler 8a4306d1b0 fix(package.json): Bump vtk extension and react-viewerbase 2019-06-29 11:35:20 +02:00
Erik Ziegler 3cb8f804ad @ohif/extension-vtk: Update to 0.1.2 after bumping react-viewerbase version 2019-06-29 11:35:20 +02:00
Rodrigo Antinarelli 16cea8681e @ohif/i18n: Fix issues with exports and update docs (#598)
* update i18n version -- already published

* update ohif/i18n version and add modules

* update ohif/i18n version

* update translating documentation

* replace addLocales method and exported modules

* lock files

* Update index.js

* fix(@ohif/i18n): export custom methods in the main i18n object

`initI18n`, `addLocales` and `T` are now being exported inside the main `i18n` object.

* remove unecessary dependencies

* update vtk-extension lock file
2019-06-29 09:33:38 +02:00
Erik Ziegler cb565427b3 fix(package.json): Bump ohif-core to fix broken multiframe usage with WADO-RS
fix #539
2019-06-28 17:56:13 +02:00
João Felipe de Medeiros Moreira 3a4715759f fix(polyfills): Adds core-js/stable and regenerator-runtime (#590) 2019-06-28 16:20:16 +02:00
biharck edb0db349b feat(OHIFStandaloneViewer.js): adding NProgress loading bar on top of the page 2019-06-27 15:28:37 +02:00
Erik Ziegler 5a3f3e3eff fix(package.json): Update react-viewerbase and extension-vtk to ensure old @ohif/i18n is not used 2019-06-27 15:12:42 +02:00
Erik Ziegler 5efa93ba61 @ohif/extension-vtk: Update dependencies which were pulling in old @ohif/i18n 2019-06-27 15:12:42 +02:00
Erik Ziegler 722d68c85a fix(package.json): Update vtk-extension to fix i18n issues 2019-06-27 14:09:20 +02:00
Erik Ziegler d14f3eafdd @ohif/extension-vtk: Republish 0.0.9 to avoid inadvertently broken 0.0.8 2019-06-27 14:09:20 +02:00
Rodrigo Antinarelli d04bb323f7 @ohif-i18n - Replace use of context to import locales (#575) 2019-06-27 12:01:11 +02:00
biharck 6548dffb42 feat(Header.js): Add About modal to header 2019-06-27 10:59:23 +02:00
Erik Ziegler 81cb9d3a75 ci(rollbar): Add Rollbar script during CI deploy 2019-06-27 09:41:21 +02:00
Erik Ziegler 5807a948b6 docs(netlify): Add Netlify badge to top of docs page 2019-06-26 11:49:46 +02:00
Erik Ziegler 2bdcb7c5f7 fix(extension-dicom-microscopy): Update to 0.0.8 to use retrieveRendered by default 2019-06-24 13:32:11 +02:00
Erik Ziegler c148cd9b85 @ohif/extension-dicom-microscopy: Use retrieveRendered for frame retrieval 2019-06-24 12:39:55 +02:00
allcontributors[bot] 51f40d49e5 docs: add swederik as a contributor (#582)
* docs: update README.md

* docs: update .all-contributorsrc
2019-06-22 10:47:55 -04:00
allcontributors[bot] ab3768bc18 docs: add dannyrb as a contributor (#581)
* docs: update README.md

* docs: update .all-contributorsrc
2019-06-22 10:47:16 -04:00
allcontributors[bot] 02cad4c851 docs: add jfmedeiros1820 as a contributor (#580)
* docs: update README.md

* docs: update .all-contributorsrc
2019-06-22 10:46:10 -04:00
João Felipe de Medeiros Moreira 612832069d ci: add e2e tests with cypress
* Creates E2E tests using Cypress and includes two tests

* Improves yarn.lock file

* Includes documentation

* Cypress project id

* test e2e w/ ci and video

* run unit command before e2e

* Also cache cypress

* Persist cypress to next build step

* Try a different path

* Try without working dir

* Persist less data, but restore yarn/cypress cache in next step

* Install cypress to invalidate cache

* Add e2e as a blocker for merged publishing
2019-06-22 10:02:07 -04:00
Danny Brown 30bcc07dda Merge pull request #578 from OHIF/all-contributors/add-dlwire
docs: add dlwire as a contributor
2019-06-21 11:56:15 -04:00
allcontributors[bot] 7ef16dad9d docs: update .all-contributorsrc 2019-06-21 15:55:50 +00:00
allcontributors[bot] a97cb087eb docs: update README.md 2019-06-21 15:55:49 +00:00
David Wire 9116d08959 fix(IHEInvokeImageDisplay): Fix the props to access query parameters per API spec
I encountered this bug trying to use the IHEInvokeImageDisplay API in order to render multiple DICOM
studies in the viewer. Unfortunately, the component was no longer working and required some changes
in order to access the query parameters used in the API. These changes update the component to use
react router to access the query parameters and pass them to ConnectedViewerRetrieveStudyData as
appropriate. The move from ViewerRetrieveStudyData to ConnectedViewerRetrieveStudyData was necessary
in order to access the active server from the redux store. I also made a change from a series of if
clauses to a switch statement as it seemed a little more appropriate given the nature of the code
paths. Happy to change that back if needed. The PATIENT and default paths were not fixed as a part
of this work because we'll need a way to pass the filter in to the StudyList component.
2019-06-21 17:52:46 +02:00
Danny Brown 1d5c1cb83f feat: extension system overhaul 2019-06-21 09:15:47 -04:00
Danny Brown f7ba7621ef Merge pull request #549 from dannyrb/feature/extensions-panels-and-docs
Feature/extensions panels and docs
2019-06-21 09:13:42 -04:00
Danny Brown 51d1679dfb Merge branch 'master' into feature/extensions-panels-and-docs 2019-06-21 00:00:33 -04:00
dannyrb 6288ff9c8f Fix broken test 2019-06-20 23:58:32 -04:00
dannyrb bc4a650283 Breaks UMD build 2019-06-20 23:55:02 -04:00
dannyrb f4e4cfdf39 lock file 2019-06-20 23:50:06 -04:00
dannyrb 23de20d7d3 Bump extension and ohif-core versions 2019-06-20 23:30:52 -04:00
dannyrb 13aedecd55 Bump two more package versions 2019-06-20 23:30:16 -04:00
dannyrb 566cb218e6 Bump deps 2019-06-20 23:23:54 -04:00
dannyrb 7d2e65c73a Stubbed readme 2019-06-20 23:23:10 -04:00
dannyrb 3cb5abf0c9 Prettier config and formatting 2019-06-20 23:22:52 -04:00
dannyrb ec9ea8b761 formatting 2019-06-20 23:17:07 -04:00
dannyrb aa250a9210 bump package version 2019-06-20 23:12:55 -04:00
dannyrb 235f56c071 bump ohif-core minimum version number 2019-06-20 23:10:58 -04:00
dannyrb ff602bf500 simple vtk extension readme 2019-06-20 23:10:17 -04:00
dannyrb 5785ab9f1f bump version 2019-06-20 23:01:39 -04:00
dannyrb 273e262420 Add badge 2019-06-20 23:01:03 -04:00
dannyrb c2b048795d bump minimum required ohif-core version number 2019-06-20 22:57:57 -04:00
dannyrb 75288d986d update readme 2019-06-20 22:57:38 -04:00
dannyrb a5b0e15369 Formatting 2019-06-20 22:57:14 -04:00
dannyrb 2326aa8ba1 Some sane prettier defaults 2019-06-20 22:56:26 -04:00
dannyrb 3a684e5963 rename 2019-06-20 22:50:56 -04:00
dannyrb 56bf65d95f name bump 2019-06-20 22:50:23 -04:00
dannyrb c193ba17e7 fix for broken CINE player 2019-06-20 20:30:12 -04:00
Danny Brown a9659a0f24 Merge pull request #572 from OHIF/all-contributors/add-diego0020
docs: add diego0020 as a contributor
2019-06-18 23:35:32 -04:00
allcontributors[bot] baa28bdf41 docs: update .all-contributorsrc 2019-06-19 03:35:18 +00:00
allcontributors[bot] d9dd127539 docs: update README.md 2019-06-19 03:35:17 +00:00
Danny Brown b3873f7673 Merge pull request #520 from diego0020/dev-react-proxy
WIP: Use react proxy instead of nginx with cors headers for local dev
2019-06-18 23:33:37 -04:00
dannyrb 03501eddb0 fix typo 2019-06-18 23:33:02 -04:00
dannyrb 2f4961c078 Note regarding docker toolbox and react-proxy 2019-06-18 23:26:27 -04:00
dannyrb 4f3f19de7c Beginnings of commandsModule docs 2019-06-18 21:09:08 -04:00
Danny Brown 39d844f106 Merge branch 'master' into dev-react-proxy 2019-06-18 21:05:13 -04:00
dannyrb 3859359a05 Note regarding how extensions are specified for app 2019-06-18 16:11:38 -04:00
dannyrb 9af3ad414a Clean up code snippet config 2019-06-18 15:29:43 -04:00
dannyrb 8112c569e8 Expanding extensions docs 2019-06-18 15:19:04 -04:00
dannyrb 32b420087b Don't set vtk on viewport's layout; rely on viewportSpecificData 2019-06-18 14:51:51 -04:00
dannyrb aa811dffe3 Use dicom-html extension 2019-06-18 14:49:45 -04:00
dannyrb 0bfd49d1eb Remove window. references 2019-06-18 14:33:39 -04:00
dannyrb f26dfe4801 Causes things to blow up when sopClassHandler should be used instead of cornerstone 2019-06-18 14:33:02 -04:00
dannyrb b542ce4437 port html extension 2019-06-17 16:23:31 -04:00
dannyrb d1f7431af6 Re-add dicom microspy extension 2019-06-17 15:42:11 -04:00
dannyrb a1bbc4e87a Pull in PDF extension 2019-06-17 15:05:51 -04:00
dannyrb b154c2612d Use new extension interface 2019-06-17 15:05:27 -04:00
dannyrb 01ea3f4179 scoped package 2019-06-17 15:05:10 -04:00
dannyrb 4d540170aa Use activeContexts getter/selector in commandsManager 2019-06-17 14:48:33 -04:00
dannyrb 8b636b53be Make sure plugin is set for cornerstone viewports before a layout change is triggered 2019-06-17 14:45:53 -04:00
dannyrb 6050721d33 Use reselect to compute our activeContexts 2019-06-17 14:20:32 -04:00
dannyrb 88568b1ddd extensions specify default toolbar button context 2019-06-17 14:03:04 -04:00
dannyrb 80047ff518 Thunk and logger for redux 2019-06-17 10:40:01 -04:00
dannyrb a75bae90aa Merge branch 'master' of github.com:OHIF/Viewers into feature/extensions-panels-and-docs
# Conflicts:
#	extensions/ohif-vtk-extension/package.json
#	extensions/ohif-vtk-extension/src/commandsModule.js
#	extensions/ohif-vtk-extension/yarn.lock
2019-06-17 09:02:24 -04:00
Erik Ziegler f47ce6e629 feat(@ohif/extension-vtk): Add visible crosshair lines to MPR mode
re #562
2019-06-17 14:48:11 +02:00
Erik Ziegler 9f67ecab55 @ohif/extension-vtk: Enable crosshairs display on viewports (0.0.6) 2019-06-17 14:30:50 +02:00
dannyrb 1367f96dcd Remove code that depends on global "buttons" in Vtk Viewport 2019-06-16 23:44:01 -04:00
dannyrb ba92111484 No need to pull commandsManager off the window 2019-06-16 23:43:30 -04:00
dannyrb e6c9152cd1 Technically available in _any_ context, not just VTK 2019-06-16 23:36:10 -04:00
dannyrb 46904ea39f Context specific commands 2019-06-16 23:31:17 -04:00
dannyrb cf65e3a690 lowercase toolbarModule 2019-06-16 23:12:20 -04:00
dannyrb 723c9c9c2e force rename toolbarModule 2019-06-16 23:12:03 -04:00
dannyrb d5b4cb7b07 Refactor vtk extension; re-add to app 2019-06-16 23:11:43 -04:00
dannyrb f90578f567 Add vtk dependencies 2019-06-16 23:10:39 -04:00
dannyrb 1af09f1fad Merge branch 'master' of github.com:OHIF/Viewers into feature/extensions-panels-and-docs
# Conflicts:
#	extensions/ohif-vtk-extension/src/ConnectedToolbarSection.js
#	src/App.js
2019-06-16 22:26:44 -04:00
dannyrb 7ed90a280f Escape hatch note 2019-06-16 22:15:44 -04:00
dannyrb fc6f7446d0 Remove dead code: ConnectedToolbarSection and setToolActive 2019-06-16 14:23:03 -04:00
dannyrb 3ed602a40a Append Module to sopClassHandler method 2019-06-16 14:17:22 -04:00
dannyrb 9b7d77e2d6 Example SOP Class Handler 2019-06-16 14:16:36 -04:00
dannyrb 0cea2a8bff Simplify basic viewport extensions 2019-06-16 14:15:34 -04:00
dannyrb ffae67dc99 Remove dead comments from commandsModule 2019-06-16 14:08:38 -04:00
dannyrb 6e4dba7a10 Fix active button 👍 2019-06-16 14:07:13 -04:00
dannyrb 94177eee24 Prefer direct ToolbarButtons usage over ToolbarSection 2019-06-16 13:58:25 -04:00
dannyrb 9d50d97d6f Remove unused getDefaultToolbarButtons now that they're pushed to extension 2019-06-16 13:57:11 -04:00
dannyrb 7971ac58a2 Generic setToolActive command 2019-06-16 13:56:49 -04:00
dannyrb 4de5fa2d0e Simplify toolbar module to be config only for now; use new modules in extension 2019-06-16 13:56:24 -04:00
Erik Ziegler bd0c7b75e7 feat(@ohif/extension-vtk): Add oblique rotate button to MPR mode
re #563
2019-06-15 16:03:12 +02:00
Erik Ziegler 357187ddee @ohif/extension-vtk: Enable rotate button (0.0.5) 2019-06-15 16:03:12 +02:00
Erik Ziegler 24a8d7bca2 feat(@ohif/extension-vtk): Update app to include basic MPR with VTK (#557) 2019-06-15 14:26:09 +02:00
Erik Ziegler d0d757d468 Merge pull request #556 from OHIF/vtk-extension-changes
refactor(@ohif/extension-vtk): Update VTK extension to add basic MPR …
2019-06-15 13:44:59 +02:00
Erik Ziegler 1bf199786c Merge branch 'master' into vtk-extension-changes 2019-06-15 13:41:41 +02:00
Erik Ziegler 5a0d37ff64 Merge pull request #555 from OHIF/cornerstone-extension-update
refactor(@ohif/extension-cornerstone): Error handling and removal of …
2019-06-15 13:40:23 +02:00
Erik Ziegler 9573f67132 refactor(@ohif/extension-vtk): Update VTK extension to add basic MPR functionality 2019-06-15 11:51:56 +02:00
Erik Ziegler 537057e4d6 refactor(@ohif/extension-cornerstone): Error handling and removal of viewportData clearing on compon 2019-06-15 11:47:07 +02:00
dannyrb 43a493283a Merge branch 'feature/extensions-panels-and-docs' of github.com:dannyrb/Viewers into feature/extensions-panels-and-docs 2019-06-14 20:45:36 -04:00
Danny Brown df2a984cd3 Merge branch 'master' into feature/extensions-panels-and-docs 2019-06-14 20:45:00 -04:00
dannyrb 902dc5e31d Correctly find toolbar extensions 2019-06-14 20:44:15 -04:00
dannyrb 29853429c7 createStacks --> studyMetadata.createDisplaySets(sopClassHandlerModules) 2019-06-14 20:28:41 -04:00
Erik Ziegler 04e00fad20 feat(i18n): Add ability to internationalize the application and its extensions (#526)
* i18n basic setup

* i18n - extension extraction

* Creating spanish translation

* i18n - extension extraction

* i18n - Multiple languages overrides

* i18n - Multiple languages overrides

* remove yalc react-viewerbase

* use t prop from withTranslation

* fix typo

* Exports provider and HOC to be used by any application without install I18Next libraries

* i18n - Documentation

* i18n - Adding Provider to non Admins

* i18n - Documentation for i18n

* i18n - Documentation for i18n

* Configures hif-vtk-extention to use ohif-i18n for translation and include load more locations

* update i18n documentation

* add language detector lib

* fix text

* WIP - using yalc for react-viewerbase

* remove unused switch language buttons

* Update yarn.lock

* Merge branch 'master' of https://github.com/OHIF/Viewers into feature/i18n-basics

# Conflicts:
#	extensions/ohif-vtk-extension/package.json
#	extensions/ohif-vtk-extension/rollup.config.js
#	extensions/ohif-vtk-extension/yarn.lock
#	package.json
#	src/App.js
#	src/components/Header/Header.js
#	yarn.lock

* Adding language detector as Peer Dependency, its not working inside the rollup bundle.

* Upgrading i18next version.

* Language Detection implementation, bug fixes related to i18n and debugger helper added.

* Updating i18next documentation.

* i18n implementation - Adding final packages

* small fix

* i18n implementation - Fixing up vtk-extension's  packages

* i18n implementation - Fixing up translations

* i18n implementation - Updating yarn.lock

* fix require.context bug

* udpate ohif/i18n version

* i18n implementation - Updating yarn.lock

* i18n implementation - Removing bad image from docs

* i18n implementation - Removing ROI from translations

* i18n implementation - Fixing CineDialog translations

* update i18n package

* fix conditional

* update i18n

* fix conditional

* update @ohif/i18n
2019-06-14 15:56:20 +02:00
Erik Ziegler db814f6248 Merge branch 'master' into feature/i18n-basics 2019-06-14 15:52:39 +02:00
Rodrigo Antinarelli 56e3982111 update @ohif/i18n 2019-06-13 16:20:36 -03:00
Rodrigo Antinarelli cb2871d377 fix conditional 2019-06-13 16:20:29 -03:00
Rodrigo Antinarelli 1cbbbd6989 update i18n 2019-06-13 15:31:33 -03:00
Rodrigo Antinarelli ea3142c1ea fix conditional 2019-06-13 15:30:13 -03:00
Rodrigo Antinarelli e90041ccd6 update i18n package 2019-06-13 15:30:05 -03:00
romulo bordezani 515768aff2 i18n implementation - Fixing CineDialog translations 2019-06-13 15:02:06 -03:00
romulo bordezani f448a7cdcc i18n implementation - Removing ROI from translations 2019-06-13 14:59:41 -03:00
romulo bordezani 3fa9bc54f8 i18n implementation - Removing bad image from docs 2019-06-13 14:59:16 -03:00
romulo bordezani 414ebd5d8b i18n implementation - Updating yarn.lock 2019-06-13 14:31:04 -03:00
romulo bordezani 59489ae3c6 Merge branch 'feature/i18n-basics' of github.com:romulobordezani/Viewers into feature/i18n-basics 2019-06-13 14:25:19 -03:00
Rodrigo Antinarelli 9321c31235 udpate ohif/i18n version 2019-06-13 14:22:23 -03:00
Rodrigo Antinarelli 66fc1dd739 fix require.context bug 2019-06-13 14:22:10 -03:00
romulo bordezani 082656182b i18n implementation - Updating yarn.lock 2019-06-13 14:17:04 -03:00
romulo bordezani 94a7caa2c4 i18n implementation - Fixing up translations 2019-06-13 14:16:43 -03:00
romulo bordezani b89fada19e i18n implementation - Fixing up vtk-extension's packages 2019-06-13 14:16:30 -03:00
dannyrb 89b1ce4a4e Pull out cornerstone command registration 2019-06-13 10:17:53 -04:00
dannyrb 361be79174 Toolbar row to use new types 2019-06-13 09:51:19 -04:00
dannyrb 31c987d700 Shift to new syntax; try to get only cornerstone extension working with new syntax 2019-06-13 09:50:53 -04:00
dannyrb 0318203770 Shift commands to appropriate extension 2019-06-13 09:50:07 -04:00
dannyrb 59c6c4dc34 Comment out unused code 2019-06-13 09:49:30 -04:00
dannyrb 05e8c803c9 Update example for commandsModule 2019-06-13 09:49:09 -04:00
dannyrb 209d575092 Merge branch 'feature/extensions-panels-and-docs' of github.com:dannyrb/Viewers into feature/extensions-panels-and-docs 2019-06-12 16:38:28 -04:00
Danny Brown d0cbf577a3 Merge branch 'master' into feature/extensions-panels-and-docs 2019-06-12 16:38:28 -04:00
dannyrb b052930123 fix connected layout manager to use extensionManager 2019-06-12 16:37:45 -04:00
dannyrb 4f6cee8960 New up and expose an extensionManager for the app 2019-06-12 16:10:57 -04:00
dannyrb 9c797233bb PLUGIN_TYPES --> MODULE_TYPES 2019-06-12 16:09:35 -04:00
dannyrb 29f86d41e6 Begin stubbing an example plugin with all options as basic docs/recipe 2019-06-12 16:09:06 -04:00
João Felipe de Medeiros Moreira 071f92e45c fix(StudyBrowser): Remove transform to fix drag/drop positioning for thumbnails (#548) 2019-06-12 20:15:51 +02:00
Rodrigo Antinarelli 45993e423d small fix 2019-06-12 13:30:08 -03:00
Rodrigo Antinarelli 8c608dc05b update branch 2019-06-12 13:22:46 -03:00
Erik Ziegler 45808dc0f1 ci(Circle): Add deploy tracking and source map upload to Rollbar (#545) 2019-06-12 15:06:24 +02:00
Erik Ziegler 9f82ef1682 chore(package.json): Update ohif-core (0.5.8) and react-viewerbase (0.7.1) (#546) 2019-06-12 14:58:30 +02:00
Erik Ziegler 0d3dcf5035 docs(netlify.toml): Fix Netlify URL path issues for deploy previews (#544) 2019-06-12 09:10:21 +02:00
romulo bordezani ab0e2fe9e2 i18n implementation - Adding final packages 2019-06-12 03:43:02 -03:00
romulo bordezani 4a4d7a2171 Updating i18next documentation. 2019-06-12 03:35:17 -03:00
romulo bordezani 0c8cd3fbe9 Language Detection implementation, bug fixes related to i18n and debugger helper added. 2019-06-11 20:05:14 -03:00
romulo bordezani fde6088cb1 Upgrading i18next version. 2019-06-11 14:11:28 -03:00
romulo bordezani b4af4bed17 Adding language detector as Peer Dependency, its not working inside the rollup bundle. 2019-06-11 14:07:23 -03:00
romulo bordezani fe4db3b2c5 VTK extension - i18n implementation. 2019-06-10 19:33:15 -03:00
romulo bordezani d5909f8d74 Merge branch 'master' of https://github.com/OHIF/Viewers into feature/i18n-basics
# Conflicts:
#	extensions/ohif-vtk-extension/package.json
#	extensions/ohif-vtk-extension/rollup.config.js
#	extensions/ohif-vtk-extension/yarn.lock
#	package.json
#	src/App.js
#	src/components/Header/Header.js
#	yarn.lock
2019-06-10 14:54:18 -03:00
Danny Brown ce9d956d00 Merge pull request #538 from dannyrb/master
fix: demo
2019-06-09 22:12:00 -04:00
dannyrb 55e326dde8 force bump 2019-06-09 22:11:25 -04:00
dannyrb 64a9e38de4 chore: build warnings preventing demo deploy 2019-06-09 22:09:37 -04:00
Danny Brown 7efdb40607 Merge pull request #514 from dannyrb/fix/hotkeys
Fix/hotkeys
2019-06-08 21:42:59 -04:00
dannyrb fddcc746d9 No ESM in vanilla modules 2019-06-08 21:23:00 -04:00
dannyrb 9d9b3a7749 Make sure our app doesn't blow up if hotkeys aren't provided 2019-06-08 15:26:11 -04:00
dannyrb 78068bed4b push default hotkeys to a shared location 2019-06-08 15:25:39 -04:00
dannyrb 7f95c1284a fix: command direction for previousViewportDisplaySet 2019-06-08 15:12:19 -04:00
dannyrb 5325d2d2fe bump versions 2019-06-08 15:08:09 -04:00
Rodrigo Antinarelli ff382b0212 Update yarn.lock 2019-06-07 19:54:49 -03:00
Rodrigo Antinarelli 5bbd6f1463 remove unused switch language buttons 2019-06-07 19:54:35 -03:00
Rodrigo Antinarelli ebb2e83925 WIP - using yalc for react-viewerbase 2019-06-07 19:54:22 -03:00
Rodrigo Antinarelli ee42257736 fix text 2019-06-07 19:53:56 -03:00
Rodrigo Antinarelli fe827b5b2a add language detector lib 2019-06-07 19:53:49 -03:00
Rodrigo Antinarelli 401eab5062 update i18n documentation 2019-06-07 19:53:30 -03:00
romulo bordezani 0753e9ec3c Merge branch 'master' of https://github.com/OHIF/Viewers into feature/i18n-basics
# Conflicts:
#	extensions/ohif-vtk-extension/package.json
#	extensions/ohif-vtk-extension/rollup.config.js
#	extensions/ohif-vtk-extension/yarn.lock
#	package.json
#	src/App.js
#	src/components/Header/Header.js
#	yarn.lock
2019-06-07 17:55:53 -03:00
João Felipe Medeiros Moreira f19cd8dd81 Merge branch 'feature/i18n-basics' of github.com:romulobordezani/Viewers into feature/i18n-basics 2019-06-07 15:36:13 -03:00
João Felipe Medeiros Moreira 42cb8e32c7 Configures hif-vtk-extention to use ohif-i18n for translation and include load more locations 2019-06-07 15:35:54 -03:00
romulo bordezani 065204a87e i18n - Documentation for i18n 2019-06-06 19:26:08 -03:00
romulo bordezani 6e295ba7c6 i18n - Documentation for i18n 2019-06-06 19:13:16 -03:00
romulo bordezani dd1a5455d9 Merge branch 'feature/i18n-basics' of github.com:romulobordezani/Viewers into feature/i18n-basics 2019-06-06 18:59:17 -03:00
romulo bordezani eca7d9be6a i18n - Adding Provider to non Admins 2019-06-06 18:57:45 -03:00
romulo bordezani ebcd9b3838 i18n - Documentation 2019-06-06 18:57:19 -03:00
dannyrb a119ca33f0 Hide our user preferences modal for now 2019-06-06 15:01:32 -04:00
Danny Brown bee9985877 Merge branch 'master' into fix/hotkeys 2019-06-06 14:46:57 -04:00
dannyrb e0cbc8ef4d No need for connected user preferences when header can contain info 2019-06-06 14:41:31 -04:00
João Felipe Medeiros Moreira 56b595980e Fixes conflict after pull 2019-06-06 15:12:30 -03:00
João Felipe Medeiros Moreira 9fd39dbf84 Exports provider and HOC to be used by any application without install I18Next libraries 2019-06-06 15:11:34 -03:00
Danny Brown cbf144ff90 Merge pull request #531 from OHIF/dependabot/npm_and_yarn/extensions/ohif-cornerstone-extension/js-yaml-3.13.1
build(deps): bump js-yaml from 3.12.0 to 3.13.1 in /extensions/ohif-cornerstone-extension
2019-06-06 10:29:04 -04:00
dannyrb 2d6f9c1a05 A way to tell CircleCI not to run for this change 2019-06-06 09:15:12 -04:00
Danny Brown 713a11a584 Merge branch 'master' into dependabot/npm_and_yarn/extensions/ohif-cornerstone-extension/js-yaml-3.13.1 2019-06-06 09:05:30 -04:00
Danny Brown 338ecb43ae Merge pull request #532 from OHIF/dependabot/npm_and_yarn/extensions/ohif-vtk-extension/js-yaml-3.13.1
build(deps): bump js-yaml from 3.12.1 to 3.13.1 in /extensions/ohif-vtk-extension
2019-06-06 09:05:17 -04:00
dependabot[bot] bf2dd92deb build(deps): bump js-yaml in /extensions/ohif-cornerstone-extension
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.12.0 to 3.13.1.
- [Release notes](https://github.com/nodeca/js-yaml/releases)
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.12.0...3.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2019-06-06 13:02:50 +00:00
Danny Brown f1b7f42ef7 Merge branch 'master' into dependabot/npm_and_yarn/extensions/ohif-vtk-extension/js-yaml-3.13.1 2019-06-06 09:01:51 -04:00
Danny Brown ff98a9dc4f Merge pull request #534 from OHIF/dependabot/npm_and_yarn/extensions/ohif-dicom-pdf-extension/handlebars-4.1.2
build(deps): bump handlebars from 4.0.12 to 4.1.2 in /extensions/ohif-dicom-pdf-extension
2019-06-06 09:01:29 -04:00
dependabot[bot] bd870a46c7 build(deps): bump js-yaml in /extensions/ohif-vtk-extension
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.12.1 to 3.13.1.
- [Release notes](https://github.com/nodeca/js-yaml/releases)
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.12.1...3.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2019-06-06 12:58:04 +00:00
Danny Brown a9636410ec Merge branch 'master' into dependabot/npm_and_yarn/extensions/ohif-dicom-pdf-extension/handlebars-4.1.2 2019-06-06 08:57:00 -04:00
Danny Brown 4aa591aaaf Merge pull request #533 from OHIF/dependabot/npm_and_yarn/extensions/ohif-dicom-html-extension/handlebars-4.1.2
build(deps): bump handlebars from 4.0.12 to 4.1.2 in /extensions/ohif-dicom-html-extension
2019-06-06 08:56:41 -04:00
dependabot[bot] 04f03f10de build(deps): bump handlebars in /extensions/ohif-dicom-pdf-extension
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.0.12 to 4.1.2.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.0.12...v4.1.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-06-06 11:05:33 +00:00
dependabot[bot] dfbabb8c93 build(deps): bump handlebars in /extensions/ohif-dicom-html-extension
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.0.12 to 4.1.2.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.0.12...v4.1.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-06-06 11:05:26 +00:00
dannyrb f16812c81f Remove FA external dep include 2019-06-05 21:30:18 -04:00
dannyrb 49fe195089 Change HotkeyDefinition to include label 2019-06-05 21:29:50 -04:00
Erik Ziegler bbc598323e fix(initWebWorkers): Fix duplicate slashes for web worker paths (#527) 2019-06-05 22:44:14 +02:00
Rodrigo Antinarelli a747590ab8 fix typo 2019-06-05 17:36:38 -03:00
Rodrigo Antinarelli a11fae01dc use t prop from withTranslation 2019-06-05 17:09:54 -03:00
Rodrigo Antinarelli 520f07ec23 remove yalc react-viewerbase 2019-06-05 17:09:35 -03:00
Erik Ziegler d20492ac62 docs(circleci): Set up automatic deploys to GCP for hosting viewer.ohif.org (#491) 2019-06-05 22:08:28 +02:00
dannyrb 347680fdf5 Setting an active tool 2019-06-05 15:57:00 -04:00
diego0020 1c3f3cfcf6 initial prototype 2019-06-05 09:11:13 -05:00
romulo bordezani 236a115112 i18n - Multiple languages overrides 2019-06-04 18:16:07 -03:00
romulo bordezani 1874f93bcc i18n - Multiple languages overrides 2019-06-04 12:34:57 -03:00
romulo bordezani d678a617dc i18n - extension extraction 2019-06-03 19:56:59 -03:00
João Felipe Medeiros Moreira aff74bcee4 Merge branch 'feature/i18n-basics' of github.com:romulobordezani/Viewers into feature/i18n-basics 2019-06-03 18:02:11 -03:00
João Felipe Medeiros Moreira 99c95fc1e1 Creating spanish translation 2019-06-03 18:02:01 -03:00
romulo bordezani 543d8d33c1 i18n - extension extraction 2019-06-03 17:56:36 -03:00
dannyrb a636df8fdc Pass in CommandsManager config 2019-06-03 15:41:49 -04:00
dannyrb 3f5660722e Defaults for hotkeys 2019-06-03 14:27:03 -04:00
dannyrb afa6d78e42 push WIP 2019-06-03 13:22:05 -04:00
dannyrb 66e3b9f857 Commands list for cornerstone extension 2019-06-03 12:43:36 -04:00
dannyrb 9b838ab326 Provide store to commands manager; hard code active contexts 2019-06-03 12:22:25 -04:00
dannyrb 9326b5e63d Actions and reducers for managing UI contexts 2019-06-03 12:22:06 -04:00
dannyrb 56de51a21d Kill old code 2019-06-03 12:21:50 -04:00
dannyrb 03d66233ff Make sure we're registering a hotkey for a command that exists 2019-06-02 23:04:24 -04:00
dannyrb 6b0ef0904e Shift initialization of OHIF classes to app.js 2019-06-02 22:44:13 -04:00
dannyrb c1f8984c1b Switch folder; dependency injection; note about moving to extensions 2019-06-02 22:43:04 -04:00
dannyrb b0706e5544 Playing with a hotkeys + commands setup and config 2019-06-02 15:44:27 -04:00
dannyrb d29f996e61 formatting 2019-06-02 15:44:01 -04:00
dannyrb fabe981855 WIP hotkeys code 2019-05-31 22:09:05 -04:00
dannyrb d9e45261f3 Registering some initial commands 2019-05-31 16:25:10 -04:00
dannyrb ae0858bdd3 Shift store init to own directory 2019-05-31 11:55:44 -04:00
romulo bordezani 376b2c518a i18n basic setup 2019-05-30 15:41:15 -03:00
189 changed files with 17741 additions and 8622 deletions

No files matched your search

+31 -2
View File
@@ -11,7 +11,8 @@
"avatar_url": "https://avatars3.githubusercontent.com/u/607793?v=4",
"profile": "https://github.com/swederik",
"contributions": [
"code"
"code",
"infra"
]
},
{
@@ -38,7 +39,8 @@
"avatar_url": "https://avatars1.githubusercontent.com/u/5797588?v=4",
"profile": "http://dannyrb.com/",
"contributions": [
"code"
"code",
"infra"
]
},
{
@@ -58,6 +60,33 @@
"contributions": [
"question"
]
},
{
"login": "diego0020",
"name": "diego0020",
"avatar_url": "https://avatars3.githubusercontent.com/u/7297450?v=4",
"profile": "https://github.com/diego0020",
"contributions": [
"code"
]
},
{
"login": "dlwire",
"name": "David Wire",
"avatar_url": "https://avatars3.githubusercontent.com/u/1167291?v=4",
"profile": "https://github.com/dlwire",
"contributions": [
"code"
]
},
{
"login": "jfmedeiros1820",
"name": "João Felipe de Medeiros Moreira",
"avatar_url": "https://avatars1.githubusercontent.com/u/2211708?v=4",
"profile": "https://github.com/jfmedeiros1820",
"contributions": [
"test"
]
}
],
"contributorsPerLine": 7,
+104 -6
View File
@@ -21,7 +21,7 @@ jobs:
# Download and cache dependencies
- checkout
- restore_cache:
name: Restore Yarn Package Cache
name: Restore Yarn and Cypress Package Cache
keys:
# when lock file changes, use increasingly general patterns to restore cache
- yarn-packages-v1-{{ .Branch }}-{{ checksum "yarn.lock" }}
@@ -33,14 +33,14 @@ jobs:
- save_cache:
name: Save Yarn Package Cache
paths:
- ~/.cache/yarn
- ~/.cache ## Cache yarn and Cypress
key: yarn-packages-v1-{{ .Branch }}-{{ checksum "yarn.lock" }}
# Build & Test
- run: yarn build:package:ci
# https://www.viget.com/articles/using-junit-on-circleci-2-0-with-jest-and-eslint/
- run:
name: 'JavaScript Test Suite'
command: yarn test:ci
command: yarn test:unit:ci
environment:
JEST_JUNIT_OUTPUT: 'reports/junit/js-test-results.xml'
# Store result
@@ -53,6 +53,29 @@ jobs:
root: ~/repo
paths: .
e2e_test:
working_directory: ~/repo
docker:
- image: cypress/base:8
environment:
## this enables colors in the output
TERM: xterm
steps:
- attach_workspace:
at: ~/repo
- restore_cache:
name: Restore Yarn and Cypress Package Cache
keys:
# when lock file changes, use increasingly general patterns to restore cache
- yarn-packages-v1-{{ .Branch }}-{{ checksum "yarn.lock" }}
- yarn-packages-v1-{{ .Branch }}-
- yarn-packages-v1-
# - run: $(yarn bin)/cypress run --record
# Shouldn't be needed if we're using a package cache that contains Cypress
# Could do a check here, if it doesn't exist, install cypress?
- run: yarn install
- run: yarn run test:e2e:ci
npm_publish:
<<: *defaults
steps:
@@ -122,6 +145,69 @@ jobs:
docker push ohif/$IMAGE_NAME:latest
fi
build_demo_site:
<<: *defaults
steps:
# Download and cache dependencies
- checkout
- restore_cache:
name: Restore Yarn Package Cache
keys:
# when lock file changes, use increasingly general patterns to restore cache
- yarn-packages-v1-{{ .Branch }}-{{ checksum "yarn.lock" }}
- yarn-packages-v1-{{ .Branch }}-
- yarn-packages-v1-
- run:
name: Install Dependencies
command: yarn install --frozen-lockfile
- save_cache:
name: Save Yarn Package Cache
paths:
- ~/.cache/yarn
key: yarn-packages-v1-{{ .Branch }}-{{ checksum "yarn.lock" }}
# Build & Test
- run:
name: 'Build Demo Site, Upload SourceMaps, Send Deploy Notification'
command: |
yarn build:demo:ci
perl -i -pe 's#</head>#`cat .circleci/rollbar.html` #e' build/index.html
export FILE_1=$(find ./build/static/js -type f -name "2.*.js" -exec basename {} \;)
export FILE_MAIN=$(find ./build/static/js -type f -name "main.*.js" -exec basename {} \;)
export FILE_RUNTIME_MAIN=$(find ./build/static/js -type f -name "runtime~main.*.js" -exec basename {} \;)
curl https://api.rollbar.com/api/1/sourcemap -F source_map=@build/static/js/$FILE_1.map -F access_token=$ROLLBAR_TOKEN -F version=$CIRCLE_SHA1 -F minified_url=https://$GOOGLE_STORAGE_BUCKET/static/js/$FILE_1
curl https://api.rollbar.com/api/1/sourcemap -F source_map=@build/static/js/$FILE_MAIN.map -F access_token=$ROLLBAR_TOKEN -F version=$CIRCLE_SHA1 -F minified_url=https://$GOOGLE_STORAGE_BUCKET/static/js/$FILE_MAIN
curl https://api.rollbar.com/api/1/sourcemap -F source_map=@build/static/js/$FILE_RUNTIME_MAIN.map -F access_token=$ROLLBAR_TOKEN -F version=$CIRCLE_SHA1 -F minified_url=https://$GOOGLE_STORAGE_BUCKET/static/js/$FILE_RUNTIME_MAIN
curl --request POST https://api.rollbar.com/api/1/deploy/ -F access_token=$ROLLBAR_TOKEN -F environment=$GOOGLE_STORAGE_BUCKET -F revision=$CIRCLE_SHA1 -F local_username=CircleCI
# Persist :+1:
- persist_to_workspace:
root: ~/repo
paths: .
demo_site_publish:
working_directory: ~/repo
docker:
- image: google/cloud-sdk
steps:
- attach_workspace:
at: ~/repo
- setup_remote_docker:
docker_layer_caching: true
- run:
name: Deploy latest version to viewer.ohif.org
command: |
# This file will exist if a new version was published by
# our `semantic-release` command in the previous job
#if [[ ! -e tmp/updated-version.txt ]]; then
# exit 0
#else
echo $GCLOUD_SERVICE_KEY | gcloud auth activate-service-account --key-file=-
gcloud --quiet config set project ${GOOGLE_PROJECT_ID}
gcloud --quiet config set compute/zone ${GOOGLE_COMPUTE_ZONE}
gsutil -m rm gs://$GOOGLE_STORAGE_BUCKET/**
gsutil -m rsync -R build gs://$GOOGLE_STORAGE_BUCKET
#fi
workflows:
version: 2
@@ -143,13 +229,25 @@ workflows:
filters:
branches:
only: master
- e2e_test:
requires:
- build_and_test
# Update NPM
- npm_publish:
requires:
- build_and_test
- e2e_test
# Update docs.ohif.org
- docs_publish:
requires:
- build_and_test
- e2e_test
# Update hub.docker.org
- docker_publish:
requires:
- build_and_test
- npm_publish
# Update viewer.ohif.org
- build_demo_site:
requires:
- e2e_test
- demo_site_publish:
requires:
- build_demo_site
+15
View File
@@ -0,0 +1,15 @@
<script>
// Note: This is a client access token so there is no issue with having it publicly available
var _rollbarConfig = {
accessToken: "739c64cd39e84592ba062bc29aac9769",
captureUncaught: true,
captureUnhandledRejections: true,
payload: {
environment: "viewer.ohif.org"
}
};
// Rollbar Snippet
!function(r){var e={};function o(n){if(e[n])return e[n].exports;var t=e[n]={i:n,l:!1,exports:{}};return r[n].call(t.exports,t,t.exports,o),t.l=!0,t.exports}o.m=r,o.c=e,o.d=function(r,e,n){o.o(r,e)||Object.defineProperty(r,e,{enumerable:!0,get:n})},o.r=function(r){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(r,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(r,"__esModule",{value:!0})},o.t=function(r,e){if(1&e&&(r=o(r)),8&e)return r;if(4&e&&"object"==typeof r&&r&&r.__esModule)return r;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:r}),2&e&&"string"!=typeof r)for(var t in r)o.d(n,t,function(e){return r[e]}.bind(null,t));return n},o.n=function(r){var e=r&&r.__esModule?function(){return r.default}:function(){return r};return o.d(e,"a",e),e},o.o=function(r,e){return Object.prototype.hasOwnProperty.call(r,e)},o.p="",o(o.s=0)}([function(r,e,o){var n=o(1),t=o(4);_rollbarConfig=_rollbarConfig||{},_rollbarConfig.rollbarJsUrl=_rollbarConfig.rollbarJsUrl||"https://cdnjs.cloudflare.com/ajax/libs/rollbar.js/2.7.1/rollbar.min.js",_rollbarConfig.async=void 0===_rollbarConfig.async||_rollbarConfig.async;var a=n.setupShim(window,_rollbarConfig),l=t(_rollbarConfig);window.rollbar=n.Rollbar,a.loadFull(window,document,!_rollbarConfig.async,_rollbarConfig,l)},function(r,e,o){var n=o(2);function t(r){return function(){try{return r.apply(this,arguments)}catch(r){try{console.error("[Rollbar]: Internal error",r)}catch(r){}}}}var a=0;function l(r,e){this.options=r,this._rollbarOldOnError=null;var o=a++;this.shimId=function(){return o},"undefined"!=typeof window&&window._rollbarShims&&(window._rollbarShims[o]={handler:e,messages:[]})}var i=o(3),d=function(r,e){return new l(r,e)},c=function(r){return new i(d,r)};function s(r){return t(function(){var e=Array.prototype.slice.call(arguments,0),o={shim:this,method:r,args:e,ts:new Date};window._rollbarShims[this.shimId()].messages.push(o)})}l.prototype.loadFull=function(r,e,o,n,a){var l=!1,i=e.createElement("script"),d=e.getElementsByTagName("script")[0],c=d.parentNode;i.crossOrigin="",i.src=n.rollbarJsUrl,o||(i.async=!0),i.onload=i.onreadystatechange=t(function(){if(!(l||this.readyState&&"loaded"!==this.readyState&&"complete"!==this.readyState)){i.onload=i.onreadystatechange=null;try{c.removeChild(i)}catch(r){}l=!0,function(){var e;if(void 0===r._rollbarDidLoad){e=new Error("rollbar.js did not load");for(var o,n,t,l,i=0;o=r._rollbarShims[i++];)for(o=o.messages||[];n=o.shift();)for(t=n.args||[],i=0;i<t.length;++i)if("function"==typeof(l=t[i])){l(e);break}}"function"==typeof a&&a(e)}()}}),c.insertBefore(i,d)},l.prototype.wrap=function(r,e,o){try{var n;if(n="function"==typeof e?e:function(){return e||{}},"function"!=typeof r)return r;if(r._isWrap)return r;if(!r._rollbar_wrapped&&(r._rollbar_wrapped=function(){o&&"function"==typeof o&&o.apply(this,arguments);try{return r.apply(this,arguments)}catch(o){var e=o;throw e&&("string"==typeof e&&(e=new String(e)),e._rollbarContext=n()||{},e._rollbarContext._wrappedSource=r.toString(),window._rollbarWrappedError=e),e}},r._rollbar_wrapped._isWrap=!0,r.hasOwnProperty))for(var t in r)r.hasOwnProperty(t)&&(r._rollbar_wrapped[t]=r[t]);return r._rollbar_wrapped}catch(e){return r}};for(var p="log,debug,info,warn,warning,error,critical,global,configure,handleUncaughtException,handleUnhandledRejection,captureEvent,captureDomContentLoaded,captureLoad".split(","),u=0;u<p.length;++u)l.prototype[p[u]]=s(p[u]);r.exports={setupShim:function(r,e){if(r){var o=e.globalAlias||"Rollbar";if("object"==typeof r[o])return r[o];r._rollbarShims={},r._rollbarWrappedError=null;var a=new c(e);return t(function(){e.captureUncaught&&(a._rollbarOldOnError=r.onerror,n.captureUncaughtExceptions(r,a,!0),n.wrapGlobals(r,a,!0)),e.captureUnhandledRejections&&n.captureUnhandledRejections(r,a,!0);var t=e.autoInstrument;return!1!==e.enabled&&(void 0===t||!0===t||"object"==typeof t&&t.network)&&r.addEventListener&&(r.addEventListener("load",a.captureLoad.bind(a)),r.addEventListener("DOMContentLoaded",a.captureDomContentLoaded.bind(a))),r[o]=a,a})()}},Rollbar:c}},function(r,e){function o(r,e,o){if(e.hasOwnProperty&&e.hasOwnProperty("addEventListener")){for(var n=e.addEventListener;n._rollbarOldAdd&&n.belongsToShim;)n=n._rollbarOldAdd;var t=function(e,o,t){n.call(this,e,r.wrap(o),t)};t._rollbarOldAdd=n,t.belongsToShim=o,e.addEventListener=t;for(var a=e.removeEventListener;a._rollbarOldRemove&&a.belongsToShim;)a=a._rollbarOldRemove;var l=function(r,e,o){a.call(this,r,e&&e._rollbar_wrapped||e,o)};l._rollbarOldRemove=a,l.belongsToShim=o,e.removeEventListener=l}}r.exports={captureUncaughtExceptions:function(r,e,o){if(r){var n;if("function"==typeof e._rollbarOldOnError)n=e._rollbarOldOnError;else if(r.onerror){for(n=r.onerror;n._rollbarOldOnError;)n=n._rollbarOldOnError;e._rollbarOldOnError=n}var t=function(){var o=Array.prototype.slice.call(arguments,0);!function(r,e,o,n){r._rollbarWrappedError&&(n[4]||(n[4]=r._rollbarWLine truncated
// End Rollbar Snippet
</script>
</head>
+12
View File
@@ -0,0 +1,12 @@
# ABOUT:
# https://docs.codecov.io/docs/codecov-yaml
#
#
# COMMIT STATUS:
# https://docs.codecov.io/docs/commit-status
coverage:
status:
project:
default:
threshold: 0.10%
patch: off
+9 -7
View File
@@ -1,16 +1,18 @@
{
"extends": [
"react-app",
"eslint:recommended",
"plugin:react/recommended"
],
"extends": ["react-app", "eslint:recommended", "plugin:react/recommended"],
"parser": "babel-eslint",
"env": {
"jest": true
},
"settings": {
"react": {
"version": "detect",
},
"version": "detect"
}
},
"globals": {
"cy": true,
"context": true,
"Cypress": true,
"assert": true
}
}
+40 -1
View File
@@ -1 +1,40 @@
* text eol=lf
# These settings are for any web project
# Handle line endings automatically for files detected as text
# and leave all files detected as binary untouched.
* text=auto
# Force the following filetypes to have unix eols, so Windows does not break them
*.* text eol=lf
# Windows forced line-endings
/.idea/* text eol=crlf
#
## These files are binary and should be left untouched
#
# (binary is a macro for -text -diff)
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.mov binary
*.mp4 binary
*.mp3 binary
*.flv binary
*.fla binary
*.swf binary
*.gz binary
*.zip binary
*.7z binary
*.ttf binary
*.eot binary
*.woff binary
*.pyc binary
*.pdf binary
*.ez binary
*.bz2 binary
*.swp binary
*.fig binary
+3
View File
@@ -25,3 +25,6 @@ yarn-error.log
sampledata/
example/deps/
docker/dcm4che/dcm4che-arc
# Cypress test results
cypress/videos/
+33 -2
View File
@@ -21,7 +21,7 @@
[![CircleCI][circleci-image]][circleci-url]
[![codecov][codecov-image]][codecov-url]
[![All Contributors](https://img.shields.io/badge/all_contributors-6-orange.svg?style=flat-square)](#contributors)
[![All Contributors](https://img.shields.io/badge/all_contributors-9-orange.svg?style=flat-square)](#contributors)
[![code style: prettier][prettier-image]][prettier-url]
[![semantic-release][semantic-image]][semantic-url]
@@ -98,6 +98,36 @@ hosted PACS and test data,
[check out our Essential: Getting Started](https://docs.ohif.org/essentials/getting-started.html)
guide.
### E2E Tests
Using [Cypress](https://www.cypress.io/) to create End-to-End tests and check whether the application flow is performing correctly, ensuring that the integrated components are working as expected.
#### Why Cypress?
Cypress is a next generation front end testing tool built for the modern web.
With Cypress is easy to set up, write, run and debug tests
It allow us to write different types of tests:
- End-to-End tests
- Integration tests
- Unit tets
All tests must be in `./cypress/integration` folder.
Commands to run the tests:
```js
// Open Cypress Dashboard that provides insight into what happened when your tests ran
yarn run cy
// Run all tests using Electron browser headless
yarn run cy:run
// Run all tests in CI mode
yarn run cy:run:ci
```
### Contributing
> Large portions of the Viewer's functionality are maintained in other
@@ -190,7 +220,7 @@ Thanks goes to these wonderful people
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore -->
<table><tr><td align="center"><a href="https://github.com/swederik"><img src="https://avatars3.githubusercontent.com/u/607793?v=4" width="100px;" alt="Erik Ziegler"/><br /><sub><b>Erik Ziegler</b></sub></a><br /><a href="https://github.com/OHIF/Viewers/commits?author=swederik" title="Code">💻</a></td><td align="center"><a href="https://github.com/evren217"><img src="https://avatars1.githubusercontent.com/u/4920551?v=4" width="100px;" alt="Evren Ozkan"/><br /><sub><b>Evren Ozkan</b></sub></a><br /><a href="https://github.com/OHIF/Viewers/commits?author=evren217" title="Code">💻</a></td><td align="center"><a href="https://github.com/galelis"><img src="https://avatars3.githubusercontent.com/u/2378326?v=4" width="100px;" alt="Gustavo André Lelis"/><br /><sub><b>Gustavo André Lelis</b></sub></a><br /><a href="https://github.com/OHIF/Viewers/commits?author=galelis" title="Code">💻</a></td><td align="center"><a href="http://dannyrb.com/"><img src="https://avatars1.githubusercontent.com/u/5797588?v=4" width="100px;" alt="Danny Brown"/><br /><sub><b>Danny Brown</b></sub></a><br /><a href="https://github.com/OHIF/Viewers/commits?author=dannyrb" title="Code">💻</a></td><td align="center"><a href="https://github.com/all-contributors/all-contributors-bot"><img src="https://avatars3.githubusercontent.com/u/46843839?v=4" width="100px;" alt="allcontributors[bot]"/><br /><sub><b>allcontributors[bot]</b></sub></a><br /><a href="https://github.com/OHIF/Viewers/commits?author=allcontributors" title="Documentation">📖</a></td><td align="center"><a href="https://www.linkedin.com/in/siliconvalleynextgeneration/"><img src="https://avatars0.githubusercontent.com/u/1230575?v=4" width="100px;" alt="Esref Durna"/><br /><sub><b>Esref Durna</b></sub></a><br /><a href="#question-EsrefDurna" title="Answering Questions">💬</a></td></tr></table>
<table><tr><td align="center"><a href="https://github.com/swederik"><img src="https://avatars3.githubusercontent.com/u/607793?v=4" width="100px;" alt="Erik Ziegler"/><br /><sub><b>Erik Ziegler</b></sub></a><br /><a href="https://github.com/OHIF/Viewers/commits?author=swederik" title="Code">💻</a> <a href="#infra-swederik" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td><td align="center"><a href="https://github.com/evren217"><img src="https://avatars1.githubusercontent.com/u/4920551?v=4" width="100px;" alt="Evren Ozkan"/><br /><sub><b>Evren Ozkan</b></sub></a><br /><a href="https://github.com/OHIF/Viewers/commits?author=evren217" title="Code">💻</a></td><td align="center"><a href="https://github.com/galelis"><img src="https://avatars3.githubusercontent.com/u/2378326?v=4" width="100px;" alt="Gustavo André Lelis"/><br /><sub><b>Gustavo André Lelis</b></sub></a><br /><a href="https://github.com/OHIF/Viewers/commits?author=galelis" title="Code">💻</a></td><td align="center"><a href="http://dannyrb.com/"><img src="https://avatars1.githubusercontent.com/u/5797588?v=4" width="100px;" alt="Danny Brown"/><br /><sub><b>Danny Brown</b></sub></a><br /><a href="https://github.com/OHIF/Viewers/commits?author=dannyrb" title="Code">💻</a> <a href="#infra-dannyrb" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td><td align="center"><a href="https://github.com/all-contributors/all-contributors-bot"><img src="https://avatars3.githubusercontent.com/u/46843839?v=4" width="100px;" alt="allcontributors[bot]"/><br /><sub><b>allcontributors[bot]</b></sub></a><br /><a href="https://github.com/OHIF/Viewers/commits?author=allcontributors" title="Documentation">📖</a></td><td align="center"><a href="https://www.linkedin.com/in/siliconvalleynextgeneration/"><img src="https://avatars0.githubusercontent.com/u/1230575?v=4" width="100px;" alt="Esref Durna"/><br /><sub><b>Esref Durna</b></sub></a><br /><a href="#question-EsrefDurna" title="Answering Questions">💬</a></td><td align="center"><a href="https://github.com/diego0020"><img src="https://avatars3.githubusercontent.com/u/7297450?v=4" width="100px;" alt="diego0020"/><br /><sub><b>diego0020</b></sub></a><br /><a href="https://github.com/OHIF/Viewers/commits?author=diego0020" title="Code">💻</a></td></tr><tr><td align="center"><a href="https://github.com/dlwire"><img src="https://avatars3.githubusercontent.com/u/1167291?v=4" width="100px;" alt="David Wire"/><br /><sub><b>David Wire</b></sub></a><br /><a href="https://github.com/OHIF/Viewers/commits?author=dlwire" title="Code">💻</a></td><td align="center"><a href="https://github.com/jfmedeiros1820"><img src="https://avatars1.githubusercontent.com/u/2211708?v=4" width="100px;" alt="João Felipe de Medeiros Moreira"/><br /><sub><b>João Felipe de Medeiros Moreira</b></sub></a><br /><a href="https://github.com/OHIF/Viewers/commits?author=jfmedeiros1820" title="Tests">⚠️</a></td></tr></table>
<!-- ALL-CONTRIBUTORS-LIST:END -->
@@ -261,4 +291,5 @@ Links:
[requests-feature]: https://github.com/OHIF/Viewers/labels/enhancement
[good-first-issue]: https://github.com/OHIF/Viewers/labels/good%20first%20issue
[google-group]: https://groups.google.com/forum/#!forum/cornerstone-platform
<!-- prettier-ignore-end -->
+5
View File
@@ -0,0 +1,5 @@
{
"baseUrl": "http://localhost:5000",
"video": true,
"projectId": "4oe38f"
}
+5
View File
@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}
@@ -0,0 +1,16 @@
describe('OHIFStandaloneViewer', () => {
beforeEach(() => {
cy.visit('/');
});
it('loads route with at least 2 rows', () => {
cy.get('#studyListData tr')
.its('length')
.should('be.gt', 2);
});
it('first 2 rows has values', () => {
cy.get('#studyListData > :nth-child(1) > .patientId').should('be.visible');
cy.get('#studyListData > :nth-child(2) > .patientId').should('be.visible');
});
});
+22
View File
@@ -0,0 +1,22 @@
describe('ViewerRouting', () => {
beforeEach(() => {
cy.visit('/');
cy.contains('Study List');
cy.get('#studyListData > :nth-child(1) > .patientId').click();
});
it('thumbnails list has more than 2 items', () => {
cy.get('.scrollable-study-thumbnails div.ThumbnailEntryContainer')
.its('length')
.should('be.gte', 2);
});
it('loads route with at least 2 thumbnails', () => {
cy.get(
':nth-child(1) > .ThumbnailEntry > .p-x-1 > .ImageThumbnail > .image-thumbnail-canvas > canvas'
).should('be.visible');
cy.get(
':nth-child(2) > .ThumbnailEntry > .p-x-1 > .ImageThumbnail > .image-thumbnail-canvas > canvas'
).should('be.visible');
});
});
+27
View File
@@ -0,0 +1,27 @@
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
on('before:browser:launch', (browser = {}, args) => {
if (browser.name === 'chrome') {
// `args` is an araay of all the arguments
// that will be passed to Chrome when it launchers
args.push('--start-fullscreen');
// whatever you return here becomes the new args
return args;
}
});
};
+25
View File
@@ -0,0 +1,25 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This is will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
+20
View File
@@ -0,0 +1,20 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands';
// Alternatively you can use CommonJS syntax:
// require('./commands')
+3 -14
View File
@@ -1,17 +1,6 @@
version: '3.5'
services:
proxy:
image: nginx:1.15-alpine
ports:
- 8899:80
volumes:
- ./config/nginx.conf:/etc/nginx/nginx.conf:ro
restart: unless-stopped
# LINK: https://hub.docker.com/r/jodogne/orthanc-plugins/
# TODO: Update to use Postgres
# https://github.com/mrts/docker-postgresql-multiple-databases
orthanc:
image: jodogne/orthanc-plugins:1.5.6
hostname: orthanc
@@ -20,7 +9,7 @@ services:
- ./config/orthanc.json:/etc/orthanc/orthanc.json:ro
# Persist data
- ./volumes/orthanc-db/:/var/lib/orthanc/db/
# ports:
# - '4242:4242' # DICOM
# - '8042:8042' # Web
ports:
- '4242:4242' # DICOM
- '8042:8042' # Web
restart: unless-stopped
+11 -1
View File
@@ -1,4 +1,14 @@
##### Looking for a Deploy Preview? - <a onclick="function redirect() { window.location.href='/demo/'; } redirect();">Deploy Preview for Viewer</a>
<div class='row'>
<div class='column' style='text-align: right; padding: 0 20px'>
<strong>Looking for a Deploy Preview?</strong>
<a onclick="function redirect() { window.location.href='/demo/'; } redirect();">Deploy Preview for Viewer</a>
</div>
<div class='column' style='text-align: left; padding: 0 20px'>
<a href="https://www.netlify.com">
<img src="https://www.netlify.com/img/global/badges/netlify-color-bg.svg"/>
</a>
</div>
</div>
> ATTENTION! You are looking at the docs for the `React` version of the OHIF
> Viewer. If you're looking for the `Meteor` version's documentation (now
+1
View File
@@ -6,6 +6,7 @@
- [Data Source](essentials/data-source.md)
- [Configuration](essentials/configuration.md)
- [Themeing](essentials/themeing.md)
- [Translating](essentials/translating.md)
- [Troubleshooting](essentials/troubleshooting.md)
- [Scope of Project](essentials/scope-of-project.md)
+147 -30
View File
@@ -1,46 +1,134 @@
# Extensions
Extensions add new functionality to the viewer by registering one or more modules. They go one step further than configuration in that they allow us to inject custom React components, so long as they adhere to the module's interface. This can be something as simple as adding a new button to the toolbar, or as complex as a new viewport capable of rendering volumes in 3D.
Extensions add new functionality to the viewer by registering one or more
modules. They go one step further than configuration in that they allow us to
inject custom React components, so long as they adhere to the module's
interface. This can be something as simple as adding a new button to the
toolbar, or as complex as a new viewport capable of rendering volumes in 3D.
- [Overview](#overview)
- [Modules](#modules)
- [Commands](#commands)
- [Hotkeys](#hotkeys)
- [Toolbar](#toolbar)
- [Panel](#panel)
- [Viewport](#viewport)
- [SOP Class Handler](#sopclasshandler)
## Overview
At a glance, an extension is a class or object that has a `getExtensionId()` method, and one or more "module" methods. You can find an abbreviated extension below, or [view the source](https://github.com/OHIF/Viewers/blob/react/extensions/ohif-cornerstone-extension/src/OHIFCornerstoneExtension.js#L32-L65) of our `cornerstone` viewport extension.
At a glance, an extension is a javascript object that has an `id` property, and
one or more "module" methods. You can find an abbreviated extension below, or
[view the source][example-ext-src] of our example extension.
```js
class myCustomExtension {
export default {
/**
* Only required property. Should be a unique value across all extensions.
*/
id: 'example-extension',
/** Required */
getExtensionId: () => 'my-extension-id';
/**
* Registers one or more named commands scoped to a context. Commands are
* the primary means for...
*/
getCommandsModule() {
return {
defaultContext: 'VIEWER'
actions: { ... },
definitions: { ... }
}
},
/** React component that receives props from ConnectLayoutManager
* If more than one viewport module is registered, SopClassHandler
* is used to help determine which component is used */
getViewportModule: () => reactViewportComponent;
/**
* Allows you to provide toolbar definitions that will be merged with any
* existing application toolbar configuration. Used to determine which
* buttons should be visible when, their order, what happens when they're
* clicked, etc.
*/
getToolbarModule() {
return {
definitions: [ ... ],
defaultContext: 'ACTIVE_VIEWPORT::CORNERSTONE'
}
}
/** React component that adds buttons/behavior to the viewer Toolbar */
getToolbarModule: () => reactToolbarComponent;
/**
* Not yet implemented
*/
getPanelModule: () => null,
/**
* Registers a ReactComponent that should be used to render data in a
* Viewport. The first registered viewport is our "default viewport". If
* more than one viewport is registered, we use `SopClassHandlers` to
* determine which viewport should be used.
*/
getViewportModule: () => reactViewportComponent,
/** Provides a whitelist of SOPClassUIDs the viewport is capable of rendering.
* Can modify default behavior for methods like `getDisplaySetFromSeries` */
getSopClassHandler: () => {
id: 'some-other-unique-id',
type: PLUGIN_TYPES.SOP_CLASS_HANDLER,
sopClassUids: ['string'],
getDisplaySetFromSeries: (series, study, dicomWebClient, authorizationHeaders) => ...
};
// Not yet used
getPanelModule: () => null;
sopClassUids: [ ... ],
getDisplaySetFromSeries: (series, study, dicomWebClient, authorizationHeaders) => { ... }
},
}
```
### Modules
There are a few different kinds of modules. Each kind of module allows us to extend the viewer in a different way, and provides a consistent API for us to do so. You can find a full list of the [different types of modules `in ohif-core`](https://github.com/OHIF/ohif-core/blob/43c08a29eff3fb646a0e83a03a236ddd84f4a6e8/src/plugins.js#L1-L6). Information on each type of module, it's API, and how we determine when/where it should be used is included below:
There are a few different module types. Each module type allows us to extend the
viewer in a different way, and provides a consistent API for us to do so. You
can find a full list of the different types of modules
[`in ohif-core`][module-types]. Information on each type of module, it's API,
and how we determine when/where it should be used is included below.
> NOTE: Modifying the extensions/modules registered to the OHIF Viewer currently
> requires us to import and pass extensions to the ExtensionManager in
> `src/App.js`, then rebuild the application. Long-term, we intend to make it
> possible to accomplish this without a build step.
#### Commands
The Commands Module allows us to register one or more commands scoped to
specific contexts. Commands can be run by [hotkeys][#], [toolbar buttons][#],
and any registered custom react component (like a [viewport][#] or [panel][#]).
Here is a simple example commands module:
```js
{
getCommandsModule() {
return {
actions: {
speak: ({ viewports, words }) => {
console.log(viewports, words);
},
},
definitions: {
rotateViewportCW: {
commandFn: actions.rotateViewport,
storeContexts: ['viewports'],
options: { rotation: 90 }
},
rotateViewportCCW: {
commandFn: actions.rotateViewport,
storeContexts: ['viewports'],
options: { rotation: -90 },
context: 'ACTIVE_VIEWER::CORNERSTONE'
},
},
defaultContext: 'VIEWER'
}
}
}
```
#### Viewport
An extension can register a Viewport Module by providing a `getViewportModule()` method that returns a React Component. The React component will receive the following props:
An extension can register a Viewport Module by providing a `getViewportModule()`
method that returns a React Component. The React component will receive the
following props:
```js
children: PropTypes.arrayOf(PropTypes.element)
@@ -52,7 +140,8 @@ children: PropTypes.node,
customProps: PropTypes.object
```
Viewport components are managed by the `LayoutManager`. Which Viewport component is used depends on:
Viewport components are managed by the `LayoutManager`. Which Viewport component
is used depends on:
- The Layout Configuration
- Registered SopClassHandlers
@@ -62,11 +151,15 @@ Viewport components are managed by the `LayoutManager`. Which Viewport component
<center><i>An example of three Viewports</i></center>
For a complete example implementation, [check out the OHIFCornerstoneViewport](https://github.com/OHIF/Viewers/blob/react/extensions/ohif-cornerstone-extension/src/OHIFCornerstoneViewport.js).
For a complete example implementation,
[check out the OHIFCornerstoneViewport](https://github.com/OHIF/Viewers/blob/react/extensions/ohif-cornerstone-extension/src/OHIFCornerstoneViewport.js).
#### Toolbar
An extension can register a Toolbar Module by providing a `getToolbarModule()` method that returns a React Component. The component does not receive any props. If you want to modify or react to state, you will need to connect to the redux store.
An extension can register a Toolbar Module by providing a `getToolbarModule()`
method that returns a React Component. The component does not receive any props.
If you want to modify or react to state, you will need to connect to the redux
store.
![Toolbar Extension](../assets/img/extensions-toolbar.gif)
@@ -74,7 +167,8 @@ An extension can register a Toolbar Module by providing a `getToolbarModule()` m
Toolbar components are rendered in the `ToolbarRow` component.
For a complete example implementation, [check out the OHIFCornerstoneViewport's Toolbar Module](https://github.com/OHIF/Viewers/blob/react/extensions/ohif-cornerstone-extension/src/ToolbarModule.js).
For a complete example implementation,
[check out the OHIFCornerstoneViewport's Toolbar Module](https://github.com/OHIF/Viewers/blob/react/extensions/ohif-cornerstone-extension/src/ToolbarModule.js).
#### SopClassHandler
@@ -84,18 +178,28 @@ For a complete example implementation, [check out the OHIFCornerstoneViewport's
> The panel module is not yet in use.
#### Hotkeys
...
### Registering Extensions
Extensions are registered for the application at startup. The `ExtensionManager`, exposed by `ohif-core`, registers a list of extensions with our application's store. Each module provided by the extension becomes available via `state.plugins.availablePlugins`, and consists of three parts: id, type ([PLUGIN_TYPE](https://github.com/OHIF/ohif-core/blob/43c08a29eff3fb646a0e83a03a236ddd84f4a6e8/src/plugins.js#L1-L6)), and the return value of the module method.
Extensions are registered for the application at startup. The
`ExtensionManager`, exposed by `ohif-core`, registers a list of extensions with
our application's store. Each module provided by the extension becomes available
via `state.plugins.availablePlugins`, and consists of three parts: id, type
([PLUGIN_TYPE](https://github.com/OHIF/ohif-core/blob/43c08a29eff3fb646a0e83a03a236ddd84f4a6e8/src/plugins.js#L1-L6)),
and the return value of the module method.
In a future version, we will likely expose a way to provide the extensions you would like included at startup.
In a future version, we will likely expose a way to provide the extensions you
would like included at startup.
_app.js_
```js
import { createStore, combineReducers } from "redux";
import OHIF from "ohif-core";
import OHIFCornerstoneExtension from "ohif-cornerstone-extension";
import { createStore, combineReducers } from 'redux';
import OHIF from 'ohif-core';
import OHIFCornerstoneExtension from 'ohif-cornerstone-extension';
const combined = combineReducers(OHIF.redux.reducers);
const store = createStore(combined);
@@ -108,6 +212,19 @@ ExtensionManager.registerExtensions(store, extensions);
## OHIF Maintained Extensions
A small number of powerful extensions for popular use cases are maintained by OHIF. They're co-located in the [`OHIF/Viewers`](https://github.com/OHIF/Viewers/tree/react/) repository, in the top level [`extensions/`](https://github.com/OHIF/Viewers/tree/react/extensions) directory.
A small number of powerful extensions for popular use cases are maintained by
OHIF. They're co-located in the
[`OHIF/Viewers`](https://github.com/OHIF/Viewers/tree/react/) repository, in the
top level [`extensions/`](https://github.com/OHIF/Viewers/tree/react/extensions)
directory.
{% include "./_maintained-extensions-table.md" %}
<!--
Links
-->
<!-- prettier-ignore-start -->
[example-ext-src]: https://github.com/OHIF/Viewers/blob/master/extensions/_ohif-example-extension/src/index.js)
[module-types]: https://github.com/OHIF/ohif-core/blob/43c08a29eff3fb646a0e83a03a236ddd84f4a6e8/src/plugins.js#L1-L6
<!-- prettier-ignore-end -->
+187
View File
@@ -0,0 +1,187 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="203px" height="39px" viewBox="0 0 203 39" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 54.1 (76490) - https://sketchapp.com -->
<title>Custom Preset 2 Copy</title>
<desc>Created with Sketch.</desc>
<defs>
<filter x="-22.4%" y="-22.4%" width="144.8%" height="144.8%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.4707441 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176" id="path-2"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176 L0.103703704,13.9901176 Z" id="path-4"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176" id="path-6"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176 L0.103703704,13.9901176 Z" id="path-8"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176" id="path-10"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176 L0.103703704,13.9901176 Z" id="path-12"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176" id="path-14"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176 L0.103703704,13.9901176 Z" id="path-16"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176" id="path-18"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176 L0.103703704,13.9901176 Z" id="path-20"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176" id="path-22"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176 L0.103703704,13.9901176 Z" id="path-24"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176" id="path-26"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176 L0.103703704,13.9901176 Z" id="path-28"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176" id="path-30"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176 L0.103703704,13.9901176 Z" id="path-32"></path>
<polyline id="path-34" points="1.7512 17.989 11.9476 17.989 12.85 0.35 0.05 0.1"></polyline>
<polyline id="path-36" points="1.7512 17.989 11.9476 17.989 12.85 0.35 0.05 0.1"></polyline>
<polygon id="path-38" points="1.7512 17.989 11.9476 17.989 12.85 0.35 0.05 0.1"></polygon>
</defs>
<g id="Custom-Preset-2-Copy" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<rect fill="#FFFFFF" x="0" y="0" width="203" height="39"></rect>
<g id="Group-65" filter="url(#filter-1)" transform="translate(6.000000, 5.000000)">
<g id="Group-49" transform="translate(1.000000, 1.000000)">
<g id="Group-3">
<mask id="mask-3" fill="white">
<use xlink:href="#path-2"></use>
</mask>
<g id="Clip-2"></g>
<path d="M1.85138074,6.7158 C1.69250667,7.85927059 2.08948444,8.45077059 1.85138074,9.00253529 C1.61306963,9.55450588 1.3349363,10.5402706 1.57324741,11.2104176 C1.81155852,11.8805647 2.16892148,13.3392412 2.48666963,13.3789765 C2.80441778,13.4180941 2.24856593,11.8019176 2.56610667,12.3143588 C2.88406222,12.8270059 2.88406222,13.5893882 3.44012148,14.1150059 C3.99597333,14.6406235 4.75072889,14.5617706 5.34661037,15.0740059 C5.94228444,15.5866529 6.53795852,16.3358588 7.09401778,16.2570059 C7.09401778,16.2570059 7.05419556,16.6510647 6.77626963,17.3214176 C6.4983437,17.9915647 6.45852148,18.7798882 6.81609185,19.2532118 C7.17345481,19.7263294 7.53081778,20.4362118 7.84877333,20.7909471 C8.16652148,21.1456824 8.40483259,23.0381529 8.32518815,23.9841824 C8.24595852,24.9304176 8.68275852,27.0594471 9.67561778,27.5327706 C10.668477,28.0058882 9.67561778,27.2960059 9.47712889,26.7047118 C9.27843259,26.1134176 9.63040296,24.7333882 10.1101363,24.5361529 C10.58904,24.3389176 11.0260474,23.5505941 11.3834104,22.9984176 C11.7409807,22.4466529 12.654403,22.2098882 12.9325363,21.5399471 C13.2106696,20.8698 13.0914104,20.0810647 13.2502844,19.7263294 C13.4091585,19.3713882 13.8461659,18.5828588 12.8927141,18.1097412 C11.939677,17.6366235 11.5424919,17.8733882 11.5026696,17.4395941 C11.4628474,17.0058 11.2245363,16.5328882 10.5496326,16.3358588 C9.87431407,16.1384176 9.27843259,15.7560941 8.52367704,15.6714765 C7.76912889,15.5866529 7.61025481,16.1781529 7.21306963,15.8625353 C6.81609185,15.5473294 6.4983437,15.2317118 6.33926222,14.8376529 C6.18059556,14.4433882 5.70376593,14.6799471 5.74379556,14.4433882 C5.78320296,14.2066235 6.41869926,13.5366824 5.70376593,13.7732412 C4.98904,14.0095941 4.3535437,13.9307412 4.39315852,13.3001235 C4.43318815,12.6693 5.30678815,12.4325353 5.66435852,12.3536824 C6.02151407,12.2748294 6.29964741,12.7084176 6.73665481,12.9847118 C7.17345481,13.2605941 6.77626963,12.5904471 7.01458074,12.1171235 C7.25289185,11.6440059 8.16652148,11.6835353 8.28557333,11.0133882 C8.40483259,10.3432412 8.24595852,9.79106471 8.96089185,9.71221176 C9.67561778,9.63335882 10.4301659,9.75153529 10.5098104,9.39659412 C10.58904,9.04206471 9.67561778,9.51518235 9.63600296,9.08138824 C9.59618074,8.6478 10.4301659,8.05650588 10.668477,8.49009412 C10.9067881,8.92368235 11.5026696,8.96321176 11.5821067,8.8053 C11.6615437,8.6478 11.5821067,8.37191765 11.3039733,7.70156471 C11.0260474,7.03121176 10.7479141,7.22844706 10.5098104,6.47944706 C10.2714993,5.73024118 9.87431407,6.51877059 9.47712889,6.12450588 C9.0799437,5.73024118 8.60332148,4.90218235 8.52367704,5.61206471 C8.44444741,6.32153529 8.44444741,6.7158 8.08708444,7.26777059 C7.72951407,7.81994706 7.57084741,7.38615294 7.25289185,7.03121176 C6.9351437,6.67647647 6.22021037,6.32153529 6.45852148,6.00632941 C6.69683259,5.69071176 6.9351437,4.86285882 7.29250667,5.09962353 C7.65007704,5.33618235 8.2061363,5.33618235 8.12669926,4.94171176 C8.04726222,4.54765294 8.12669926,4.38974118 8.28557333,4.19271176 C8.44444741,3.99547647 9.00050667,3.64053529 9.00050667,4.35041765 C9.00050667,5.06009412 8.92086222,5.25732941 9.47712889,5.33618235 C10.0331881,5.41503529 10.668477,5.45435882 10.6290696,5.09962353 C10.58904,4.74468235 10.7879437,4.82353529 10.6290696,4.23203529 C10.4699881,3.64053529 9.99336593,3.60141765 9.47712889,3.32512353 C8.96089185,3.04924118 8.68275852,2.61565294 8.24595852,2.77335882 C7.80915852,2.93106471 7.76912889,3.08856471 7.72951407,3.52235882 C7.68969185,3.95615294 7.45138074,4.11385882 7.29250667,3.91662353 C7.13384,3.71959412 7.33232889,3.08856471 6.73665481,3.48303529 C6.14077333,3.87709412 5.90266963,4.54765294 5.58492148,4.07432941 C5.26696593,3.60141765 6.0613363,2.77335882 5.22735111,3.1283 C4.39315852,3.48303529 3.79727704,3.87709412 4.23428444,4.03500588 C4.67129185,4.19271176 5.10829926,4.4688 4.67129185,4.62650588 C4.23428444,4.78400588 3.36047704,4.50812353 3.04272889,4.82353529 C2.72498074,5.13874118 1.85138074,6.7158 1.85138074,6.7158" id="Fill-1" fill="#2196F3" mask="url(#mask-3)"></path>
</g>
<g id="Group-6">
<mask id="mask-5" fill="white">
<use xlink:href="#path-4"></use>
</mask>
<g id="Clip-5"></g>
<path d="M1.85138074,6.7158 C1.69250667,7.85927059 2.08948444,8.45077059 1.85138074,9.00253529 C1.61306963,9.55450588 1.3349363,10.5402706 1.57324741,11.2104176 C1.81155852,11.8805647 2.16892148,13.3392412 2.48666963,13.3789765 C2.80441778,13.4180941 2.24856593,11.8019176 2.56610667,12.3143588 C2.88406222,12.8270059 2.88406222,13.5893882 3.44012148,14.1150059 C3.99597333,14.6406235 4.75072889,14.5617706 5.34661037,15.0740059 C5.94228444,15.5866529 6.53795852,16.3358588 7.09401778,16.2570059 C7.09401778,16.2570059 7.05419556,16.6510647 6.77626963,17.3214176 C6.4983437,17.9915647 6.45852148,18.7798882 6.81609185,19.2532118 C7.17345481,19.7263294 7.53081778,20.4362118 7.84877333,20.7909471 C8.16652148,21.1456824 8.40483259,23.0381529 8.32518815,23.9841824 C8.24595852,24.9304176 8.68275852,27.0594471 9.67561778,27.5327706 C10.668477,28.0058882 9.67561778,27.2960059 9.47712889,26.7047118 C9.27843259,26.1134176 9.63040296,24.7333882 10.1101363,24.5361529 C10.58904,24.3389176 11.0260474,23.5505941 11.3834104,22.9984176 C11.7409807,22.4466529 12.654403,22.2098882 12.9325363,21.5399471 C13.2106696,20.8698 13.0914104,20.0810647 13.2502844,19.7263294 C13.4091585,19.3713882 13.8461659,18.5828588 12.8927141,18.1097412 C11.939677,17.6366235 11.5424919,17.8733882 11.5026696,17.4395941 C11.4628474,17.0058 11.2245363,16.5328882 10.5496326,16.3358588 C9.87431407,16.1384176 9.27843259,15.7560941 8.52367704,15.6714765 C7.76912889,15.5866529 7.61025481,16.1781529 7.21306963,15.8625353 C6.81609185,15.5473294 6.4983437,15.2317118 6.33926222,14.8376529 C6.18059556,14.4433882 5.70376593,14.6799471 5.74379556,14.4433882 C5.78320296,14.2066235 6.41869926,13.5366824 5.70376593,13.7732412 C4.98904,14.0095941 4.3535437,13.9307412 4.39315852,13.3001235 C4.43318815,12.6693 5.30678815,12.4325353 5.66435852,12.3536824 C6.02151407,12.2748294 6.29964741,12.7084176 6.73665481,12.9847118 C7.17345481,13.2605941 6.77626963,12.5904471 7.01458074,12.1171235 C7.25289185,11.6440059 8.16652148,11.6835353 8.28557333,11.0133882 C8.40483259,10.3432412 8.24595852,9.79106471 8.96089185,9.71221176 C9.67561778,9.63335882 10.4301659,9.75153529 10.5098104,9.39659412 C10.58904,9.04206471 9.67561778,9.51518235 9.63600296,9.08138824 C9.59618074,8.6478 10.4301659,8.05650588 10.668477,8.49009412 C10.9067881,8.92368235 11.5026696,8.96321176 11.5821067,8.8053 C11.6615437,8.6478 11.5821067,8.37191765 11.3039733,7.70156471 C11.0260474,7.03121176 10.7479141,7.22844706 10.5098104,6.47944706 C10.2714993,5.73024118 9.87431407,6.51877059 9.47712889,6.12450588 C9.0799437,5.73024118 8.60332148,4.90218235 8.52367704,5.61206471 C8.44444741,6.32153529 8.44444741,6.7158 8.08708444,7.26777059 C7.72951407,7.81994706 7.57084741,7.38615294 7.25289185,7.03121176 C6.9351437,6.67647647 6.22021037,6.32153529 6.45852148,6.00632941 C6.69683259,5.69071176 6.9351437,4.86285882 7.29250667,5.09962353 C7.65007704,5.33618235 8.2061363,5.33618235 8.12669926,4.94171176 C8.04726222,4.54765294 8.12669926,4.38974118 8.28557333,4.19271176 C8.44444741,3.99547647 9.00050667,3.64053529 9.00050667,4.35041765 C9.00050667,5.06009412 8.92086222,5.25732941 9.47712889,5.33618235 C10.0331881,5.41503529 10.668477,5.45435882 10.6290696,5.09962353 C10.58904,4.74468235 10.7879437,4.82353529 10.6290696,4.23203529 C10.4699881,3.64053529 9.99336593,3.60141765 9.47712889,3.32512353 C8.96089185,3.04924118 8.68275852,2.61565294 8.24595852,2.77335882 C7.80915852,2.93106471 7.76912889,3.08856471 7.72951407,3.52235882 C7.68969185,3.95615294 7.45138074,4.11385882 7.29250667,3.91662353 C7.13384,3.71959412 7.33232889,3.08856471 6.73665481,3.48303529 C6.14077333,3.87709412 5.90266963,4.54765294 5.58492148,4.07432941 C5.26696593,3.60141765 6.0613363,2.77335882 5.22735111,3.1283 C4.39315852,3.48303529 3.79727704,3.87709412 4.23428444,4.03500588 C4.67129185,4.19271176 5.10829926,4.4688 4.67129185,4.62650588 C4.23428444,4.78400588 3.36047704,4.50812353 3.04272889,4.82353529 C2.72498074,5.13874118 1.85138074,6.7158 1.85138074,6.7158 Z" id="Stroke-4" stroke="#2196F3" mask="url(#mask-5)"></path>
</g>
<g id="Group-9">
<mask id="mask-7" fill="white">
<use xlink:href="#path-6"></use>
</mask>
<g id="Clip-8"></g>
<path d="M6.5378963,2.45802941 C6.53582222,2.89882353 6.65715556,3.24635294 7.05434074,2.85229412 C7.45152593,2.45802941 7.68962963,1.98491176 7.96797037,2.18194118 C8.2458963,2.37917647 8.72251852,2.32667647 8.9208,2.3135 C9.1197037,2.30032353 9.15931852,1.70882353 9.71537778,1.78767647 C10.271437,1.86652941 10.0729481,1.6695 10.6686222,1.35388235 C11.2645037,1.03847059 12.5354963,0.486705882 11.2246815,0.644411765 C9.91386667,0.802117647 9.83442963,0.447176471 8.9208,1.03847059 C8.00758519,1.62997059 7.8090963,1.62997059 7.57078519,1.78767647 C7.33247407,1.94538235 7.05434074,1.31455882 6.73659259,1.78767647 C6.41863704,2.26079412 6.54017778,2.00879412 6.5378963,2.45802941" id="Fill-7" fill="#2196F3" mask="url(#mask-7)"></path>
</g>
<g id="Group-12">
<mask id="mask-9" fill="white">
<use xlink:href="#path-8"></use>
</mask>
<g id="Clip-11"></g>
<path d="M6.5378963,2.45802941 C6.53582222,2.89882353 6.65715556,3.24635294 7.05434074,2.85229412 C7.45152593,2.45802941 7.68962963,1.98491176 7.96797037,2.18194118 C8.2458963,2.37917647 8.72251852,2.32667647 8.9208,2.3135 C9.1197037,2.30032353 9.15931852,1.70882353 9.71537778,1.78767647 C10.271437,1.86652941 10.0729481,1.6695 10.6686222,1.35388235 C11.2645037,1.03847059 12.5354963,0.486705882 11.2246815,0.644411765 C9.91386667,0.802117647 9.83442963,0.447176471 8.9208,1.03847059 C8.00758519,1.62997059 7.8090963,1.62997059 7.57078519,1.78767647 C7.33247407,1.94538235 7.05434074,1.31455882 6.73659259,1.78767647 C6.41863704,2.26079412 6.54017778,2.00879412 6.5378963,2.45802941 Z" id="Stroke-10" stroke="#2196F3" mask="url(#mask-9)"></path>
</g>
<g id="Group-15">
<mask id="mask-11" fill="white">
<use xlink:href="#path-10"></use>
</mask>
<g id="Clip-14"></g>
<path d="M11.3040148,1.23570588 C10.8346519,1.63841176 10.1126667,2.22147059 10.6685185,2.22147059 C11.2245778,2.22147059 11.4946222,1.93241176 11.7966074,2.3135 C12.0985926,2.69438235 11.9791259,3.28588235 11.9791259,3.56176471 C11.9791259,3.83785294 11.8202519,4.46888235 12.2176444,5.25720588 C12.6148296,6.04552941 12.6544444,6.55817647 13.051837,6.04552941 C13.4488148,5.53329412 14.4020593,4.54752941 14.8786815,4.46888235 C15.3553037,4.38982353 15.8323407,4.19258824 16.0704444,3.79832353 C16.3085481,3.40405882 16.0704444,3.02152941 16.4674222,2.73988235 C16.8644,2.45802941 16.784963,2.10308824 16.9044296,1.6695 C17.0232741,1.23570588 18.0959852,1.23570588 17.6191556,0.999352941 C17.1427407,0.762588235 16.2689333,0.604882353 15.2360444,0.723264706 C14.203363,0.841441176 12.1778222,0.486705882 11.3040148,1.23570588" id="Fill-13" fill="#2196F3" mask="url(#mask-11)"></path>
</g>
<g id="Group-18">
<mask id="mask-13" fill="white">
<use xlink:href="#path-12"></use>
</mask>
<g id="Clip-17"></g>
<path d="M11.3040148,1.23570588 C10.8346519,1.63841176 10.1126667,2.22147059 10.6685185,2.22147059 C11.2245778,2.22147059 11.4946222,1.93241176 11.7966074,2.3135 C12.0985926,2.69438235 11.9791259,3.28588235 11.9791259,3.56176471 C11.9791259,3.83785294 11.8202519,4.46888235 12.2176444,5.25720588 C12.6148296,6.04552941 12.6544444,6.55817647 13.051837,6.04552941 C13.4488148,5.53329412 14.4020593,4.54752941 14.8786815,4.46888235 C15.3553037,4.38982353 15.8323407,4.19258824 16.0704444,3.79832353 C16.3085481,3.40405882 16.0704444,3.02152941 16.4674222,2.73988235 C16.8644,2.45802941 16.784963,2.10308824 16.9044296,1.6695 C17.0232741,1.23570588 18.0959852,1.23570588 17.6191556,0.999352941 C17.1427407,0.762588235 16.2689333,0.604882353 15.2360444,0.723264706 C14.203363,0.841441176 12.1778222,0.486705882 11.3040148,1.23570588 Z" id="Stroke-16" stroke="#2196F3" mask="url(#mask-13)"></path>
</g>
<g id="Group-21">
<mask id="mask-15" fill="white">
<use xlink:href="#path-14"></use>
</mask>
<g id="Clip-20"></g>
<path d="M6.93518519,13.4181353 C6.68256296,13.8270176 6.81592593,13.8519294 7.09405926,13.9307824 C7.37198519,14.0096353 6.9748,14.4825471 7.29254815,14.5220765 C7.6102963,14.5618118 8.32522963,14.7588412 8.52371852,14.5220765 C8.72262222,14.2857235 8.20617778,14.3779588 7.84860741,14.1150471 C7.49145185,13.8519294 7.11459259,13.1278412 6.93518519,13.4181353" id="Fill-19" fill="#2196F3" mask="url(#mask-15)"></path>
</g>
<g id="Group-24">
<mask id="mask-17" fill="white">
<use xlink:href="#path-16"></use>
</mask>
<g id="Clip-23"></g>
<path d="M6.93518519,13.4181353 C6.68256296,13.8270176 6.81592593,13.8519294 7.09405926,13.9307824 C7.37198519,14.0096353 6.9748,14.4825471 7.29254815,14.5220765 C7.6102963,14.5618118 8.32522963,14.7588412 8.52371852,14.5220765 C8.72262222,14.2857235 8.20617778,14.3779588 7.84860741,14.1150471 C7.49145185,13.8519294 7.11459259,13.1278412 6.93518519,13.4181353 Z" id="Stroke-22" stroke="#2196F3" mask="url(#mask-17)"></path>
</g>
<g id="Group-27">
<mask id="mask-19" fill="white">
<use xlink:href="#path-18"></use>
</mask>
<g id="Clip-26"></g>
<path d="M26.1584504,19.8445265 C25.7305689,20.0572029 25.9203467,20.3967029 25.5229541,20.6332618 C25.1257689,20.8696147 25.284643,20.9484676 25.1655911,21.5006441 C25.0463319,22.0524088 25.2052059,22.3678206 25.4833393,21.9342324 C25.7614726,21.5006441 26.6350726,19.6081735 26.1584504,19.8445265" id="Fill-25" fill="#2196F3" mask="url(#mask-19)"></path>
</g>
<g id="Group-30">
<mask id="mask-21" fill="white">
<use xlink:href="#path-20"></use>
</mask>
<g id="Clip-29"></g>
<path d="M26.1584504,19.8445265 C25.7305689,20.0572029 25.9203467,20.3967029 25.5229541,20.6332618 C25.1257689,20.8696147 25.284643,20.9484676 25.1655911,21.5006441 C25.0463319,22.0524088 25.2052059,22.3678206 25.4833393,21.9342324 C25.7614726,21.5006441 26.6350726,19.6081735 26.1584504,19.8445265 Z" id="Stroke-28" stroke="#2196F3" mask="url(#mask-21)"></path>
</g>
<g id="Group-33">
<mask id="mask-23" fill="white">
<use xlink:href="#path-22"></use>
</mask>
<g id="Clip-32"></g>
<path d="M26.5159378,11.4075706 C26.3966785,11.5259529 26.1981896,10.8556 26.0791378,10.5401882 C25.9598785,10.2247765 25.9627822,9.67651176 26.29816,9.37180588 C26.7158785,8.99174706 26.5159378,9.86983529 26.5159378,10.3431588 C26.5159378,10.8160706 26.6349896,11.2891882 26.5159378,11.4075706 M25.1254785,10.1854529 C24.8473452,10.0277471 24.331523,10.1854529 23.6960267,10.3824824 C23.060323,10.5797176 23.5688859,9.94374706 23.8549007,9.5151 C24.1106341,9.13195294 23.9739526,9.63327647 24.5302193,9.67280588 C25.0860711,9.71233529 25.4040267,10.3431588 25.1254785,10.1854529 M24.2124711,11.5259529 C24.1726489,11.8411588 24.331523,12.3538059 23.4577156,12.1567765 C22.5839081,11.9595412 22.5839081,11.4864235 22.2265452,11.8411588 C21.8691822,12.1961 21.4321748,12.5113059 20.9157304,11.9595412 C20.3994933,11.4075706 20.4789304,11.2498647 20.2010044,11.2103353 C20.0029304,11.1825412 19.3427526,11.0361588 18.7922933,11.1951 C18.8350193,11.1697765 18.8806489,11.1364235 18.9298044,11.0921588 C19.3269896,10.7374235 19.2475526,10.6190412 19.6843526,10.2247765 C20.1215674,9.83030588 20.4391081,9.47577647 20.7568563,9.83030588 C21.0746044,10.1854529 21.749923,10.2643059 21.5116119,10.6585706 C21.2733007,11.0526294 21.4321748,11.2891882 21.7103081,11.0526294 C21.9880267,10.8160706 22.3854193,10.6585706 22.1074933,10.3431588 C21.8291526,10.0277471 21.5510193,9.19968824 21.9486193,9.75165882 C22.3458044,10.3036294 22.4648563,10.5797176 22.70296,10.8949235 C22.9414785,11.2103353 23.1797896,11.4075706 23.2592267,11.2103353 C23.3386637,11.0133059 23.2194044,10.5797176 23.3386637,10.5008647 C23.4577156,10.4220118 23.3386637,11.1710118 23.6960267,11.2103353 C24.0533896,11.2498647 24.2520859,11.2103353 24.2124711,11.5259529 M28.4224267,13.2213941 C28.3033748,12.5508353 27.4295674,6.47936471 27.4295674,6.47936471 C27.4295674,6.47936471 25.0860711,4.98115882 24.6890933,5.29636471 C24.2917007,5.61198235 23.6165896,5.56442353 23.6960267,5.25312941 C23.7754637,4.94183529 24.2917007,5.02089412 23.4176859,4.42918824 C22.5442933,3.83768824 22.3854193,3.32524706 21.7103081,4.07424706 C21.0347822,4.82345294 20.8761156,5.45427647 20.4789304,5.65151176 C20.0817452,5.84854118 19.763997,6.47936471 20.2010044,6.63707059 C20.6378044,6.79457059 20.6776267,6.63707059 21.0347822,6.95227647 C21.39256,7.26789412 21.8691822,7.18883529 21.9486193,6.99201176 C22.0280563,6.79457059 22.1074933,6.16395294 22.1471081,5.92739412 C22.1869304,5.69083529 22.5905452,4.90230588 22.5474044,5.53312941 C22.5044711,6.16395294 23.1001452,6.16395294 22.70296,6.59754118 C22.3059822,7.03112941 22.5442933,7.38627647 21.749923,7.46512941 C20.9553452,7.54377647 20.9157304,7.07086471 20.4789304,7.30742353 C20.041923,7.54377647 20.0817452,7.70168824 19.9228711,7.93804118 C19.763997,8.1746 18.9298044,8.64771765 18.9298044,8.64771765 C18.9298044,8.64771765 18.2546933,8.41115882 18.5722341,8.84495294 C18.8901896,9.27854118 19.1681156,9.79098235 18.8901896,9.83030588 C18.6120563,9.86983529 17.8573007,9.43624706 17.8573007,9.90936471 C17.8573007,10.3824824 17.7384563,10.8949235 18.0562044,11.0133059 C18.2804119,11.0966882 18.4260119,11.2776588 18.63176,11.2523353 C18.4722637,11.3206882 18.3272859,11.4197176 18.2150785,11.5652765 C17.9058341,11.9661294 18.0958193,12.6692176 17.460323,12.9057765 C16.8250341,13.1425412 16.8250341,13.4182176 16.7055674,13.9308647 C16.586723,14.4433059 16.7055674,15.7442765 16.8644415,15.8626588 C17.0231081,15.9808353 17.3014489,16.9666 17.9767674,16.8875412 C18.6520859,16.8086882 19.3668119,16.7784235 19.605123,16.8922765 C19.8434341,17.0057176 20.2404119,16.6511882 20.3596711,17.5578941 C20.4789304,18.4646 20.7568563,18.5829824 20.9157304,19.0561 C21.0746044,19.5290118 20.8362933,20.5149824 20.9157304,21.1062765 C20.9951674,21.6975706 21.5510193,22.7228647 21.5510193,23.2353059 C21.5510193,23.7477471 22.1471081,23.9843059 22.4648563,23.7872765 C22.7826044,23.5900412 23.4577156,23.1957765 23.7356415,22.5649529 C24.0139822,21.9343353 24.0139822,21.6189235 24.4505748,20.7908647 C24.8873748,19.9630118 24.7685304,19.3715118 24.9668119,18.7406882 C25.1655081,18.1098647 25.6433748,17.6760706 26.29816,16.9666 C26.9527378,16.2571294 26.8349304,15.8626588 26.29816,15.9019824 C25.7613896,15.9413059 25.4034044,15.4290706 25.1254785,14.7982471 C24.8479674,14.1672176 24.5302193,12.5903647 24.7685304,13.1028059 C25.0068415,13.6156588 25.4832563,15.0348059 25.9598785,15.2713647 C26.4365007,15.5079235 27.3105156,14.8692765 27.5090044,14.6366294 C27.7074933,14.4037765 27.6280563,13.7338353 27.1116119,13.4577471 C26.5953748,13.1816588 26.913123,12.9453059 27.4295674,13.2605118 C27.9458044,13.5759235 28.5416859,13.8913353 28.4224267,13.2213941" id="Fill-31" fill="#2196F3" mask="url(#mask-23)"></path>
</g>
<g id="Group-36">
<mask id="mask-25" fill="white">
<use xlink:href="#path-24"></use>
</mask>
<g id="Clip-35"></g>
<path d="M26.5159378,11.4075706 C26.3966785,11.5259529 26.1981896,10.8556 26.0791378,10.5401882 C25.9598785,10.2247765 25.9627822,9.67651176 26.29816,9.37180588 C26.7158785,8.99174706 26.5159378,9.86983529 26.5159378,10.3431588 C26.5159378,10.8160706 26.6349896,11.2891882 26.5159378,11.4075706 Z M25.1254785,10.1854529 C24.8473452,10.0277471 24.331523,10.1854529 23.6960267,10.3824824 C23.060323,10.5797176 23.5688859,9.94374706 23.8549007,9.5151 C24.1106341,9.13195294 23.9739526,9.63327647 24.5302193,9.67280588 C25.0860711,9.71233529 25.4040267,10.3431588 25.1254785,10.1854529 Z M24.2124711,11.5259529 C24.1726489,11.8411588 24.331523,12.3538059 23.4577156,12.1567765 C22.5839081,11.9595412 22.5839081,11.4864235 22.2265452,11.8411588 C21.8691822,12.1961 21.4321748,12.5113059 20.9157304,11.9595412 C20.3994933,11.4075706 20.4789304,11.2498647 20.2010044,11.2103353 C20.0029304,11.1825412 19.3427526,11.0361588 18.7922933,11.1951 C18.8350193,11.1697765 18.8806489,11.1364235 18.9298044,11.0921588 C19.3269896,10.7374235 19.2475526,10.6190412 19.6843526,10.2247765 C20.1215674,9.83030588 20.4391081,9.47577647 20.7568563,9.83030588 C21.0746044,10.1854529 21.749923,10.2643059 21.5116119,10.6585706 C21.2733007,11.0526294 21.4321748,11.2891882 21.7103081,11.0526294 C21.9880267,10.8160706 22.3854193,10.6585706 22.1074933,10.3431588 C21.8291526,10.0277471 21.5510193,9.19968824 21.9486193,9.75165882 C22.3458044,10.3036294 22.4648563,10.5797176 22.70296,10.8949235 C22.9414785,11.2103353 23.1797896,11.4075706 23.2592267,11.2103353 C23.3386637,11.0133059 23.2194044,10.5797176 23.3386637,10.5008647 C23.4577156,10.4220118 23.3386637,11.1710118 23.6960267,11.2103353 C24.0533896,11.2498647 24.2520859,11.2103353 24.2124711,11.5259529 Z M28.4224267,13.2213941 C28.3033748,12.5508353 27.4295674,6.47936471 27.4295674,6.47936471 C27.4295674,6.47936471 25.0860711,4.98115882 24.6890933,5.29636471 C24.2917007,5.61198235 23.6165896,5.56442353 23.6960267,5.25312941 C23.7754637,4.94183529 24.2917007,5.02089412 23.4176859,4.42918824 C22.5442933,3.83768824 22.3854193,3.32524706 21.7103081,4.07424706 C21.0347822,4.82345294 20.8761156,5.45427647 20.4789304,5.65151176 C20.0817452,5.84854118 19.763997,6.47936471 20.2010044,6.63707059 C20.6378044,6.79457059 20.6776267,6.63707059 21.0347822,6.95227647 C21.39256,7.26789412 21.8691822,7.18883529 21.9486193,6.99201176 C22.0280563,6.79457059 22.1074933,6.16395294 22.1471081,5.92739412 C22.1869304,5.69083529 22.5905452,4.90230588 22.5474044,5.53312941 C22.5044711,6.16395294 23.1001452,6.16395294 22.70296,6.59754118 C22.3059822,7.03112941 22.5442933,7.38627647 21.749923,7.46512941 C20.9553452,7.54377647 20.9157304,7.07086471 20.4789304,7.30742353 C20.041923,7.54377647 20.0817452,7.70168824 19.9228711,7.93804118 C19.763997,8.1746 18.9298044,8.64771765 18.9298044,8.64771765 C18.9298044,8.64771765 18.2546933,8.41115882 18.5722341,8.84495294 C18.8901896,9.27854118 19.1681156,9.79098235 18.8901896,9.83030588 C18.6120563,9.86983529 17.8573007,9.43624706 17.8573007,9.90936471 C17.8573007,10.3824824 17.7384563,10.8949235 18.0562044,11.0133059 C18.2804119,11.0966882 18.4260119,11.2776588 18.63176,11.2523353 C18.4722637,11.3206882 18.3272859,11.4197176 18.2150785,11.5652765 C17.9058341,11.9661294 18.0958193,12.6692176 17.460323,12.9057765 C16.8250341,13.1425412 16.8250341,13.4182176 16.7055674,13.9308647 C16.586723,14.4433059 16.7055674,15.7442765 16.8644415,15.8626588 C17.0231081,15.9808353 17.3014489,16.9666 17.9767674,16.8875412 C18.6520859,16.8086882 19.3668119,16.7784235 19.605123,16.8922765 C19.8434341,17.0057176 20.2404119,16.6511882 20.3596711,17.5578941 C20.4789304,18.4646 20.7568563,18.5829824 20.9157304,19.0561 C21.0746044,19.5290118 20.8362933,20.5149824 20.9157304,21.1062765 C20.9951674,21.6975706 21.5510193,22.7228647 21.5510193,23.2353059 C21.5510193,23.7477471 22.1471081,23.9843059 22.4648563,23.7872765 C22.7826044,23.5900412 23.4577156,23.1957765 23.7356415,22.5649529 C24.0139822,21.9343353 24.0139822,21.6189235 24.4505748,20.7908647 C24.8873748,19.9630118 24.7685304,19.3715118 24.9668119,18.7406882 C25.1655081,18.1098647 25.6433748,17.6760706 26.29816,16.9666 C26.9527378,16.2571294 26.8349304,15.8626588 26.29816,15.9019824 C25.7613896,15.9413059 25.4034044,15.4290706 25.1254785,14.7982471 C24.8479674,14.1672176 24.5302193,12.5903647 24.7685304,13.1028059 C25.0068415,13.6156588 25.4832563,15.0348059 25.9598785,15.2713647 C26.4365007,15.5079235 27.3105156,14.8692765 27.5090044,14.6366294 C27.7074933,14.4037765 27.6280563,13.7338353 27.1116119,13.4577471 C26.5953748,13.1816588 26.913123,12.9453059 27.4295674,13.2605118 C27.9458044,13.5759235 28.5416859,13.8913353 28.4224267,13.2213941 Z" id="Stroke-34" stroke="#2196F3" mask="url(#mask-25)"></path>
</g>
<g id="Group-39">
<mask id="mask-27" fill="white">
<use xlink:href="#path-26"></use>
</mask>
<g id="Clip-38"></g>
<path d="M18.8503674,6.59758235 C18.6070785,6.67025882 18.4135674,7.14955294 18.5326193,7.38631765 C18.6520859,7.62267059 18.4135674,7.26772941 18.0958193,7.46496471 C17.7778637,7.66199412 17.3060119,8.21417059 17.7405304,8.25328824 C18.1752563,8.29302353 18.0958193,7.93808235 18.4930044,8.09578824 C18.8901896,8.25328824 19.3269896,8.21417059 19.3269896,7.81990588 C19.3269896,7.42543529 19.2475526,6.47940588 18.8503674,6.59758235" id="Fill-37" fill="#2196F3" mask="url(#mask-27)"></path>
</g>
<g id="Group-42">
<mask id="mask-29" fill="white">
<use xlink:href="#path-28"></use>
</mask>
<g id="Clip-41"></g>
<path d="M18.8503674,6.59758235 C18.6070785,6.67025882 18.4135674,7.14955294 18.5326193,7.38631765 C18.6520859,7.62267059 18.4135674,7.26772941 18.0958193,7.46496471 C17.7778637,7.66199412 17.3060119,8.21417059 17.7405304,8.25328824 C18.1752563,8.29302353 18.0958193,7.93808235 18.4930044,8.09578824 C18.8901896,8.25328824 19.3269896,8.21417059 19.3269896,7.81990588 C19.3269896,7.42543529 19.2475526,6.47940588 18.8503674,6.59758235 Z" id="Stroke-40" stroke="#2196F3" mask="url(#mask-29)"></path>
</g>
<g id="Group-45">
<mask id="mask-31" fill="white">
<use xlink:href="#path-30"></use>
</mask>
<g id="Clip-44"></g>
<path d="M16.2689333,4.78404706 C16.0295852,4.81801765 15.9509778,5.41487059 16.4674222,5.49372353 C16.9838667,5.57257647 17.9082815,5.37534118 17.5652296,5.05992941 C17.2221778,4.74472353 16.8252,4.70519412 16.2689333,4.78404706" id="Fill-43" fill="#2196F3" mask="url(#mask-31)"></path>
</g>
<g id="Group-48">
<mask id="mask-33" fill="white">
<use xlink:href="#path-32"></use>
</mask>
<g id="Clip-47"></g>
<path d="M16.2689333,4.78404706 C16.0295852,4.81801765 15.9509778,5.41487059 16.4674222,5.49372353 C16.9838667,5.57257647 17.9082815,5.37534118 17.5652296,5.05992941 C17.2221778,4.74472353 16.8252,4.70519412 16.2689333,4.78404706 Z" id="Stroke-46" stroke="#2196F3" mask="url(#mask-33)"></path>
</g>
</g>
<g id="Group-54">
<path d="M28.1296528,14.2858085 C28.1296528,21.8560338 21.992681,27.9932099 14.4222514,27.9932099 C6.85182183,27.9932099 0.71485,21.8560338 0.71485,14.2858085 C0.71485,6.71537887 6.85182183,0.578407042 14.4222514,0.578407042 C21.992681,0.578407042 28.1296528,6.71537887 28.1296528,14.2858085 Z" id="Stroke-50" stroke="#2196F3"></path>
<path d="M14.4854387,1.69603028 C7.4461993,1.69603028 1.71931197,7.42291761 1.71931197,14.462157 C1.71931197,21.5013965 7.4461993,27.2280796 14.4854387,27.2280796 C21.5246782,27.2280796 27.2513613,21.5013965 27.2513613,14.462157 C27.2513613,7.42291761 21.5246782,1.69603028 14.4854387,1.69603028 M14.4854387,28.8618824 C6.54536127,28.8618824 0.0855091549,22.4022345 0.0855091549,14.462157 C0.0855091549,6.52187535 6.54536127,0.0622274648 14.4854387,0.0622274648 C22.4255162,0.0622274648 28.8851641,6.52187535 28.8851641,14.462157 C28.8851641,22.4022345 22.4255162,28.8618824 14.4854387,28.8618824" id="Fill-52" fill="#2196F3"></path>
</g>
<g id="Group-64" transform="translate(16.000000, 0.000000)">
<g id="Group-57">
<mask id="mask-35" fill="white">
<use xlink:href="#path-34"></use>
</mask>
<g id="Clip-56"></g>
<path d="M7.92792,7.13868 C7.61952,7.44688 7.25072,7.60088 6.82132,7.60088 C6.39172,7.60088 6.02312,7.44688 5.71492,7.13868 C5.40672,6.83048 5.25232,6.46128 5.25232,6.03208 C5.25232,5.60268 5.40672,5.23948 5.71492,4.94208 C6.02312,4.64488 6.39172,4.49608 6.82132,4.49608 C7.25072,4.49608 7.61952,4.64488 7.92792,4.94208 C8.23592,5.23948 8.39032,5.60268 8.39032,6.03208 C8.39032,6.46128 8.23592,6.83048 7.92792,7.13868 M10.43812,2.53088 C9.44732,1.55088 8.24732,1.06088 6.83792,1.06088 C5.42852,1.06088 4.22852,1.55088 3.23752,2.53088 C2.24652,3.51048 1.75112,4.69428 1.75112,6.08168 C1.75112,6.91828 2.17492,8.31688 3.02292,10.27648 C3.87052,12.23628 4.71832,14.01988 5.56592,15.62728 C6.41412,17.23468 6.83792,18.01648 6.83792,17.97268 C6.96992,17.73048 7.15152,17.40008 7.38272,16.98168 C7.61412,16.56328 8.02152,15.77608 8.60512,14.61988 C9.18852,13.46368 9.70052,12.40108 10.14052,11.43288 C10.58132,10.46368 10.98872,9.46168 11.36292,8.42648 C11.73752,7.39188 11.92432,6.61008 11.92432,6.08168 C11.92432,4.69428 11.42892,3.51048 10.43812,2.53088" id="Fill-55" fill="#FFFFFF" mask="url(#mask-35)"></path>
</g>
<g id="Group-60">
<mask id="mask-37" fill="white">
<use xlink:href="#path-36"></use>
</mask>
<g id="Clip-59"></g>
<path d="M7.92792,7.13868 C7.61952,7.44688 7.25072,7.60088 6.82132,7.60088 C6.39172,7.60088 6.02312,7.44688 5.71492,7.13868 C5.40672,6.83048 5.25232,6.46128 5.25232,6.03208 C5.25232,5.60268 5.40672,5.23948 5.71492,4.94208 C6.02312,4.64488 6.39172,4.49608 6.82132,4.49608 C7.25072,4.49608 7.61952,4.64488 7.92792,4.94208 C8.23592,5.23948 8.39032,5.60268 8.39032,6.03208 C8.39032,6.46128 8.23592,6.83048 7.92792,7.13868 M10.43812,2.53088 C9.44732,1.55088 8.24732,1.06088 6.83792,1.06088 C5.42852,1.06088 4.22852,1.55088 3.23752,2.53088 C2.24652,3.51048 1.75112,4.69428 1.75112,6.08168 C1.75112,6.91828 2.17492,8.31688 3.02292,10.27648 C3.87052,12.23628 4.71832,14.01988 5.56592,15.62728 C6.41412,17.23468 6.83792,18.01648 6.83792,17.97268 C6.96992,17.73048 7.15152,17.40008 7.38272,16.98168 C7.61412,16.56328 8.02152,15.77608 8.60512,14.61988 C9.18852,13.46368 9.70052,12.40108 10.14052,11.43288 C10.58132,10.46368 10.98872,9.46168 11.36292,8.42648 C11.73752,7.39188 11.92432,6.61008 11.92432,6.08168 C11.92432,4.69428 11.42892,3.51048 10.43812,2.53088" id="Fill-58" fill="#FFFFFF" mask="url(#mask-37)"></path>
</g>
<g id="Group-63">
<mask id="mask-39" fill="white">
<use xlink:href="#path-38"></use>
</mask>
<g id="Clip-62"></g>
<path d="M6.82128,4.9961 C6.51968,4.9961 6.27828,5.0933 6.06188,5.3021 C5.85068,5.5057 5.75228,5.7377 5.75228,6.0321 C5.75228,6.3301 5.85268,6.5695 6.06828,6.7851 C6.28368,7.0005 6.52308,7.1009 6.82128,7.1009 C7.11948,7.1009 7.35888,7.0005 7.57448,6.7849 C7.78988,6.5695 7.89028,6.3301 7.89028,6.0321 C7.89028,5.7377 7.79188,5.5057 7.58068,5.3017 C7.36428,5.0933 7.12288,4.9961 6.82128,4.9961 L6.82128,4.9961 Z M6.82128,8.1009 C6.25648,8.1009 5.76528,7.8961 5.36128,7.4921 C4.95728,7.0881 4.75228,6.5969 4.75228,6.0321 C4.75228,5.4639 4.95928,4.9761 5.36748,4.5823 C5.77108,4.1933 6.26008,3.9961 6.82128,3.9961 C7.38228,3.9961 7.87128,4.1933 8.27488,4.5821 C8.68348,4.9763 8.89028,5.4641 8.89028,6.0321 C8.89028,6.5967 8.68548,7.0879 8.28168,7.4921 C7.87728,7.8961 7.38608,8.1009 6.82128,8.1009 L6.82128,8.1009 Z M6.83788,1.5609 C5.55368,1.5609 4.49108,1.9945 3.58908,2.8865 C2.68888,3.7763 2.25108,4.8215 2.25108,6.0817 C2.25108,6.6073 2.46468,7.7273 3.48188,10.0779 C4.31968,12.0155 5.16968,13.8041 6.00828,15.3941 C6.38528,16.1089 6.64868,16.6035 6.83208,16.9447 C6.86828,16.8789 6.90608,16.8105 6.94528,16.7399 C7.17208,16.3295 7.58028,15.5405 8.15888,14.3947 C8.73768,13.2469 9.25128,12.1809 9.68528,11.2259 C10.11888,10.2727 10.52508,9.2735 10.89248,8.2565 C11.33228,7.0427 11.42448,6.4039 11.42448,6.0817 C11.42448,4.8215 10.98668,3.7765 10.08648,2.8865 C9.18468,1.9945 8.12208,1.5609 6.83788,1.5609 L6.83788,1.5609 Z M7.04328,18.4751 L6.83508,18.4745 C6.52208,18.4733 6.46988,18.3767 6.06328,17.6257 C5.85068,17.2335 5.53768,16.6451 5.12388,15.8607 C4.27328,14.2479 3.41208,12.4359 2.56388,10.4749 C1.68068,8.4333 1.25108,6.9963 1.25108,6.0817 C1.25108,4.5619 1.80108,3.2475 2.88588,2.1753 C3.96928,1.1041 5.29908,0.5609 6.83788,0.5609 C8.37688,0.5609 9.70648,1.1041 10.78968,2.1753 C11.87448,3.2477 12.42448,4.5621 12.42448,6.0817 C12.42448,6.6751 12.23108,7.4977 11.83308,8.5967 C11.45648,9.6383 11.04028,10.6623 10.59568,11.6399 C10.15628,12.6071 9.63668,13.6855 9.05148,14.8451 C8.45908,16.0185 8.05648,16.7965 7.82048,17.2235 C7.62348,17.5797 7.46268,17.8721 7.33788,18.1003 L7.33788,18.1803 L7.04328,18.4751 Z" id="Fill-61" fill="#2196F3" mask="url(#mask-39)"></path>
</g>
</g>
</g>
<g id="Translation-Manageme" transform="translate(40.000000, 6.000000)" fill-rule="nonzero">
<path d="M2.688,9.94 L2.688,1.946 L1.42108547e-14,1.946 L1.42108547e-14,0.504 L7.126,0.504 L7.126,1.946 L4.41,1.946 L4.41,9.94 L2.688,9.94 Z M7.462,9.94 L7.462,5.32 C7.462,4.396 7.448,3.724 7.406,3.122 L8.89,3.122 L8.96,4.41 L9.002,4.41 C9.338,3.458 10.136,2.968 10.878,2.968 C11.046,2.968 11.144,2.982 11.284,3.01 L11.284,4.62 C11.13,4.592 10.976,4.578 10.766,4.578 C9.954,4.578 9.38,5.096 9.226,5.88 C9.198,6.034 9.184,6.216 9.184,6.398 L9.184,9.94 L7.462,9.94 Z M17.612,5.852 L17.612,8.302 C17.612,8.918 17.64,9.52 17.724,9.94 L16.17,9.94 L16.044,9.184 L16.002,9.184 C15.596,9.716 14.882,10.094 13.986,10.094 C12.614,10.094 11.844,9.1 11.844,8.064 C11.844,6.356 13.37,5.474 15.89,5.488 L15.89,5.376 C15.89,4.928 15.708,4.186 14.504,4.186 C13.832,4.186 13.132,4.396 12.67,4.69 L12.334,3.57 C12.838,3.262 13.72,2.968 14.798,2.968 C16.982,2.968 17.612,4.354 17.612,5.852 Z M15.932,7.546 L15.932,6.608 C14.714,6.594 13.552,6.846 13.552,7.882 C13.552,8.554 13.986,8.862 14.532,8.862 C15.232,8.862 15.722,8.414 15.89,7.924 C15.932,7.798 15.932,7.672 15.932,7.546 Z M19.432,9.94 L19.432,5.152 C19.432,4.368 19.404,3.71 19.376,3.122 L20.874,3.122 L20.958,4.144 L21,4.144 C21.308,3.612 22.05,2.968 23.184,2.968 C24.374,2.968 25.606,3.738 25.606,5.894 L25.606,9.94 L23.884,9.94 L23.884,6.09 C23.884,5.11 23.52,4.368 22.582,4.368 C21.896,4.368 21.42,4.858 21.238,5.376 C21.182,5.516 21.154,5.726 21.154,5.922 L21.154,9.94 L19.432,9.94 Z M27.02,9.604 L27.37,8.344 C27.748,8.582 28.49,8.848 29.106,8.848 C29.862,8.848 30.198,8.526 30.198,8.078 C30.198,7.616 29.918,7.392 29.078,7.084 C27.748,6.636 27.202,5.908 27.202,5.096 C27.202,3.892 28.196,2.968 29.778,2.968 C30.534,2.968 31.192,3.15 31.598,3.374 L31.248,4.578 C30.968,4.41 30.408,4.186 29.806,4.186 C29.19,4.186 28.854,4.494 28.854,4.914 C28.854,5.348 29.176,5.544 30.044,5.866 C31.29,6.3 31.85,6.93 31.864,7.938 C31.864,9.184 30.898,10.08 29.092,10.08 C28.266,10.08 27.524,9.884 27.02,9.604 Z M33.278,9.94 L33.278,-7.10542736e-15 L35,-7.10542736e-15 L35,9.94 L33.278,9.94 Z M42.168,5.852 L42.168,8.302 C42.168,8.918 42.196,9.52 42.28,9.94 L40.726,9.94 L40.6,9.184 L40.558,9.184 C40.152,9.716 39.438,10.094 38.542,10.094 C37.17,10.094 36.4,9.1 36.4,8.064 C36.4,6.356 37.926,5.474 40.446,5.488 L40.446,5.376 C40.446,4.928 40.264,4.186 39.06,4.186 C38.388,4.186 37.688,4.396 37.226,4.69 L36.89,3.57 C37.394,3.262 38.276,2.968 39.354,2.968 C41.538,2.968 42.168,4.354 42.168,5.852 Z M40.488,7.546 L40.488,6.608 C39.27,6.594 38.108,6.846 38.108,7.882 C38.108,8.554 38.542,8.862 39.088,8.862 C39.788,8.862 40.278,8.414 40.446,7.924 C40.488,7.798 40.488,7.672 40.488,7.546 Z M44.184,1.848 L45.878,1.372 L45.878,3.122 L47.516,3.122 L47.516,4.41 L45.878,4.41 L45.878,7.42 C45.878,8.26 46.102,8.68 46.76,8.68 C47.068,8.68 47.236,8.666 47.432,8.61 L47.46,9.912 C47.208,10.01 46.746,10.094 46.214,10.094 C45.57,10.094 45.052,9.884 44.73,9.534 C44.352,9.142 44.184,8.512 44.184,7.616 L44.184,4.41 L43.218,4.41 L43.218,3.122 L44.184,3.122 L44.184,1.848 Z M50.54,9.94 L48.818,9.94 L48.818,3.122 L50.54,3.122 L50.54,9.94 Z M49.686,0.28 C50.274,0.28 50.638,0.686 50.652,1.218 C50.652,1.722 50.274,2.142 49.672,2.142 C49.098,2.142 48.72,1.722 48.72,1.218 C48.72,0.686 49.112,0.28 49.686,0.28 Z M55.496,2.968 C57.526,2.968 58.884,4.396 58.884,6.468 C58.884,8.974 57.12,10.094 55.384,10.094 C53.466,10.094 51.968,8.778 51.968,6.58 C51.968,4.34 53.438,2.968 55.496,2.968 Z M55.454,4.214 C54.236,4.214 53.746,5.404 53.746,6.538 C53.746,7.854 54.404,8.848 55.44,8.848 C56.42,8.848 57.106,7.896 57.106,6.51 C57.106,5.446 56.63,4.214 55.454,4.214 Z M60.298,9.94 L60.298,5.152 C60.298,4.368 60.27,3.71 60.242,3.122 L61.74,3.122 L61.824,4.144 L61.866,4.144 C62.174,3.612 62.916,2.968 64.05,2.968 C65.24,2.968 66.472,3.738 66.472,5.894 L66.472,9.94 L64.75,9.94 L64.75,6.09 C64.75,5.11 64.386,4.368 63.448,4.368 C62.762,4.368 62.286,4.858 62.104,5.376 C62.048,5.516 62.02,5.726 62.02,5.922 L62.02,9.94 L60.298,9.94 Z M79.422,9.94 L79.24,6.09 C79.184,4.872 79.114,3.402 79.128,2.128 L79.086,2.128 C78.778,3.276 78.386,4.55 77.966,5.74 L76.58,9.828 L75.264,9.828 L74.004,5.796 C73.64,4.592 73.304,3.304 73.052,2.128 L73.024,2.128 C72.982,3.36 72.926,4.858 72.856,6.146 L72.646,9.94 L71.036,9.94 L71.666,0.504 L73.934,0.504 L75.166,4.298 C75.502,5.404 75.796,6.524 76.034,7.574 L76.076,7.574 C76.328,6.552 76.65,5.39 77.014,4.284 L78.316,0.504 L80.556,0.504 L81.102,9.94 L79.422,9.94 Z M88.13,5.852 L88.13,8.302 C88.13,8.918 88.158,9.52 88.242,9.94 L86.688,9.94 L86.562,9.184 L86.52,9.184 C86.114,9.716 85.4,10.094 84.504,10.094 C83.132,10.094 82.362,9.1 82.362,8.064 C82.362,6.356 83.888,5.474 86.408,5.488 L86.408,5.376 C86.408,4.928 86.226,4.186 85.022,4.186 C84.35,4.186 83.65,4.396 83.188,4.69 L82.852,3.57 C83.356,3.262 84.238,2.968 85.316,2.968 C87.5,2.968 88.13,4.354 88.13,5.852 Z M86.45,7.546 L86.45,6.608 C85.232,6.594 84.07,6.846 84.07,7.882 C84.07,8.554 84.504,8.862 85.05,8.862 C85.75,8.862 86.24,8.414 86.408,7.924 C86.45,7.798 86.45,7.672 86.45,7.546 Z M89Line truncated
<path d="M0.91,27.712 L0.91,20.376 C0.91,19.508 0.882,18.808 0.854,18.164 L1.946,18.164 L2.016,19.326 L2.044,19.326 C2.534,18.5 3.346,18.024 4.452,18.024 C6.104,18.024 7.336,19.41 7.336,21.454 C7.336,23.89 5.838,25.094 4.242,25.094 C3.346,25.094 2.562,24.702 2.156,24.03 L2.128,24.03 L2.128,27.712 L0.91,27.712 Z M2.128,21.006 L2.128,22.182 C2.128,22.364 2.142,22.532 2.184,22.686 C2.408,23.54 3.15,24.128 4.032,24.128 C5.334,24.128 6.09,23.064 6.09,21.51 C6.09,20.166 5.376,19.004 4.074,19.004 C3.234,19.004 2.436,19.592 2.212,20.516 C2.17,20.67 2.128,20.852 2.128,21.006 Z M11.746,18.024 C13.692,18.024 15.008,19.438 15.008,21.496 C15.008,24.002 13.258,25.094 11.634,25.094 C9.814,25.094 8.386,23.75 8.386,21.608 C8.386,19.354 9.884,18.024 11.746,18.024 Z M11.718,18.948 C10.276,18.948 9.646,20.292 9.646,21.566 C9.646,23.05 10.486,24.17 11.69,24.17 C12.866,24.17 13.748,23.064 13.748,21.538 C13.748,20.39 13.174,18.948 11.718,18.948 Z M15.694,18.164 L16.954,18.164 L17.864,21.608 C18.046,22.364 18.228,23.064 18.354,23.764 L18.396,23.764 C18.55,23.078 18.774,22.35 18.998,21.622 L20.104,18.164 L21.14,18.164 L22.19,21.552 C22.442,22.364 22.638,23.078 22.792,23.764 L22.834,23.764 C22.946,23.078 23.128,22.364 23.352,21.566 L24.318,18.164 L25.536,18.164 L23.352,24.94 L22.232,24.94 L21.196,21.706 C20.958,20.95 20.762,20.278 20.594,19.48 L20.566,19.48 C20.398,20.292 20.188,20.992 19.95,21.72 L18.858,24.94 L17.738,24.94 L15.694,18.164 Z M32.074,21.776 L27.314,21.776 C27.342,23.442 28.392,24.128 29.638,24.128 C30.52,24.128 31.066,23.974 31.514,23.778 L31.738,24.66 C31.304,24.856 30.548,25.094 29.47,25.094 C27.384,25.094 26.138,23.708 26.138,21.664 C26.138,19.62 27.342,18.024 29.316,18.024 C31.542,18.024 32.116,19.956 32.116,21.202 C32.116,21.454 32.102,21.636 32.074,21.776 Z M27.328,20.894 L30.926,20.894 C30.94,20.124 30.604,18.906 29.218,18.906 C27.958,18.906 27.426,20.04 27.328,20.894 Z M33.642,24.94 L33.642,20.278 C33.642,19.48 33.628,18.794 33.586,18.164 L34.664,18.164 L34.72,19.508 L34.762,19.508 C35.07,18.598 35.826,18.024 36.652,18.024 C36.778,18.024 36.876,18.038 36.988,18.052 L36.988,19.214 C36.862,19.186 36.736,19.186 36.568,19.186 C35.7,19.186 35.084,19.83 34.916,20.754 C34.888,20.922 34.874,21.132 34.874,21.328 L34.874,24.94 L33.642,24.94 Z M43.526,21.776 L38.766,21.776 C38.794,23.442 39.844,24.128 41.09,24.128 C41.972,24.128 42.518,23.974 42.966,23.778 L43.19,24.66 C42.756,24.856 42,25.094 40.922,25.094 C38.836,25.094 37.59,23.708 37.59,21.664 C37.59,19.62 38.794,18.024 40.768,18.024 C42.994,18.024 43.568,19.956 43.568,21.202 C43.568,21.454 43.554,21.636 43.526,21.776 Z M38.78,20.894 L42.378,20.894 C42.392,20.124 42.056,18.906 40.67,18.906 C39.41,18.906 38.878,20.04 38.78,20.894 Z M49.714,15 L50.932,15 L50.932,23.19 C50.932,23.792 50.96,24.478 50.988,24.94 L49.896,24.94 L49.84,23.764 L49.798,23.764 C49.434,24.52 48.622,25.094 47.516,25.094 C45.878,25.094 44.604,23.708 44.604,21.65 C44.59,19.396 46.004,18.024 47.642,18.024 C48.692,18.024 49.378,18.514 49.686,19.046 L49.714,19.046 L49.714,15 Z M49.714,22.098 L49.714,20.922 C49.714,20.768 49.7,20.558 49.658,20.404 C49.476,19.634 48.804,18.99 47.88,18.99 C46.606,18.99 45.85,20.11 45.85,21.594 C45.85,22.966 46.536,24.1 47.852,24.1 C48.678,24.1 49.434,23.54 49.658,22.63 C49.7,22.462 49.714,22.294 49.714,22.098 Z M55.958,23.19 L55.958,15 L57.176,15 L57.176,19.256 L57.204,19.256 C57.638,18.5 58.422,18.024 59.514,18.024 C61.208,18.024 62.384,19.424 62.384,21.468 C62.384,23.89 60.844,25.094 59.332,25.094 C58.352,25.094 57.568,24.716 57.05,23.834 L57.022,23.834 L56.952,24.94 L55.902,24.94 C55.93,24.478 55.958,23.792 55.958,23.19 Z M57.176,21.02 L57.176,22.224 C57.176,22.378 57.19,22.532 57.232,22.672 C57.456,23.526 58.184,24.114 59.08,24.114 C60.382,24.114 61.138,23.064 61.138,21.51 C61.138,20.152 60.438,18.99 59.108,18.99 C58.282,18.99 57.498,19.578 57.246,20.502 C57.204,20.656 57.176,20.824 57.176,21.02 Z M62.93,18.164 L64.274,18.164 L65.744,22.168 C65.912,22.616 66.08,23.148 66.192,23.554 L66.22,23.554 C66.346,23.148 66.486,22.63 66.654,22.14 L67.998,18.164 L69.3,18.164 L67.452,22.994 C66.57,25.318 65.968,26.494 65.128,27.236 C64.512,27.754 63.924,27.964 63.616,28.02 L63.308,26.998 C63.616,26.9 64.022,26.704 64.386,26.396 C64.722,26.13 65.128,25.654 65.422,25.024 C65.478,24.898 65.52,24.8 65.52,24.73 C65.52,24.66 65.492,24.562 65.422,24.408 L62.93,18.164 Z" id="poweredby" fill="#AAAAAA"></path>
<path d="M73.29,24.94 L73.29,15 L75.012,15 L75.012,24.94 L73.29,24.94 Z M79.982,17.968 C82.012,17.968 83.37,19.396 83.37,21.468 C83.37,23.974 81.606,25.094 79.87,25.094 C77.952,25.094 76.454,23.778 76.454,21.58 C76.454,19.34 77.924,17.968 79.982,17.968 Z M79.94,19.214 C78.722,19.214 78.232,20.404 78.232,21.538 C78.232,22.854 78.89,23.848 79.926,23.848 C80.906,23.848 81.592,22.896 81.592,21.51 C81.592,20.446 81.116,19.214 79.94,19.214 Z M89.558,23.456 L89.796,24.73 C89.432,24.898 88.718,25.08 87.864,25.08 C85.736,25.08 84.35,23.708 84.35,21.594 C84.35,19.55 85.75,17.968 88.144,17.968 C88.774,17.968 89.418,18.108 89.81,18.276 L89.502,19.578 C89.222,19.438 88.816,19.312 88.2,19.312 C86.884,19.312 86.1,20.278 86.114,21.524 C86.114,22.924 87.024,23.722 88.2,23.722 C88.788,23.722 89.222,23.596 89.558,23.456 Z M92.792,24.94 L91.07,24.94 L91.07,18.122 L92.792,18.122 L92.792,24.94 Z M91.938,15.28 C92.526,15.28 92.89,15.686 92.904,16.218 C92.904,16.722 92.526,17.142 91.924,17.142 C91.35,17.142 90.972,16.722 90.972,16.218 C90.972,15.686 91.364,15.28 91.938,15.28 Z M94.01,24.94 L94.01,23.946 L96.572,20.67 C96.922,20.25 97.216,19.914 97.566,19.522 L97.566,19.494 L94.262,19.494 L94.262,18.122 L99.666,18.122 L99.666,19.172 L97.174,22.378 C96.838,22.784 96.516,23.176 96.166,23.54 L96.166,23.568 L99.75,23.568 L99.75,24.94 L94.01,24.94 Z M106.638,22.014 L102.074,22.014 C102.116,23.246 103.068,23.778 104.174,23.778 C104.972,23.778 105.532,23.652 106.064,23.47 L106.316,24.646 C105.728,24.898 104.916,25.08 103.936,25.08 C101.724,25.08 100.422,23.722 100.422,21.636 C100.422,19.746 101.57,17.968 103.754,17.968 C105.966,17.968 106.694,19.788 106.694,21.286 C106.694,21.608 106.666,21.86 106.638,22.014 Z M102.074,20.81 L105.07,20.81 C105.084,20.18 104.804,19.144 103.656,19.144 C102.592,19.144 102.144,20.11 102.074,20.81 Z M108.724,25.094 C108.108,25.094 107.674,24.618 107.674,23.988 C107.674,23.344 108.122,22.882 108.738,22.882 C109.368,22.882 109.802,23.33 109.802,23.988 C109.802,24.618 109.382,25.094 108.724,25.094 Z M115.962,23.456 L116.2,24.73 C115.836,24.898 115.122,25.08 114.268,25.08 C112.14,25.08 110.754,23.708 110.754,21.594 C110.754,19.55 112.154,17.968 114.548,17.968 C115.178,17.968 115.822,18.108 116.214,18.276 L115.906,19.578 C115.626,19.438 115.22,19.312 114.604,19.312 C113.288,19.312 112.504,20.278 112.518,21.524 C112.518,22.924 113.428,23.722 114.604,23.722 C115.192,23.722 115.626,23.596 115.962,23.456 Z M120.442,17.968 C122.472,17.968 123.83,19.396 123.83,21.468 C123.83,23.974 122.066,25.094 120.33,25.094 C118.412,25.094 116.914,23.778 116.914,21.58 C116.914,19.34 118.384,17.968 120.442,17.968 Z M120.4,19.214 C119.182,19.214 118.692,20.404 118.692,21.538 C118.692,22.854 119.35,23.848 120.386,23.848 C121.366,23.848 122.052,22.896 122.052,21.51 C122.052,20.446 121.576,19.214 120.4,19.214 Z M125.244,24.94 L125.244,20.152 C125.244,19.368 125.216,18.71 125.188,18.122 L126.658,18.122 L126.742,19.13 L126.784,19.13 C127.106,18.598 127.722,17.968 128.884,17.968 C129.78,17.968 130.48,18.472 130.774,19.228 L130.802,19.228 C131.04,18.85 131.32,18.57 131.628,18.374 C132.02,18.108 132.454,17.968 133.028,17.968 C134.148,17.968 135.296,18.738 135.296,20.922 L135.296,24.94 L133.616,24.94 L133.616,21.174 C133.616,20.04 133.224,19.368 132.398,19.368 C131.81,19.368 131.376,19.788 131.194,20.278 C131.138,20.432 131.11,20.656 131.11,20.852 L131.11,24.94 L129.43,24.94 L129.43,20.992 C129.43,20.04 129.052,19.368 128.254,19.368 C127.61,19.368 127.176,19.872 127.008,20.334 C126.952,20.516 126.924,20.712 126.924,20.908 L126.924,24.94 L125.244,24.94 Z" id="locize.com" fill="#888888"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 59 KiB

@@ -127,7 +127,7 @@ through the trouble of using AWS/GCP/Azure, it's more likely you're doing so to
avoid using a proxy or to simplify authentication.
If that is the case, check out some of our more advanced `docker` deployments
that target these providers from the left-hand sidebar.
that target these providers from the left-hand sidepanel.
These guides can be a bit longer and a update more frequently. To provide
accurate documentation, we will link to each provider's own recommended steps:
+9 -2
View File
@@ -29,11 +29,17 @@ For our purposes, we will be using `Orthanc`, but you can see a list of
- Docker
- [Docker for Mac](https://docs.docker.com/docker-for-mac/)
- [Docker for Windows](https://docs.docker.com/docker-for-windows/)
- [Docker for Windows (recommended)](https://docs.docker.com/docker-for-windows/)
- [Docker Toolbox for Windows](https://docs.docker.com/toolbox/toolbox_install_windows/)
_Not sure if you have `docker` installed already? Try running `docker --version`
in command prompt or terminal_
> If you are using `Docker Toolbox` you need to change the _proxy_ parameter in
> _package.json_ to http://192.168.99.100:8042 or the ip docker-machine ip
> throws. This is the value [`react-scripts`][react-proxy] uses to proxy
> requests
### Running Orthanc
_Start Orthanc:_
@@ -112,7 +118,7 @@ window.config = {
},
],
},
}
};
```
To learn more about how you can configure the OHIF Viewer, check out our
@@ -142,6 +148,7 @@ _Feel free to make a Pull Request if you want to add to this list._
[dicom-web]: https://en.wikipedia.org/wiki/DICOMweb
[storescu]: http://support.dcmtk.org/docs/storescu.html
[cra-start]: https://github.com/facebook/create-react-app#npm-start-or-yarn-start
[react-proxy]: https://facebook.github.io/create-react-app/docs/proxying-api-requests-in-development#configuring-the-proxy-manually
<!-- Archives -->
[dcm4chee]: https://github.com/dcm4che/dcm4chee-arc-light
[dcm4chee-docker]: https://github.com/dcm4che/dcm4chee-arc-light/wiki/Running-on-Docker
+317
View File
@@ -0,0 +1,317 @@
# Translating
OHIF supports internationalization using [i18next](https://www.i18next.com/)
through the npm package [@ohif/i18n](https://www.npmjs.com/package/@ohif/i18n),
where is the main instance of i18n containing several languages and tools.
<div class='row'>
<div class='column'>
<p>Our translation management is powered by <a href="https://locize.com/" target="_blank" rel="noopener noreferrer">Locize</a> through their generous support of open source.</p>
</div>
<div class='column'>
<a href="https://locize.com/" target="_blank" rel="noopener noreferrer" style='padding: 20px'>
<img src="../assets/img/locizeSponsor.svg" alt="Locize Translation Management Logo">
</a>
</div>
</div>
### Installing
```bash
yarn add @ohif/i18n
# OR
npm install --save @ohif/i18n
```
### How it works
After installing `@ohif/i18n` npm package, the translation function
[t](https://www.i18next.com/overview/api#t) can be used [with](#with-react) or
[without](#without-react) React.
A translation will occur every time a text match happens in a
[t](https://www.i18next.com/overview/api#t) function.
The [t](https://www.i18next.com/overview/api#t) function is responsible for
getting translations using all the power of i18next.
E.g.
Before:
```html
<div>my translated text</div>
```
After:
```html
<div>{t('my translated text')}</div>
```
If the translation.json file contains a key that matches the HTML content e.g.
`my translated text`, it will be replaced automatically by the
[t](https://www.i18next.com/overview/api#t) function.
---
#### With React
This section will introduce you to [react-i18next](https://react.i18next.com/)
basics and show how to implement the [t](https://www.i18next.com/overview/api#t)
function easily.
##### Using HOCs
In most cases we used
[High Order Components](https://react.i18next.com/latest/withtranslation-hoc) to
share the `t` function among OHIF's components.
E.g.
```js
import React from 'react';
import { withTranslation } from '@ohif/i18n';
function MyComponent({ t, i18n }) {
return <p>{t('my translated text')}</p>;
}
export default withTranslation('MyNameSpace')(MyComponent);
```
> Important: if you are using React outside the OHIF Viewer, check the
> [I18nextProvider](#using-outside-of-ohif-viewer) section, `withTranslation`
> HOC doesnt works without a I18nextProvider
##### Using Hooks
Also, it's possible to get the `t` tool using
[React Hooks](https://react.i18next.com/latest/usetranslation-hook), but it
requires at least React > 16.8 😉
#### Using outside of OHIF viewer
OHIF Viewer already sets a main
[I18nextProvider](https://react.i18next.com/latest/i18nextprovider) connected to
the shared i18n instance from `@ohif/i18n`, all extensions inside OHIF Viewer
will share this same provider at the end, you don't need to set new providers at
all.
But, if you need to use it completely outside of OHIF viewer, you can set the
I18nextProvider this way:
```js
import i18n from '@ohif/i18n';
import { I18nextProvider } from 'react-i18next';
import App from './App';
<I18nextProvider i18n={i18n}>
<App />
</I18nextProvider>;
```
After setting `I18nextProvider` in your React App, all translations from
`@ohif/i18n` should be available following the basic [With React](#with-react)
usage.
---
#### Without React
When needed, you can also use available translations _without React_.
E.g.
```js
import { T } from '@ohif/i18n';
console.log(T('my translated text'));
console.log(T('$t(Common:Play) my translated text'));
```
---
# Main Concepts While Translating
## - Namespaces
Namespaces are being used to organize translations in smaller portions, combined
semantically or by use. Each `.json` file inside `@ohif/i18n` npm package
becomes a new namespace automatically.
- Buttons: All buttons translations
- CineDialog: Translations for the toll tips inside the Cine Player Dialog
- Common: all common jargons that can be reused like `t('$t(common:image)')`
- Header: translations related to OHIF's Header Top Bar
- MeasurementTable - Translations for the react-viewerbase Measurement Table
- UserPreferencesModal - Translations for the react-viewerbase Preferences Modal
### How to use another NameSpace inside the current NameSpace?
i18next provides a parsing feature able to get translations strings from any
NameSpace, like this following example getting data from `Common` NameSpace:
```
$t(Common:Reset)
```
## - Extending Languages in @ohif/i18n
Sometimes, even using the same language, some nouns or jargons can change
according to the country, states or even from Hospital to Hospital.
In this cases, you don't need to set an entire language again, you can extend
languages creating a new folder inside a pre existent language folder and
@ohif/i18n will do the hard work.
This new folder must to be called with a double character name, like the `UK` in
the following file tree:
```bash
|-- src
|-- locales
index.js
|-- en
|-- Buttons.json
index.js
| UK
|-- Buttons.js
indes.js
| US
|-- Buttons.js
index.js
...
```
All properties inside a Namespace will be merged in the new sub language, e.g
`en-US` and `en-UK` will merge the props with `en`, using i18next's fallback
languages tool.
You will need to export all Json files in your `index.js` file, mounting an
object like this:
```js
{
en: {
NameSpace: {
keyWord1: 'keyWord1Translation',
keyWord2: 'keyWord2Translation',
keyWord3: 'keyWord3Translation',
}
},
'en-UK': {
NameSpace: {
keyWord1: 'keyWord1DifferentTranslation',
}
}
}
```
Please check the `index.js` files inside locales folder for an example of this
exporting structure.
### - Extending languages dynamically
You have access to the i18next instance, so you can use the
[addResourceBundle](https://www.i18next.com/how-to/add-or-load-translations#add-after-init)
method to add and change language resources as needed.
E.g.
```js
import { i18n } from '@ohif/i18n';
i18next.addResourceBundle('pt-BR', 'Buttons', {
Angle: 'Ângulo',
});
```
---
### How to set a whole new language
To set a brand new language you can do it in two different ways:
- Opening a pull request for `@ohif/i18n` and sharing the translation with the
community. 😍 Please see [Contributing](#contributing-with-new-languages)
section for further information.
- Setting it only in your project or extension:
You'll need a a final object like the following, what is setting French as
language, and send it to `addLocales` method.
```js
const newLanguage =
{
fr: {
Commons: {
"Reset": "Réinitialiser",
"Previous": "Précédent",
},
Buttons: {
"Rectangle": "Rectangle",
"Circle": "Cercle",
}
}
```
To make it easier to translate, you can copy the .json files in the /locales
folder and theirs index.js exporters, keeping same keys and NameSpaces.
Importing the main index.js file, will provide you an Object as expected by the
method `addlocales`;
E.g. of `addLocales` usage
```js
import { addLocales } from '@ohif/i18n';
import locales from './locales/index.js';
addLocales(locales);
```
You can also set them manually, one by one, using this
[method](#extending-languages-dynamically).
---
## Language Detections
@ohif/i18n uses
[i18next-browser-languageDetector](https://github.com/i18next/i18next-browser-languageDetector)
to manage detections, also exports a method called initI18n that accepts a new
detector config as parameter.
### Changing the language
OHIF Viewer accepts a query param called `lng` in the url to change the
language.
E.g.
```
https://docs.ohif.org/demo/?lng=es-MX
```
### Language Persistence
The user's language preference is kept automatically by the detector and stored
at a cookie called 'i18next', and in a localstorage key called 'i18nextLng'.
These names can be changed with a new
[Detector Config](https://github.com/i18next/i18next-browser-languageDetector).
## Debugging translations
There is an environment variable responsible for debugging the translations,
called `REACT_APP_I18N_DEBUG`.
Run the project as following to get full debug information:
```bash
REACT_APP_I18N_DEBUG=true yarn run dev
```
### Contributing with new languages
Contributions of any kind are welcome! Please check the
[instructions](https://docs.ohif.org/contributing.html).
+1 -1
View File
@@ -35,7 +35,7 @@
"gitbook-plugin-ga": "^2.0.0",
"gitbook-plugin-github": "^3.0.0",
"gitbook-plugin-sitemap": "^1.2.0",
"gitbook-plugin-theme-cornerstone": "^1.1.2",
"gitbook-plugin-theme-cornerstone": "^1.1.4",
"gitbook-plugin-versions": "^2.1.4"
},
"devDependencies": {
@@ -0,0 +1,105 @@
/**
*
*/
export default {
/**
* Only required property. Should be a unique value across all extensions.
*/
id: 'example-extension',
/**
* LIFECYCLE HOOKS
*/
preRegistration(extensionConfiguration) {},
/**
* MODULE GETTERS
*/
getViewportModule() {
return '... react component ...';
},
getSopClassHandlerModule() {
return sopClassHandlerModule;
},
getPanelModule() {
return panelModule;
},
getToolbarModule() {
return panelModule;
},
getCommandsModule(/* store */) {
return commandsModule;
},
};
/**
*
*/
const commandsModule = {
actions: {
// Store Contexts + Options
exampleAction: ({ viewports, param1 }) => {
console.log(`There are ${viewports.length} viewports`);
console.log(`param1's value is: ${param1}`);
},
},
definitions: {
exampleActionDef: {
commandFn: this.actions.exampleAction,
storeContexts: ['viewports'],
options: { param1: 'hello world' },
},
},
};
/**
*
*/
const sopClassHandlerModule = {
id: 'OHIFDicomHtmlSopClassHandler',
sopClassUids: Object.values({
BASIC_TEXT_SR: '1.2.840.10008.5.1.4.1.1.88.11',
ENHANCED_SR: '1.2.840.10008.5.1.4.1.1.88.22',
COMPREHENSIVE_SR: '1.2.840.10008.5.1.4.1.1.88.33',
PROCEDURE_LOG_STORAGE: '1.2.840.10008.5.1.4.1.1.88.40',
MAMMOGRAPHY_CAD_SR: '1.2.840.10008.5.1.4.1.1.88.50',
CHEST_CAD_SR: '1.2.840.10008.5.1.4.1.1.88.65',
X_RAY_RADIATION_DOSE_SR: '1.2.840.10008.5.1.4.1.1.88.67',
}),
getDisplaySetFromSeries(series, study, dicomWebClient, authorizationHeaders) {
const instance = series.getFirstInstance();
return {
plugin: 'html',
displaySetInstanceUid: 0, //utils.guid(),
wadoRoot: study.getData().wadoRoot,
wadoUri: instance.getData().wadouri,
sopInstanceUid: instance.getSOPInstanceUID(),
seriesInstanceUid: series.getSeriesInstanceUID(),
studyInstanceUid: study.getStudyInstanceUID(),
authorizationHeaders,
};
},
};
/**
*
*/
const panelModule = {
menuOptions: [
{
icon: 'th-list',
label: 'Segments',
target: 'segment-panel',
},
],
components: [
{
id: 'segment-panel',
component: '... react component ...',
},
],
defaultContext: ['VIEWER'],
};
@@ -1,3 +1,9 @@
{
"singleQuote": true
}
"trailingComma": "es5",
"printWidth": 80,
"proseWrap": "always",
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"endOfLine": "lf"
}
@@ -1 +1,89 @@
# @ohif/extension-cornerstone
![npm (scoped)](https://img.shields.io/npm/v/@ohif/extension-cornerstone.svg?style=flat-square)
This extension adds support for viewing and manipulating 2D medical images via a
viewport. The underlying implementation wraps the
`cornerstonejs/react-cornerstone-viewport`, and provides basic commands and
toolbar buttons for common actions.
<!-- TODO: Simple image or GIF? -->
#### Index
Extension Id: `cornerstone`
- [Commands Module](#commands-module)
- [Toolbar Module](#toolbar-module)
- [Viewport Module](#viewport-module)
## Commands Module
This extensions includes the following `Commands` and `Command Definitions`.
These can be registered with `@ohif/core`'s `CommandManager`. After registering
the commands, they can be bound to `hotkeys` using the `HotkeysManager` and
listed in the `UserPreferences` modal.
You can read more about [`Commands`][docs-commands], [`Hotkeys`][docs-hotkeys],
and the [`UserPreferences` Modal][docs-userprefs] in their respective locations
in the OHIF Viewer's documentation.
| Command Name | Description | Store Contexts |
| ---------------------------- | --------------------------------------- | -------------- |
| `rotateViewportCW` | | viewports |
| `rotateViewportCCW` | | viewports |
| `invertViewport` | | viewports |
| `flipViewportVertical` | | viewports |
| `flipViewportHorizontal` | | viewports |
| `scaleUpViewport` | | viewports |
| `scaleDownViewport` | | viewports |
| `fitViewportToWindow` | | viewports |
| `resetViewport` | | viewports |
| clearAnnotations | TODO | |
| next/previous Image | TODO | |
| first/last Image | TODO | |
| `nextViewportDisplaySet` | | |
| `previousViewportDisplaySet` | | |
| `setToolActive` | Activates tool for primary button/touch | |
## Toolbar Module
Our toolbar module contains definitions for:
- `StackScroll`
- `Zoom`
- `Wwwc`
- `Pan`
- `Length`
- `Angle`
- `Reset`
- `Cine`
All use the `ACTIVE_VIEWPORT::CORNERSTONE` context.
## Viewport Module
Our Viewport wraps [cornerstonejs/react-cornerstone-viewport][react-viewport]
and is connected the redux store. This module is the most prone to change as we
hammer out our Viewport interface.
## Resources
### Repositories
- [cornerstonejs/react-cornerstone-viewport][react-viewport]
- [cornerstonejs/cornerstoneTools][cornerstone-tools]
- [cornerstonejs/cornerstone][cornerstone]
<!--
Links
-->
<!-- prettier-ignore-start -->
[docs-commands]: https://www.com
[docs-hotkeys]: https://www.com
[docs-userprefs]: htt
[react-viewport]: https://github.com/cornerstonejs/react-cornerstone-viewport
[cornerstone-tools]: https://github.com/cornerstonejs/cornerstoneTools
[cornerstone]: https://github.com/cornerstonejs/cornerstone
<!-- prettier-ignore-end -->
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-cornerstone",
"version": "0.0.34",
"version": "0.0.39",
"description": "OHIF extension for Cornerstone",
"author": "OHIF",
"license": "MIT",
@@ -26,7 +26,7 @@
"dcmjs": "^0.3.8",
"dicom-parser": "^1.8.3",
"hammerjs": "^2.0.8",
"ohif-core": "^0.3.5",
"ohif-core": "^0.6.0",
"prop-types": "^15.6.2",
"react": "^15.0.0 || ^16.0.0",
"react-dom": "^15.0.0 || ^16.0.0",
@@ -1,22 +1,26 @@
import { connect } from 'react-redux';
import CornerstoneViewport from 'react-cornerstone-viewport';
import OHIF from 'ohif-core';
import { connect } from 'react-redux';
import throttle from 'lodash.throttle';
const {
setViewportActive,
setViewportSpecificData,
clearViewportSpecificData
} = OHIF.redux.actions;
const { setViewportActive, setViewportSpecificData } = OHIF.redux.actions;
const mapStateToProps = (state, ownProps) => {
const activeButton = state.tools.buttons.find(tool => tool.active === true);
let dataFromStore;
if (state.extensions && state.extensions.cornerstone) {
dataFromStore = state.extensions.cornerstone;
}
// TODO: This should be extension configuration
// ...dataFromStore -->
// availableTools,
// onNewImage,
// onRightClick,
// onTouchPress,
// onTouchStart,
// onMouseClick,
// If this is the active viewport, enable prefetching.
const { viewportIndex } = ownProps; //.viewportData;
const isActive = viewportIndex === state.viewports.activeViewportIndex;
@@ -26,12 +30,14 @@ const mapStateToProps = (state, ownProps) => {
return {
layout: state.viewports.layout,
isActive,
activeTool: activeButton && activeButton.command,
// TODO: Need a cleaner and more versatile way.
// Currently justing using escape hatch + commands
// activeTool: activeButton && activeButton.command,
...dataFromStore,
enableStackPrefetch: isActive,
//stack: viewportSpecificData.stack,
cineToolData: viewportSpecificData.cine,
viewport: viewportSpecificData.viewport
viewport: viewportSpecificData.viewport,
};
};
@@ -47,10 +53,6 @@ const mapDispatchToProps = (dispatch, ownProps) => {
dispatch(setViewportSpecificData(viewportIndex, data));
},
clearViewportSpecificData: () => {
dispatch(clearViewportSpecificData(viewportIndex));
},
/**
* Our component "enables" the underlying dom element on "componentDidMount"
* It listens for that event, and then emits the enabledElement. We can grab
@@ -61,7 +63,9 @@ const mapDispatchToProps = (dispatch, ownProps) => {
const enabledElement = event.detail.element;
dispatch(
setViewportSpecificData(viewportIndex, {
dom: enabledElement
// TODO: Hack to make sure our plugin info is available from the outset
plugin: 'cornerstone',
dom: enabledElement,
})
);
},
@@ -70,18 +74,18 @@ const mapDispatchToProps = (dispatch, ownProps) => {
const {
onAdded,
onRemoved,
onModified
onModified,
} = OHIF.measurements.MeasurementHandlers;
const actions = {
added: onAdded,
removed: onRemoved,
modified: throttle(event => {
return onModified(event);
}, 300)
}, 300),
};
return actions[action](event);
}
},
};
};
@@ -1,29 +0,0 @@
import { connect } from 'react-redux';
import { ToolbarSection } from 'react-viewerbase';
import OHIF from 'ohif-core'
const { setToolActive } = OHIF.redux.actions;
const mapStateToProps = state => {
const activeButton = state.tools.buttons.find(tool => tool.active === true);
return {
buttons: state.tools.buttons,
activeCommand: activeButton && activeButton.command
};
};
const mapDispatchToProps = dispatch => {
return {
setToolActive: tool => {
dispatch(setToolActive(tool.command))
}
};
};
const ConnectedToolbarSection = connect(
mapStateToProps,
mapDispatchToProps
)(ToolbarSection);
export default ConnectedToolbarSection;
@@ -1,65 +0,0 @@
import React, { Component } from 'react';
import OHIFCornerstoneViewport from './OHIFCornerstoneViewport.js';
import ToolbarModule from './ToolbarModule.js';
/**
* Pass in 'children' to a React component. The purpose of this is to
* allow end users of this extension to pass in components which will
* be rendered on top of the base components.
*
* @param WrappedComponent
* @param children
* @return {function(*): *}
*/
function componentWithProps(WrappedComponent, children, customProps) {
return function(props) {
const extraProps = {
customProps
};
if (children.viewport) {
extraProps.children = children.viewport;
}
const mergedProps = Object.assign({}, props, extraProps);
return <WrappedComponent {...mergedProps} />;
};
}
// Note: If you are authoring extensions which use stateful libraries (e.g. cornerstone-core, react-redux) as peerDependencies and are also duplicated at the application level, try using 'yalc' to link it to the application, rather than yarn link. This can help fix 'module not found' issues.
// https://github.com/whitecolor/yalc
export default class OHIFCornerstoneExtension {
constructor(props) {
const { children = {}, customProps = {} } = props;
this.children = children;
this.customProps = customProps;
}
/**
* Extension ID is a unique id, might be used for namespacing extension specific redux actions/reducers (?)
*/
getExtensionId() {
return 'cornerstone';
}
getViewportModule() {
return componentWithProps(
OHIFCornerstoneViewport,
this.children,
this.customProps
);
}
getSopClassHandler() {
return null;
}
getPanelModule() {
return null;
}
getToolbarModule() {
return ToolbarModule;
}
}
@@ -1,9 +1,9 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import OHIF from 'ohif-core';
import ConnectedCornerstoneViewport from './ConnectedCornerstoneViewport';
import OHIF from 'ohif-core';
import PropTypes from 'prop-types';
import cornerstone from 'cornerstone-core';
import './config';
import handleSegmentationStorage from './handleSegmentationStorage.js';
const { StackManager } = OHIF.utils;
@@ -18,7 +18,7 @@ cornerstone.metaData.addProvider(
StackManager.setMetadataProvider(metadataProvider);
const SOP_CLASSES = {
SEGMENTATION_STORAGE: '1.2.840.10008.5.1.4.1.1.66.4'
SEGMENTATION_STORAGE: '1.2.840.10008.5.1.4.1.1.66.4',
};
const specialCaseHandlers = {};
@@ -28,11 +28,11 @@ specialCaseHandlers[
class OHIFCornerstoneViewport extends Component {
state = {
viewportData: null
viewportData: null,
};
static defaultProps = {
customProps: {}
customProps: {},
};
static propTypes = {
@@ -40,7 +40,7 @@ class OHIFCornerstoneViewport extends Component {
displaySet: PropTypes.object,
viewportIndex: PropTypes.number,
children: PropTypes.node,
customProps: PropTypes.object
customProps: PropTypes.object,
};
static id = 'OHIFCornerstoneViewport';
@@ -54,31 +54,60 @@ class OHIFCornerstoneViewport extends Component {
StackManager.clearStacks();
}
/**
* Obtain the CornerstoneTools Stack for the specified display set.
*
* @param {Object[]} studies
* @param {String} studyInstanceUid
* @param {String} displaySetInstanceUid
* @param {String} [sopInstanceUid]
* @param {Number} [frameIndex=1]
* @return {Object} CornerstoneTools Stack
*/
static getCornerstoneStack(
studies,
studyInstanceUid,
displaySetInstanceUid,
sopInstanceUid,
frameIndex
frameIndex = 0
) {
if (!studies || !studies.length) {
throw new Error('Studies not provided.');
}
if (!studyInstanceUid) {
throw new Error('StudyInstanceUID not provided.');
}
if (!displaySetInstanceUid) {
throw new Error('StudyInstanceUID not provided.');
}
// Create shortcut to displaySet
const study = studies.find(
study => study.studyInstanceUid === studyInstanceUid
);
if (!study) {
throw new Error('Study not found.');
}
const displaySet = study.displaySets.find(set => {
return set.displaySetInstanceUid === displaySetInstanceUid;
});
if (!displaySet) {
throw new Error('Display Set not found.');
}
// Get stack from Stack Manager
const storedStack = StackManager.findOrCreateStack(study, displaySet);
// Clone the stack here so we don't mutate it
const stack = Object.assign({}, storedStack);
stack.currentImageIdIndex = frameIndex;
if (frameIndex !== undefined) {
stack.currentImageIdIndex = frameIndex;
} else if (sopInstanceUid) {
if (sopInstanceUid) {
const index = stack.imageIds.findIndex(imageId => {
const sopCommonModule = cornerstone.metaData.get(
'sopCommonModule',
@@ -94,10 +123,10 @@ class OHIFCornerstoneViewport extends Component {
if (index > -1) {
stack.currentImageIdIndex = index;
} else {
stack.currentImageIdIndex = 0;
console.warn(
'SOPInstanceUID provided was not found in specified DisplaySet'
);
}
} else {
stack.currentImageIdIndex = 0;
}
return stack;
@@ -154,7 +183,7 @@ class OHIFCornerstoneViewport extends Component {
viewportData = {
studyInstanceUid,
displaySetInstanceUid,
stack
stack,
};
break;
@@ -170,7 +199,7 @@ class OHIFCornerstoneViewport extends Component {
displaySetInstanceUid,
sopClassUids,
sopInstanceUid,
frameIndex
frameIndex,
} = displaySet;
if (sopClassUids && sopClassUids.length > 1) {
@@ -190,7 +219,7 @@ class OHIFCornerstoneViewport extends Component {
frameIndex
).then(viewportData => {
this.setState({
viewportData
viewportData,
});
});
}
@@ -221,7 +250,7 @@ class OHIFCornerstoneViewport extends Component {
childrenWithProps = this.props.children.map((child, index) => {
return React.cloneElement(child, {
viewportIndex: this.props.viewportIndex,
key: index
key: index,
});
});
}
@@ -1,43 +0,0 @@
import React, { Component } from 'react';
import ConnectedCineDialog from './ConnectedCineDialog';
import ConnectedToolbarSection from './ConnectedToolbarSection';
import { ToolbarButton } from 'react-viewerbase';
class ToolbarModule extends Component {
state = {
cineDialogOpen: false
};
onClickCineToolbarButton = () => {
this.setState({
cineDialogOpen: !this.state.cineDialogOpen
});
};
render() {
const cineDialogContainerStyle = {
display: this.state.cineDialogOpen ? 'block' : 'none',
position: 'absolute',
top: '82px',
zIndex: 999
};
return (
<div className="ToolbarModule">
<ConnectedToolbarSection />
<ToolbarButton
active={this.state.cineDialogOpen}
onClick={this.onClickCineToolbarButton}
text="CINE"
icon="youtube"
/>
<div className="CineDialogContainer" style={cineDialogContainerStyle}>
<ConnectedCineDialog />
</div>
</div>
);
}
}
export default ToolbarModule;
@@ -0,0 +1,235 @@
import cornerstone from 'cornerstone-core';
import cornerstoneTools from 'cornerstone-tools';
import OHIF from 'ohif-core';
const actions = {
rotateViewport: ({ viewports, rotation }) => {
const enabledElement = _getActiveViewportEnabledElement(
viewports.viewportSpecificData,
viewports.activeViewportIndex
);
if (enabledElement) {
let viewport = cornerstone.getViewport(enabledElement);
viewport.rotation += rotation;
cornerstone.setViewport(enabledElement, viewport);
}
},
flipViewportHorizontal: ({ viewports }) => {
const enabledElement = _getActiveViewportEnabledElement(
viewports.viewportSpecificData,
viewports.activeViewportIndex
);
if (enabledElement) {
let viewport = cornerstone.getViewport(enabledElement);
viewport.hflip = !viewport.hflip;
cornerstone.setViewport(enabledElement, viewport);
}
},
flipViewportVertical: ({ viewports }) => {
const enabledElement = _getActiveViewportEnabledElement(
viewports.viewportSpecificData,
viewports.activeViewportIndex
);
if (enabledElement) {
let viewport = cornerstone.getViewport(enabledElement);
viewport.vflip = !viewport.vflip;
cornerstone.setViewport(enabledElement, viewport);
}
},
scaleViewport: ({ viewports, direction }) => {
const enabledElement = _getActiveViewportEnabledElement(
viewports.viewportSpecificData,
viewports.activeViewportIndex
);
const step = direction * 0.15;
if (enabledElement) {
if (step) {
let viewport = cornerstone.getViewport(enabledElement);
viewport.scale += step;
cornerstone.setViewport(enabledElement, viewport);
} else {
cornerstone.fitToWindow(enabledElement);
}
}
},
resetViewport: ({ viewports }) => {
const enabledElement = _getActiveViewportEnabledElement(
viewports.viewportSpecificData,
viewports.activeViewportIndex
);
if (enabledElement) {
cornerstone.reset(enabledElement);
}
},
invertViewport: ({ viewports }) => {
const enabledElement = _getActiveViewportEnabledElement(
viewports.viewportSpecificData,
viewports.activeViewportIndex
);
if (enabledElement) {
let viewport = cornerstone.getViewport(enabledElement);
viewport.invert = !viewport.invert;
cornerstone.setViewport(enabledElement, viewport);
}
},
// TODO: this is receiving `evt` from `ToolbarRow`. We could use it to have
// better mouseButtonMask sets.
setToolActive: ({ toolName }) => {
if (!toolName) {
console.warn('No toolname provided to setToolActive command');
}
cornerstoneTools.setToolActive(toolName, { mouseButtonMask: 1 });
},
updateViewportDisplaySet: ({ direction }) => {
// TODO
console.warn('updateDisplaySet: ', direction);
},
clearAnnotations: ({ viewports }) => {
const element = _getActiveViewportEnabledElement(
viewports.viewportSpecificData,
viewports.activeViewportIndex
);
if (!element) {
return;
}
const enabledElement = cornerstone.getEnabledElement(element);
if (!enabledElement || !enabledElement.image) {
return;
}
const {
toolState,
} = cornerstoneTools.globalImageIdSpecificToolStateManager;
if (
!toolState ||
toolState.hasOwnProperty(enabledElement.image.imageId) === false
) {
return;
}
const imageIdToolState = toolState[enabledElement.image.imageId];
const measurementsToRemove = [];
Object.keys(imageIdToolState).forEach(toolType => {
const { data } = imageIdToolState[toolType];
data.forEach(measurementData => {
const { _id, lesionNamingNumber, measurementNumber } = measurementData;
if (!_id) {
return;
}
measurementsToRemove.push({
toolType,
_id,
lesionNamingNumber,
measurementNumber,
});
});
});
measurementsToRemove.forEach(measurementData => {
OHIF.measurements.MeasurementHandlers.onRemoved({
detail: {
toolType: measurementData.toolType,
measurementData,
},
});
});
},
};
const definitions = {
rotateViewportCW: {
commandFn: actions.rotateViewport,
storeContexts: ['viewports'],
options: { rotation: 90 },
},
rotateViewportCCW: {
commandFn: actions.rotateViewport,
storeContexts: ['viewports'],
options: { rotation: -90 },
},
invertViewport: {
commandFn: actions.invertViewport,
storeContexts: ['viewports'],
options: {},
},
flipViewportVertical: {
commandFn: actions.flipViewportVertical,
storeContexts: ['viewports'],
options: {},
},
flipViewportHorizontal: {
commandFn: actions.flipViewportHorizontal,
storeContexts: ['viewports'],
options: {},
},
scaleUpViewport: {
commandFn: actions.scaleViewport,
storeContexts: ['viewports'],
options: { direction: 1 },
},
scaleDownViewport: {
commandFn: actions.scaleViewport,
storeContexts: ['viewports'],
options: { direction: -1 },
},
fitViewportToWindow: {
commandFn: actions.scaleViewport,
storeContexts: ['viewports'],
options: { direction: 0 },
},
resetViewport: {
commandFn: actions.resetViewport,
storeContexts: ['viewports'],
options: {},
},
clearAnnotations: {
commandFn: actions.clearAnnotations,
storeContexts: ['viewports'],
options: {},
},
// TODO: Next/Previous image
// TODO: First/Last image
// Next/Previous series/DisplaySet
nextViewportDisplaySet: {
commandFn: actions.updateViewportDisplaySet,
storeContexts: [],
options: { direction: 1 },
},
previousViewportDisplaySet: {
commandFn: actions.updateViewportDisplaySet,
storeContexts: [],
options: { direction: -1 },
},
// TOOLS
setToolActive: {
commandFn: actions.setToolActive,
storeContexts: [],
options: {},
},
};
/**
* Grabs `dom` reference for the enabledElement of
* the active viewport
*/
function _getActiveViewportEnabledElement(viewports, activeIndex) {
const activeViewport = viewports[activeIndex] || {};
return activeViewport.dom;
}
export default {
actions,
definitions,
defaultContext: 'ACTIVE_VIEWPORT::CORNERSTONE',
};
@@ -1,28 +0,0 @@
import cornerstone from 'cornerstone-core';
import cornerstoneMath from 'cornerstone-math';
import cornerstoneTools from 'cornerstone-tools';
import Hammer from 'hammerjs';
// For debugging
window.cornerstoneTools = cornerstoneTools;
cornerstoneTools.external.cornerstone = cornerstone;
cornerstoneTools.external.Hammer = Hammer;
cornerstoneTools.external.cornerstoneMath = cornerstoneMath;
cornerstoneTools.init();
// Set the tool font and font size
// context.font = "[style] [variant] [weight] [size]/[line height] [font family]";
const fontFamily =
'Roboto, OpenSans, HelveticaNeue-Light, Helvetica Neue Light, Helvetica Neue, Helvetica, Arial, Lucida Grande, sans-serif';
cornerstoneTools.textStyle.setFont(`16px ${fontFamily}`);
// Set the tool width
cornerstoneTools.toolStyle.setToolWidth(2);
// Set color for inactive tools
cornerstoneTools.toolColors.setToolColor('rgb(255, 255, 0)');
// Set color for active tools
cornerstoneTools.toolColors.setActiveColor('rgb(0, 255, 0)');
cornerstoneTools.store.state.touchProximity = 40;
@@ -1,7 +1,8 @@
import * as dcmjs from 'dcmjs';
import OHIF from 'ohif-core';
import cornerstone from 'cornerstone-core';
import cornerstoneTools from 'cornerstone-tools';
import * as dcmjs from 'dcmjs';
const { StackManager } = OHIF.utils;
@@ -27,28 +28,6 @@ function getDisplaySetsBySeries(studies, studyInstanceUid, seriesInstanceUid) {
});
}
function getCornerstoneStack(studies, studyInstanceUid, displaySetInstanceUid) {
const study = studies.find(
study => study.studyInstanceUid === studyInstanceUid
);
// Create shortcut to displaySet
const displaySet = getDisplaySet(
studies,
studyInstanceUid,
displaySetInstanceUid
);
// Get stack from Stack Manager
const stack = StackManager.findOrCreateStack(study, displaySet);
// Clone the stack here so we don't mutate it later
const stackClone = Object.assign({}, stack);
stackClone.currentImageIdIndex = 0;
return stackClone;
}
function parseSeg(arrayBuffer, imageIds) {
return dcmjs.adapters.Cornerstone.Segmentation.generateToolState(
imageIds,
@@ -77,7 +56,7 @@ function retrieveDicomData(wadoUri) {
// TODO: Authorization header depends on the server. If we ever have multiple servers
// we will need to figure out how / when to pass this information in.
return fetch(wadoUri, {
headers: OHIF.DICOMWeb.getAuthorizationHeader()
headers: OHIF.DICOMWeb.getAuthorizationHeader(),
}).then(response => response.arrayBuffer());
}
@@ -144,7 +123,7 @@ async function handleSegmentationStorage(
return {
studyInstanceUid,
displaySetInstanceUid,
stack
stack,
};
}
@@ -1,3 +1,23 @@
import OHIFCornerstoneExtension from './OHIFCornerstoneExtension.js';
import OHIFCornerstoneViewport from './OHIFCornerstoneViewport.js';
import commandsModule from './commandsModule.js';
import toolbarModule from './toolbarModule.js';
export default OHIFCornerstoneExtension;
/**
*
*/
export default {
/**
* Only required property. Should be a unique value across all extensions.
*/
id: 'cornerstone',
getViewportModule() {
return OHIFCornerstoneViewport;
},
getToolbarModule() {
return toolbarModule;
},
getCommandsModule() {
return commandsModule;
},
};
@@ -0,0 +1,198 @@
// TODO: A way to add Icons that don't already exist?
// - Register them and add
// - Include SVG Source/Inline?
// - By URL, or own component?
// TODO: `ohif-core` toolbar builder?
// What KINDS of toolbar buttons do we have...
// - One's that dispatch commands
// - One's that set tool's active
// - More custom, like CINE
// - Built in for one's like this, or custom components?
// Visible?
// Disabled?
// Based on contexts or misc. criteria?
// -- ACTIVE_ROUTE::VIEWER
// -- ACTIVE_VIEWPORT::CORNERSTONE
// setToolActive commands should receive the button event that triggered
// so we can do the "bind to this button" magic
const TOOLBAR_BUTTON_TYPES = {
COMMAND: 'command',
SET_TOOL_ACTIVE: 'setToolActive',
BUILT_IN: 'builtIn'
};
const definitions = [
{
id: 'StackScroll',
label: 'Stack Scroll',
icon: 'bars',
//
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
commandName: 'setToolActive',
commandOptions: { toolName: 'StackScroll' },
},
{
id: 'Zoom',
label: 'Zoom',
icon: 'search-plus',
//
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
commandName: 'setToolActive',
commandOptions: { toolName: 'Zoom' },
},
{
id: 'Wwwc',
label: 'Levels',
icon: 'level',
//
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
commandName: 'setToolActive',
commandOptions: { toolName: 'Wwwc' },
},
{
id: 'Pan',
label: 'Pan',
icon: 'arrows',
//
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
commandName: 'setToolActive',
commandOptions: { toolName: 'Pan' },
},
{
id: 'Length',
label: 'Length',
icon: 'measure-temp',
//
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
commandName: 'setToolActive',
commandOptions: { toolName: 'Length' },
},
{
id: 'Angle',
label: 'Angle',
icon: 'angle-left',
//
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
commandName: 'setToolActive',
commandOptions: { toolName: 'Angle' },
},
{
id: 'Reset',
label: 'Reset',
icon: 'reset',
//
type: TOOLBAR_BUTTON_TYPES.COMMAND,
commandName: 'resetViewport',
},
{
id: 'Cine',
label: 'CINE',
icon: 'youtube',
//
type: TOOLBAR_BUTTON_TYPES.BUILT_IN,
options: {
behavior: 'CINE',
},
},
{
id: 'More',
label: 'More',
icon: 'ellipse-circle',
buttons: [
{
id: 'Magnify',
label: 'Magnify',
icon: 'circle',
//
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
commandName: 'setToolActive',
commandOptions: { toolName: 'Magnify' },
},
{
id: 'WwwcRegion',
label: 'ROI Window',
icon: 'stop',
//
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
commandName: 'setToolActive',
commandOptions: { toolName: 'WwwcRegion' },
},
{
id: 'DragProbe',
label: 'Probe',
icon: 'dot-circle',
//
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
commandName: 'setToolActive',
commandOptions: { toolName: 'DragProbe' },
},
{
id: 'EllipticalRoi',
label: 'Ellipse',
icon: 'circle-o',
//
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
commandName: 'setToolActive',
commandOptions: { toolName: 'EllipticalRoi' },
},
{
id: 'RectangleRoi',
label: 'Rectangle',
icon: 'square-o',
//
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
commandName: 'setToolActive',
commandOptions: { toolName: 'RectangleRoi' },
},
{
id: 'Invert',
label: 'Invert',
icon: 'adjust',
//
type: TOOLBAR_BUTTON_TYPES.COMMAND,
commandName: 'invertViewport',
},
{
id: 'RotateRight',
label: 'Rotate Right',
icon: 'rotate-right',
//
type: TOOLBAR_BUTTON_TYPES.COMMAND,
commandName: 'rotateViewportCW',
},
{
id: 'FlipH',
label: 'Flip H',
icon: 'ellipse-h',
//
type: TOOLBAR_BUTTON_TYPES.COMMAND,
commandName: 'flipViewportHorizontal',
},
{
id: 'FlipV',
label: 'Flip V',
icon: 'ellipse-v',
//
type: TOOLBAR_BUTTON_TYPES.COMMAND,
commandName: 'flipViewportVertical',
},
{
id: 'Clear',
label: 'Clear',
icon: 'trash',
//
type: TOOLBAR_BUTTON_TYPES.COMMAND,
commandName: 'clearAnnotations',
},
],
},
];
export default {
definitions,
defaultContext: 'ACTIVE_VIEWPORT::CORNERSTONE',
};
@@ -789,6 +789,7 @@ any-observable@^0.3.0:
argparse@^1.0.7:
version "1.0.10"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
dependencies:
sprintf-js "~1.0.2"
@@ -1947,6 +1948,7 @@ espree@^5.0.0:
esprima@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
esquery@^1.0.1:
version "1.0.1"
@@ -2974,8 +2976,9 @@ js-levenshtein@^1.1.3:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
js-yaml@^3.12.0, js-yaml@^3.9.0:
version "3.12.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1"
version "3.13.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
dependencies:
argparse "^1.0.7"
esprima "^4.0.0"
@@ -5047,6 +5050,7 @@ split-string@^3.0.1, split-string@^3.0.2:
sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
stable@~0.1.6:
version "0.1.8"
@@ -1,3 +1,9 @@
{
"singleQuote": true
}
"trailingComma": "es5",
"printWidth": 80,
"proseWrap": "always",
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"endOfLine": "lf"
}
@@ -1,6 +1,6 @@
{
"name": "ohif-dicom-html-extension",
"version": "0.0.2",
"name": "@ohif/extension-dicom-html",
"version": "0.0.3",
"description": "OHIF extension for rendering structured reports to HTML",
"author": "OHIF",
"license": "MIT",
@@ -20,11 +20,14 @@
},
"peerDependencies": {
"dcmjs": "^0.3.3",
"ohif-core": "^0.2.6",
"ohif-core": "^0.6.0",
"prop-types": "^15.6.2",
"react": "^15.0.0 || ^16.0.0",
"react-dom": "^15.0.0 || ^16.0.0"
},
"dependencies": {
"@babel/runtime": "^7.2.0"
},
"devDependencies": {
"@babel/core": "^7.2.2",
"@babel/plugin-external-helpers": "^7.2.0",
@@ -80,7 +83,7 @@
"files": [
"dist"
],
"dependencies": {
"@babel/runtime": "^7.2.0"
"publishConfig": {
"access": "public"
}
}
@@ -1,27 +0,0 @@
import OHIFDicomHtmlViewport from './OHIFDicomHtmlViewport.js';
import OHIFDicomHtmlSopClassHandler from './OHIFDicomHtmlSopClassHandler.js';
export default class OHIFDicomHtmlExtension {
/**
* Extension ID is a unique id, might be used for namespacing extension specific redux actions/reducers (?)
*/
getExtensionId() {
return 'html';
}
getViewportModule() {
return OHIFDicomHtmlViewport;
}
getSopClassHandler() {
return OHIFDicomHtmlSopClassHandler;
}
getPanelModuleDefinition() {
return null;
}
getToolbarModuleDefinition() {
return null;
}
}
@@ -1,7 +1,4 @@
import OHIF from 'ohif-core';
const { plugins, utils } = OHIF;
const { PLUGIN_TYPES } = plugins;
import { MODULE_TYPES, utils } from 'ohif-core';
// TODO: Should probably use dcmjs for this
const SOP_CLASS_UIDS = {
@@ -20,7 +17,7 @@ const sopClassUids = Object.values(SOP_CLASS_UIDS);
// same SOP Class
const OHIFDicomHtmlSopClassHandler = {
id: 'OHIFDicomHtmlSopClassHandler',
type: PLUGIN_TYPES.SOP_CLASS_HANDLER,
type: MODULE_TYPES.SOP_CLASS_HANDLER,
sopClassUids,
getDisplaySetFromSeries(series, study, dicomWebClient, authorizationHeaders) {
const instance = series.getFirstInstance();
@@ -1,3 +1,16 @@
import OHIFDicomHtmlExtension from './OHIFDicomHtmlExtension.js';
import OHIFDicomHtmlSopClassHandler from './OHIFDicomHtmlSopClassHandler.js';
import OHIFDicomHtmlViewport from './OHIFDicomHtmlViewport.js';
export default OHIFDicomHtmlExtension;
export default {
/**
* Only required property. Should be a unique value across all extensions.
*/
id: 'html',
getViewportModule() {
return OHIFDicomHtmlViewport;
},
getSopClassHandlerModule() {
return OHIFDicomHtmlSopClassHandler;
}
};
+27 -8
View File
@@ -1501,7 +1501,7 @@ async@^1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
async@^2.1.4, async@^2.5.0, async@^2.6.1:
async@^2.1.4, async@^2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610"
dependencies:
@@ -2501,6 +2501,11 @@ commander@~2.13.0:
version "2.13.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c"
commander@~2.20.0:
version "2.20.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
common-tags@^1.4.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937"
@@ -4425,10 +4430,11 @@ handle-thing@^1.2.5:
resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4"
handlebars@^4.0.3:
version "4.0.12"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5"
version "4.1.2"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67"
integrity sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==
dependencies:
async "^2.5.0"
neo-async "^2.6.0"
optimist "^0.6.1"
source-map "^0.6.1"
optionalDependencies:
@@ -6519,6 +6525,7 @@ minimist@^1.1.1, minimist@^1.2.0:
minimist@~0.0.1:
version "0.0.10"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
minipass@^2.2.1, minipass@^2.3.4:
version "2.3.5"
@@ -6657,9 +6664,10 @@ negotiator@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
neo-async@^2.5.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835"
neo-async@^2.5.0, neo-async@^2.6.0:
version "2.6.1"
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c"
integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==
nice-try@^1.0.4:
version "1.0.5"
@@ -6963,6 +6971,7 @@ opn@5.4.0, opn@^5.1.0:
optimist@^0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY=
dependencies:
minimist "~0.0.1"
wordwrap "~0.0.2"
@@ -9442,6 +9451,7 @@ source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7:
source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
sourcemap-codec@^1.4.1:
version "1.4.4"
@@ -10131,13 +10141,21 @@ uglify-es@^3.3.4:
commander "~2.13.0"
source-map "~0.6.1"
uglify-js@3.4.x, uglify-js@^3.1.4:
uglify-js@3.4.x:
version "3.4.9"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3"
dependencies:
commander "~2.17.1"
source-map "~0.6.1"
uglify-js@^3.1.4:
version "3.6.0"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.0.tgz#704681345c53a8b2079fb6cec294b05ead242ff5"
integrity sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==
dependencies:
commander "~2.20.0"
source-map "~0.6.1"
uglifyjs-webpack-plugin@^1.2.4:
version "1.3.0"
resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz#75f548160858163a08643e086d5fefe18a5d67de"
@@ -10621,6 +10639,7 @@ wide-align@^1.1.0:
wordwrap@~0.0.2:
version "0.0.3"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=
wordwrap@~1.0.0:
version "1.0.0"
@@ -1,3 +1,9 @@
{
"singleQuote": true
}
"trailingComma": "es5",
"printWidth": 80,
"proseWrap": "always",
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"endOfLine": "lf"
}
@@ -0,0 +1,34 @@
# @ohif/extension-dicom-microscopy
![npm (scoped)](https://img.shields.io/npm/v/@ohif/extension-dicom-microscopy.svg?style=flat-square)
<!-- TODO: Simple image or GIF? -->
#### Index
Extension Id: `microscopy`
- [SopClassHandler Module](#sopclasshandler-module)
- [Viewport Module](#viewport-module)
## SopClassHandler Module
..
## Viewport Module
...
## Resources
### Repositories
...
<!--
Links
-->
<!-- prettier-ignore-start -->
<!-- prettier-ignore-end -->
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-dicom-microscopy",
"version": "0.0.6",
"version": "0.0.9",
"description": "OHIF extension for Dicom Microscopy",
"author": "OHIF",
"license": "MIT",
@@ -19,9 +19,10 @@
"lint": "eslint -c .eslintrc --fix src && prettier --single-quote --write src/**/*.{js,jsx,json,css}"
},
"peerDependencies": {
"ohif-core": "^0.6.0",
"react": "^15.0.0 || ^16.0.0",
"react-dom": "^15.0.0 || ^16.0.0",
"ohif-core": "^0.4.0"
"react-resize-detector": "^4.2.0"
},
"devDependencies": {
"@babel/core": "^7.2.2",
@@ -81,6 +82,7 @@
"dependencies": {
"@babel/runtime": "^7.2.0",
"classnames": "^2.2.6",
"dicom-microscopy-viewer": "^0.4.3"
"dicom-microscopy-viewer": "0.5.0",
"lodash.debounce": "^4.0.8"
}
}
@@ -10,6 +10,7 @@ import builtins from 'rollup-plugin-node-builtins';
const globals = {
react: 'React',
'react-resize-detector': 'ReactResizeDetector',
'react-dom': 'ReactDOM',
'ohif-core': 'OHIF'
};
@@ -52,6 +53,15 @@ export default {
],
'.yalc/dicom-microscopy-viewer/build/dicom-microscopy-viewer.js': [
'api'
],
'node_modules/react-resize-detector/node_modules/prop-types/index.js': [
'bool',
'number',
'string',
'shape',
'func',
'any',
'node'
]
}
})
@@ -3,7 +3,7 @@ import OHIF from 'ohif-core';
const { utils } = OHIF;
const SOP_CLASS_UIDS = {
VL_WHOLE_SLIDE_MICROSCOPY_IMAGE_STORAGE: '1.2.840.10008.5.1.4.1.1.77.1.6'
VL_WHOLE_SLIDE_MICROSCOPY_IMAGE_STORAGE: '1.2.840.10008.5.1.4.1.1.77.1.6',
};
const DicomMicroscopySopClassHandler = {
@@ -20,9 +20,9 @@ const DicomMicroscopySopClassHandler = {
dicomWebClient,
sopInstanceUid: instance.getSOPInstanceUID(),
seriesInstanceUid: series.getSeriesInstanceUID(),
studyInstanceUid: study.getStudyInstanceUID()
studyInstanceUid: study.getStudyInstanceUID(),
};
}
},
};
export default DicomMicroscopySopClassHandler;
@@ -1,17 +1,25 @@
import React, { Component } from 'react';
import ReactResizeDetector from 'react-resize-detector';
import { api } from 'dicom-microscopy-viewer';
import debounce from 'lodash.debounce';
const microscopyViewer = api.VLWholeSlideMicroscopyImageViewer;
class DicomMicroscopyViewport extends Component {
state = {
error: null
error: null,
};
viewer = null;
constructor(props) {
super(props);
this.container = React.createRef();
this.debouncedResize = debounce(() => {
if (this.viewer) this.viewer.resize();
}, 100);
}
// install the microscopy renderer into the web page.
@@ -21,7 +29,7 @@ class DicomMicroscopyViewport extends Component {
const searchInstanceOptions = {
studyInstanceUID: displaySet.studyInstanceUid,
seriesInstanceUID: displaySet.seriesInstanceUid
seriesInstanceUID: displaySet.seriesInstanceUid,
};
dicomWebClient
@@ -33,7 +41,7 @@ class DicomMicroscopyViewport extends Component {
const retrieveInstanceOptions = {
studyInstanceUID: displaySet.studyInstanceUid,
seriesInstanceUID: displaySet.seriesInstanceUid,
sopInstanceUID
sopInstanceUID,
};
const promise = dicomWebClient
@@ -51,17 +59,18 @@ class DicomMicroscopyViewport extends Component {
.then(metadata => {
metadata = metadata.filter(m => m);
const viewer = new microscopyViewer({
this.viewer = new microscopyViewer({
client: dicomWebClient,
metadata
metadata,
retrieveRendered: false
});
viewer.render({ container });
this.viewer.render({ container });
});
}
componentDidMount() {
const { studies, displaySet } = this.props.viewportData;
const { displaySet } = this.props.viewportData;
this.installOpenLayersRenderer(this.container.current, displaySet);
}
@@ -70,6 +79,13 @@ class DicomMicroscopyViewport extends Component {
const style = { width: '100%', height: '100%' };
return (
<div className={'DicomMicroscopyViewer'} style={style}>
{ReactResizeDetector && (
<ReactResizeDetector
handleWidth
handleHeight
onResize={this.onWindowResize}
/>
)}
{this.state.error ? (
<h2>{JSON.stringify(this.state.error)}</h2>
) : (
@@ -78,6 +94,10 @@ class DicomMicroscopyViewport extends Component {
</div>
);
}
onWindowResize = () => {
this.debouncedResize();
};
}
export default DicomMicroscopyViewport;
@@ -1,27 +0,0 @@
import DicomMicroscopyViewport from './DicomMicroscopyViewport.js';
import DicomMicroscopySopClassHandler from './DicomMicroscopySopClassHandler.js';
export default class OHIFDicomMicroscopyExtension {
/**
* Extension ID is a unique id, might be used for namespacing extension specific redux actions/reducers (?)
*/
getExtensionId() {
return 'microscopy';
}
getViewportModule() {
return DicomMicroscopyViewport;
}
getSopClassHandler() {
return DicomMicroscopySopClassHandler;
}
getPanelModule() {
return null;
}
getToolbarModule() {
return null;
}
}
@@ -1,3 +1,16 @@
import OHIFDicomMicroscopyExtension from './OHIFDicomMicroscopyExtension.js';
import DicomMicroscopySopClassHandler from './DicomMicroscopySopClassHandler.js';
import DicomMicroscopyViewport from './DicomMicroscopyViewport.js';
export default OHIFDicomMicroscopyExtension;
export default {
/**
* Only required property. Should be a unique value across all extensions.
*/
id: 'microscopy',
getViewportModule() {
return DicomMicroscopyViewport;
},
getSopClassHandlerModule() {
return DicomMicroscopySopClassHandler;
},
};
@@ -1617,10 +1617,10 @@ des.js@^1.0.0:
inherits "^2.0.1"
minimalistic-assert "^1.0.0"
dicom-microscopy-viewer@^0.4.3:
version "0.4.3"
resolved "https://registry.yarnpkg.com/dicom-microscopy-viewer/-/dicom-microscopy-viewer-0.4.3.tgz#defaa821026765bcd109b97258742df72a9b92bb"
integrity sha512-PjT3qH0hv6dKOQzXFIHw4w/d8QCbiUOJOGZHvAkkRvnjeNRP7/ri8vbFvcSev+nYxKskNb1Tn0xd1+dsDpPGNw==
dicom-microscopy-viewer@0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/dicom-microscopy-viewer/-/dicom-microscopy-viewer-0.5.0.tgz#e4f74261337d8a78d51490af0d17edc63997e619"
integrity sha512-r3BPLBvexv9v/Rr/FBTgXgp7orIFKLWW5uYM6IsYpz36ttU84Edk7Z2GAyk6887QNsfEMLzYV+5ik6HRrMg0cA==
dependencies:
dicomweb-client "^0.4.2"
ol "^5.3.0"
@@ -3199,6 +3199,11 @@ lodash.camelcase@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
lodash.debounce@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=
lodash.memoize@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
@@ -3238,6 +3243,7 @@ longest-streak@^2.0.1:
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
@@ -1,3 +1,9 @@
{
"singleQuote": true
}
"trailingComma": "es5",
"printWidth": 80,
"proseWrap": "always",
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"endOfLine": "lf"
}
@@ -1,6 +1,6 @@
{
"name": "ohif-dicom-pdf-extension",
"version": "0.0.6",
"name": "@ohif/extension-dicom-pdf",
"version": "0.0.7",
"description": "OHIF extension for Dicom PDF",
"author": "OHIF",
"license": "MIT",
@@ -20,11 +20,16 @@
},
"peerDependencies": {
"dicom-parser": "^1.8.3",
"ohif-core": "^0.3.4",
"ohif-core": "^0.6.0",
"prop-types": "^15.6.2",
"react": "^15.0.0 || ^16.0.0",
"react-dom": "^15.0.0 || ^16.0.0"
},
"dependencies": {
"@babel/runtime": "^7.2.0",
"classnames": "^2.2.6",
"lodash.isequal": "^4.5.0"
},
"devDependencies": {
"@babel/core": "^7.2.2",
"@babel/plugin-external-helpers": "^7.2.0",
@@ -80,9 +85,7 @@
"files": [
"dist"
],
"dependencies": {
"@babel/runtime": "^7.2.0",
"classnames": "^2.2.6",
"lodash.isequal": "^4.5.0"
"publishConfig": {
"access": "public"
}
}
@@ -1,27 +0,0 @@
import OHIFDicomPDFViewport from './OHIFDicomPDFViewport.js';
import OHIFDicomPDFSopClassHandler from './OHIFDicomPDFSopClassHandler.js';
export default class OHIFDicomPDFExtension {
/**
* Extension ID is a unique id, might be used for namespacing extension specific redux actions/reducers (?)
*/
getExtensionId() {
return 'pdf';
}
getViewportModule() {
return OHIFDicomPDFViewport;
}
getSopClassHandler() {
return OHIFDicomPDFSopClassHandler;
}
getPanelModule() {
return null;
}
getToolbarModule() {
return null;
}
}
@@ -1,7 +1,4 @@
import OHIF from "ohif-core";
const { plugins, utils } = OHIF;
const { PLUGIN_TYPES } = plugins;
import { MODULE_TYPES, utils } from 'ohif-core';
// TODO: Should probably use dcmjs for this
const SOP_CLASS_UIDS = {
@@ -10,10 +7,8 @@ const SOP_CLASS_UIDS = {
const OHIFDicomPDFSopClassHandler = {
id: 'OHIFDicomPDFSopClassHandlerPlugin',
type: PLUGIN_TYPES.SOP_CLASS_HANDLER,
sopClassUids: [
SOP_CLASS_UIDS.ENCAPSULATED_PDF
],
type: MODULE_TYPES.SOP_CLASS_HANDLER,
sopClassUids: [SOP_CLASS_UIDS.ENCAPSULATED_PDF],
getDisplaySetFromSeries(series, study, dicomWebClient, authorizationHeaders) {
const instance = series.getFirstInstance();
@@ -28,6 +23,6 @@ const OHIFDicomPDFSopClassHandler = {
authorizationHeaders: authorizationHeaders
};
}
}
};
export default OHIFDicomPDFSopClassHandler;
@@ -1,3 +1,16 @@
import OHIFDicomPDFExtension from './OHIFDicomPDFExtension.js';
import OHIFDicomPDFSopClassHandler from './OHIFDicomPDFSopClassHandler.js';
import OHIFDicomPDFViewport from './OHIFDicomPDFViewport.js';
export default OHIFDicomPDFExtension;
export default {
/**
* Only required property. Should be a unique value across all extensions.
*/
id: 'pdf',
getViewportModule() {
return OHIFDicomPDFViewport;
},
getSopClassHandlerModule() {
return OHIFDicomPDFSopClassHandler;
}
};
+27 -8
View File
@@ -1501,7 +1501,7 @@ async@^1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
async@^2.1.4, async@^2.5.0, async@^2.6.1:
async@^2.1.4, async@^2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610"
dependencies:
@@ -2505,6 +2505,11 @@ commander@~2.13.0:
version "2.13.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c"
commander@~2.20.0:
version "2.20.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
common-tags@^1.4.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937"
@@ -4429,10 +4434,11 @@ handle-thing@^1.2.5:
resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4"
handlebars@^4.0.3:
version "4.0.12"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5"
version "4.1.2"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67"
integrity sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==
dependencies:
async "^2.5.0"
neo-async "^2.6.0"
optimist "^0.6.1"
source-map "^0.6.1"
optionalDependencies:
@@ -6528,6 +6534,7 @@ minimist@^1.1.1, minimist@^1.2.0:
minimist@~0.0.1:
version "0.0.10"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
minipass@^2.2.1, minipass@^2.3.4:
version "2.3.5"
@@ -6666,9 +6673,10 @@ negotiator@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
neo-async@^2.5.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835"
neo-async@^2.5.0, neo-async@^2.6.0:
version "2.6.1"
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c"
integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==
nice-try@^1.0.4:
version "1.0.5"
@@ -6972,6 +6980,7 @@ opn@5.4.0, opn@^5.1.0:
optimist@^0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY=
dependencies:
minimist "~0.0.1"
wordwrap "~0.0.2"
@@ -9451,6 +9460,7 @@ source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7:
source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
sourcemap-codec@^1.4.1:
version "1.4.4"
@@ -10140,13 +10150,21 @@ uglify-es@^3.3.4:
commander "~2.13.0"
source-map "~0.6.1"
uglify-js@3.4.x, uglify-js@^3.1.4:
uglify-js@3.4.x:
version "3.4.9"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3"
dependencies:
commander "~2.17.1"
source-map "~0.6.1"
uglify-js@^3.1.4:
version "3.6.0"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.0.tgz#704681345c53a8b2079fb6cec294b05ead242ff5"
integrity sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==
dependencies:
commander "~2.20.0"
source-map "~0.6.1"
uglifyjs-webpack-plugin@^1.2.4:
version "1.3.0"
resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz#75f548160858163a08643e086d5fefe18a5d67de"
@@ -10630,6 +10648,7 @@ wide-align@^1.1.0:
wordwrap@~0.0.2:
version "0.0.3"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=
wordwrap@~1.0.0:
version "1.0.0"
+14
View File
@@ -0,0 +1,14 @@
{
"presets": [
["@babel/preset-env", {
"targets": {
"ie": "11"
}
}],
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-transform-runtime"
]
}
+9
View File
@@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
+29
View File
@@ -0,0 +1,29 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
node_modules
# builds
build
dist
.rpt2_cache
# misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.idea
yalc.lock
.yalc
# Note: DO NOT include this file because it includes our API key
.locize
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Open Health Imaging Foundation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+4
View File
@@ -0,0 +1,4 @@
# @ohif/i18n
More information available at
[OHIF Docs](https://docs.ohif.org/essentials/translating.html).
+90
View File
@@ -0,0 +1,90 @@
{
"name": "@ohif/i18n",
"version": "0.2.2",
"description": "OHIF extension for internationalization",
"author": "OHIF",
"license": "MIT",
"repository": "OHIF/Viewers",
"main": "dist/index.umd.js",
"module": "dist/index.es.js",
"jsnext:main": "dist/index.es.js",
"engines": {
"node": ">=8",
"npm": ">=5"
},
"scripts": {
"build": "rollup -c",
"prepublishOnly": "npm run build",
"pullTranslations": "./pullTranslations.sh"
},
"peerDependencies": {
"i18next": "^17.0.3",
"i18next-browser-languagedetector": "^3.0.1",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-i18next": "^10.11.0"
},
"devDependencies": {
"@babel/core": "^7.2.2",
"@babel/plugin-external-helpers": "^7.2.0",
"@babel/plugin-proposal-class-properties": "^7.2.3",
"@babel/plugin-transform-runtime": "^7.2.0",
"@babel/preset-env": "^7.2.3",
"@babel/preset-react": "^7.0.0",
"babel-eslint": "^10.0.1",
"cross-env": "^5.2.0",
"eslint": "5.13.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^8.0.0",
"eslint-plugin-promise": "^4.0.1",
"eslint-plugin-react": "^7.11.1",
"husky": "^1.3.1",
"i18next": "^15.1.3",
"i18next-browser-languagedetector": "^3.0.1",
"lint-staged": "^8.1.0",
"locize-cli": "^4.8.0",
"prettier": "^1.15.3",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-i18next": "^10.11.0",
"rollup": "^1.1.2",
"rollup-plugin-babel": "^4.2.0",
"rollup-plugin-commonjs": "^9.2.0",
"rollup-plugin-node-builtins": "^2.1.2",
"rollup-plugin-node-resolve": "^4.0.0",
"rollup-plugin-peer-deps-external": "^2.2.0",
"rollup-plugin-postcss": "^2.0.3",
"rollup-plugin-url": "^2.1.0"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"src/**/*.{js,jsx,json,css}": [
"prettier --single-quote --write",
"git add"
]
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
],
"files": [
"dist"
],
"publishConfig": {
"access": "public"
},
"dependencies": {
"@babel/runtime": "^7.2.0",
"classnames": "^2.2.6",
"i18next-locize-backend": "^2.0.0",
"locize-editor": "^2.0.0",
"locize-lastused": "^1.1.0",
"rollup-plugin-json": "^4.0.0"
}
}
+4
View File
@@ -0,0 +1,4 @@
rm -rf src/locales/
cd src/locales/
npx locize --config-path ../../.locize download --ver latest
node ./writeLocaleIndexFiles.js
+67
View File
@@ -0,0 +1,67 @@
import babel from 'rollup-plugin-babel';
import commonjs from 'rollup-plugin-commonjs';
import external from 'rollup-plugin-peer-deps-external';
import postcss from 'rollup-plugin-postcss';
import resolve from 'rollup-plugin-node-resolve';
import url from 'rollup-plugin-url';
import pkg from './package.json';
// Deal with https://github.com/rollup/rollup-plugin-commonjs/issues/297
import builtins from 'rollup-plugin-node-builtins';
import json from 'rollup-plugin-json';
const globals = {
react: 'React',
'react-dom': 'ReactDOM',
'react-redux': 'ReactRedux',
'react-resize-detector': 'ReactResizeDetector',
'prop-types': 'PropTypes',
i18next: 'i18next',
'react-i18next': 'react-i18next',
'i18next-browser-languagedetector': 'LngDetector',
};
export default {
input: 'src/index.js',
output: [
{
file: pkg.main,
format: 'umd',
name: 'ohif-i18n',
sourcemap: true,
globals,
exports: 'named',
},
{
file: pkg.module,
format: 'es',
sourcemap: true,
globals,
exports: 'named',
},
],
plugins: [
builtins(),
external(),
postcss({
modules: false,
}),
json({
// ignores indent and generates the smallest code
compact: true, // Default: false
// generate a named export for every property of the JSON object
namedExports: true, // Default: true
}),
url(),
babel({
exclude: 'node_modules/**',
externalHelpers: true,
runtimeHelpers: true,
}),
resolve(),
commonjs({
include: ['node_modules/**', '.yalc/**'],
}),
],
external: Object.keys(pkg.peerDependencies || {}),
};
+24
View File
@@ -0,0 +1,24 @@
const debugMode = !!(
process.env.NODE_ENV !== 'production' && process.env.REACT_APP_I18N_DEBUG
);
const detectionOptions = {
// order and from where user language should be detected
order: ['querystring', 'cookie', 'localStorage', 'navigator', 'htmlTag', 'path', 'subdomain'],
// keys or params to lookup language from
lookupQuerystring: 'lng',
lookupCookie: 'i18next',
lookupLocalStorage: 'i18nextLng',
lookupFromPathIndex: 0,
lookupFromSubdomainIndex: 0,
// cache user language on
caches: ['localStorage', 'cookie'],
excludeCacheFor: ['cimode'], // languages to not persist (cookie, localStorage)
// optional htmlTag with lang attribute, the default is:
htmlTag: document.documentElement
};
export { debugMode, detectionOptions };
+8
View File
@@ -0,0 +1,8 @@
import { debugMode } from './config';
export default (message, level = 'log') => {
if (debugMode) {
// eslint-disable-next-line
console[level]('@ohif/i18n: ', message);
}
};
+140
View File
@@ -0,0 +1,140 @@
import i18n from 'i18next';
import Backend from 'i18next-locize-backend';
import LastUsed from 'locize-lastused';
import Editor from 'locize-editor';
import LanguageDetector from 'i18next-browser-languagedetector';
import { initReactI18next } from 'react-i18next';
import customDebug from './debugger';
import pkg from '../package.json';
import { debugMode, detectionOptions } from './config';
// Note: The index.js files inside src/locales are dynamically generated
// by the pullTranslations.sh script
import locales from './locales';
function addLocales(newLocales) {
customDebug(`Adding locales ${newLocales}`, 'info');
let resourceBundle = [];
Object.keys(newLocales).map(key => {
Object.keys(newLocales[key]).map(namespace => {
const locale = newLocales[key][namespace];
resourceBundle.push({ key, namespace, locale });
i18n.addResourceBundle(key, namespace, locale, true, true);
});
});
customDebug(`Locales added successfully`, 'info');
customDebug(resourceBundle, 'info');
}
// Note: Developers can add the API key to use the in-context editor.
// DO NOT commit the API key
const config = (window.config && window.config.i18n) || {};
const locizeOptions = {
projectId: config.LOCIZE_PROJECTID,
apiKey: config.LOCIZE_API_KEY,
referenceLng: 'en-US',
fallbacklng: 'en-US',
};
const envUseLocize = !!config.USE_LOCIZE;
const envApiKeyAvailable = !!config.LOCIZE_API_KEY;
function initI18n(
detection = detectionOptions,
useLocize = envUseLocize,
apiKeyAvailable = envApiKeyAvailable
) {
let initialized;
if (useLocize) {
customDebug(`Using Locize for translation files`, 'info');
initialized = i18n
// i18next-locize-backend
// loads translations from your project, saves new keys to it (saveMissing: true)
// https://github.com/locize/i18next-locize-backend
.use(Backend)
// locize-lastused
// sets a timestamp of last access on every translation segment on locize
// -> safely remove the ones not being touched for weeks/months
// https://github.com/locize/locize-lastused
.use(LastUsed)
// locize-editor
// InContext Editor of locize ?locize=true to show it
// https://github.com/locize/locize-editor
.use(Editor)
// detect user language
// learn more: https://github.com/i18next/i18next-browser-languageDetector
.use(LanguageDetector)
// pass the i18n instance to react-i18next.
.use(initReactI18next)
// init i18next
// for all options read: https://www.i18next.com/overview/configuration-options
.init({
fallbackLng: 'en-US',
saveMissing: apiKeyAvailable,
debug: debugMode,
keySeparator: false,
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
},
detection,
backend: locizeOptions,
locizeLastUsed: locizeOptions,
editor: {
...locizeOptions,
onEditorSaved: async (lng, ns) => {
// reload that namespace in given language
await i18n.reloadResources(lng, ns);
// trigger an event on i18n which triggers a rerender
// based on bindI18n below in react options
i18n.emit('editorSaved');
},
},
react: {
useSuspense: false, // TODO: Was seeing weird errors without this
wait: true,
bindI18n: 'languageChanged editorSaved',
},
});
} else {
customDebug(`Using local translation files`, 'info');
initialized = i18n
// detect user language
// learn more: https://github.com/i18next/i18next-browser-languageDetector
.use(LanguageDetector)
// pass the i18n instance to react-i18next.
.use(initReactI18next)
// init i18next
// for all options read: https://www.i18next.com/overview/configuration-options
.init({
fallbackLng: 'en-US',
resources: locales,
debug: debugMode,
keySeparator: false,
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
},
detection,
react: {
wait: true,
},
});
}
return initialized.then(function(t) {
i18n.T = t;
customDebug(`T function available.`, 'info');
});
}
customDebug(`version ${pkg.version} loaded.`, 'info');
i18n.initializing = initI18n();
i18n.initI18n = initI18n;
i18n.addLocales = addLocales;
export default i18n;
@@ -0,0 +1,42 @@
{
"Acquired": "Acquired",
"Angle": "Angle",
"Axial": "Axial",
"Bidirectional": "Bidirectional",
"Brush": "Brush",
"CINE": "CINE",
"Cancel": "Cancel",
"Circle": "Circle",
"Clear": "Clear",
"Coronal": "Coronal",
"Crosshairs": "Crosshairs",
"Ellipse": "Ellipse",
"Elliptical": "Elliptical",
"Flip H": "Flip H",
"Flip V": "Flip V",
"Freehand": "Freehand",
"Invert": "Invert",
"Layout": "$t(Common:Layout)",
"Length": "Length",
"Levels": "Levels",
"Magnify": "Magnify",
"Manual": "Manual",
"Measurements": "Measurements",
"More": "$t(Common:More)",
"Next": "$t(Common:Next)",
"Pan": "Pan",
"Play": "$t(Common:Play)",
"Previous": "$t(Common:Previous)",
"Probe": "Probe",
"ROI Window": "ROI Window",
"Rectangle": "Rectangle",
"Reset": "$t(Common:Reset)",
"Reset to Defaults": "$t(Common:Reset) to Defaults",
"Rotate Right": "Rotate Right",
"Sagittal": "Sagittal",
"Save": "Save",
"Stack Scroll": "Stack Scroll",
"Stop": "$t(Common:Stop)",
"Themes": "Themes",
"Zoom": "Zoom"
}
@@ -0,0 +1,8 @@
{
"Next image": "$t(Common:Play) $t(Common:Image)",
"Play / Stop": "$t(Common:Play) / $t(Common:Stop)",
"Previous image": "$t(Common:Previous) $t(Common:Image)",
"Skip to first image": "Skip to first $t(Common:Image)",
"Skip to last image": "Skip, to last $t(Common:Image)",
"fps": "fps"
}
@@ -0,0 +1,10 @@
{
"Image": "Image",
"Layout": "Layout",
"More": "More",
"Next": "Next",
"Play": "Play",
"Previous": "Previous",
"Reset": "Reset",
"Stop": "Stop"
}
@@ -0,0 +1,8 @@
{
"About": "About",
"Back to Viewer": "Back to Viewer",
"INVESTIGATIONAL USE ONLY": "INVESTIGATIONAL USE ONLY",
"Options": "Options",
"Preferences": "Preferences",
"Study list": "Study list"
}
@@ -0,0 +1,9 @@
{
"Criteria nonconformities": "Criteria nonconformities",
"Delete": "Delete",
"Description": "Description",
"MAX": "MAX",
"NonTargets": "NonTargets",
"Relabel": "Relabel",
"Targets": "Targets"
}
@@ -0,0 +1,6 @@
{
"Cancel": "$t(Buttons:Cancel)",
"Reset to Defaults": "$t(Buttons:Reset to Defaults)",
"Save": "$t(Buttons:Save)",
"User Preferences": "User Preferences"
}
@@ -0,0 +1,17 @@
import Buttons from './Buttons.json';
import CineDialog from './CineDialog.json';
import Common from './Common.json';
import Header from './Header.json';
import MeasurementTable from './MeasurementTable.json';
import UserPreferencesModal from './UserPreferencesModal.json';
export default {
'en-US': {
Buttons,
CineDialog,
Common,
Header,
MeasurementTable,
UserPreferencesModal,
},
};
@@ -0,0 +1,42 @@
{
"Acquired": "Acquired",
"Angle": "Ángulo",
"Axial": "Axial",
"Bidirectional": "Bidirectional",
"Brush": "Escoba",
"CINE": "CINE",
"Cancel": "Cancelar",
"Circle": "Circle",
"Clear": "Limpiar",
"Coronal": "Coronal",
"Crosshairs": "Cruces",
"Ellipse": "Elipse",
"Elliptical": "Elliptical",
"Flip H": "Espejo Hor.",
"Flip V": "Espejo Ver.",
"Freehand": "Freehand",
"Invert": "Invertido",
"Layout": "$t(Common:Layout)",
"Length": "Medición",
"Levels": "Niveles",
"Magnify": "Lupa",
"Manual": "Manual",
"Measurements": "Medidas",
"More": "$t(Common:More)",
"Next": "$t(Common:Next)",
"Pan": "Mover",
"Play": "$t(Common:Play)",
"Previous": "$t(Common:Previous)",
"Probe": "Probar",
"ROI Window": "Ventana ROI",
"Rectangle": "Rectángulo",
"Reset": "$t(Common:Reset)",
"Reset to Defaults": "$t(Common:reset) por defectos",
"Rotate Right": "Rotar ->",
"Sagittal": "Sagittal",
"Save": "Guardar",
"Stack Scroll": "Avance X slice",
"Stop": "$t(Common:Stop)",
"Themes": "Temas",
"Zoom": "Zoom"
}
@@ -0,0 +1,8 @@
{
"Next image": "$t(Common:Play) $t(Common:Image)",
"Play / Stop": "$t(Common:Play) / $t(Common:Stop)",
"Previous image": "$t(Common:Previous) $t(Common:Image)",
"Skip to first image": "Avanza para la primera $t(Common:Image)",
"Skip to last image": "Pular para la ultima $t(Common:Image)",
"fps": "fps"
}
@@ -0,0 +1,10 @@
{
"Image": "Imagen",
"Layout": "Esquema",
"More": "Más",
"Next": "Próximo",
"Play": "Play",
"Previous": "Anterior",
"Reset": "Reiniciar",
"Stop": "Stop"
}
@@ -0,0 +1,8 @@
{
"About": "Sobre",
"Back to Viewer": "Back to Viewer",
"INVESTIGATIONAL USE ONLY": "SOLO USO DE INVESTIGACIÓN",
"Options": "Opciones",
"Preferences": "Preferencias",
"Study list": "Lista de estudio"
}
@@ -0,0 +1,9 @@
{
"Criteria nonconformities": "Criterios de no conformidades",
"Delete": "Borrar",
"Description": "Descripción",
"MAX": "máximo",
"NonTargets": "NonObjetivos",
"Relabel": "Reetiquetar",
"Targets": "Objetivos"
}
@@ -0,0 +1,6 @@
{
"Cancel": "$t(Buttons:Cancel)",
"Reset to Defaults": "$t(Buttons:Reset to Defaults)",
"Save": "$t(Buttons:Save)",
"User Preferences": "Preferencias de usuario"
}
@@ -0,0 +1,17 @@
import Buttons from './Buttons.json';
import CineDialog from './CineDialog.json';
import Common from './Common.json';
import Header from './Header.json';
import MeasurementTable from './MeasurementTable.json';
import UserPreferencesModal from './UserPreferencesModal.json';
export default {
es: {
Buttons,
CineDialog,
Common,
Header,
MeasurementTable,
UserPreferencesModal,
},
};
@@ -0,0 +1,9 @@
import en_US from './en-US/';
import es from './es/';
import nl from './nl/';
export default {
...en_US,
...es,
...nl,
};
@@ -0,0 +1,6 @@
{
"Circle": "Cirkel",
"More": "Meer",
"Pan": "Pan",
"Zoom": "Inzoomen"
}
@@ -0,0 +1,3 @@
{
"More": "Meer"
}
@@ -0,0 +1,7 @@
{
"About": "Over",
"INVESTIGATIONAL USE ONLY": "ALLEEN VOOR ONDERZOEK",
"Options": "Opties",
"Preferences": "Voorkeuren",
"Study list": "Studie Overzicht"
}
@@ -0,0 +1,11 @@
import Buttons from './Buttons.json';
import Common from './Common.json';
import Header from './Header.json';
export default {
nl: {
Buttons,
Common,
Header,
},
};
@@ -0,0 +1,92 @@
const path = require('path');
const fs = require('fs');
const directoryPath = path.join(__dirname, 'src', 'locales');
const { lstatSync, readdirSync } = require('fs');
const { join } = require('path');
const isDirectory = source => lstatSync(source).isDirectory();
const getDirectories = source =>
readdirSync(source)
.map(name => join(source, name))
.filter(isDirectory);
const getJSONFiles = source =>
readdirSync(source)
.filter(name => name.includes('.json'))
.map(name => join(source, name))
.filter(a => !isDirectory(a));
const directories = getDirectories(directoryPath);
function writeFile(filepath, name, content) {
fs.writeFile(path.join(filepath, name), content, err => {
if (err) throw err;
});
}
// For each language directory
const languages = [];
directories.forEach(directory => {
const language = path.basename(directory);
languages.push(language);
const name = 'index.js';
// Create one file (index.js) inside the language folder
// For each namespace
let content = '';
const files = getJSONFiles(directory);
const namespaces = files.map(file => path.basename(file, '.json'));
files.forEach(file => {
const filename = path.basename(file);
const namespace = path.basename(file, '.json');
content += `import ${namespace} from "./${filename}";\n`;
});
content += '\n';
let exportLines = `export default { \n '${language}': {\n`;
namespaces.forEach(namespace => {
exportLines += ` ${namespace},\n`;
});
exportLines += ' }\n};';
content += exportLines;
// If the file {namespace}.json is present,
// create a file to import the namespace and
// export all of the namespaces for the language
// e.g.
// import namespace from './{namespace}.json';
// export { namespace1, namespace2, ... }
writeFile(directory, name, content);
});
let fileContent = '';
const languageVariables = languages.map(language => {
const languageVariable = language.replace('-', '_');
fileContent += `import ${languageVariable} from './${language}/';\n`;
return languageVariable;
});
fileContent += '\n';
fileContent += 'export default {\n';
languageVariables.forEach(language => {
fileContent += ` ...${language},\n`;
});
fileContent += '};';
// Create one file (index.js) inside the locales folder
// which exports each of the languages
// e.g.
// import language1 from './{language1}/'
// import language2 from './{language2}/'
//
// export { language1, language2 }
writeFile(directoryPath, 'index.js', fileContent);
File diff suppressed because it is too large. Load diff
+8 -2
View File
@@ -1,3 +1,9 @@
{
"singleQuote": true
}
"trailingComma": "es5",
"printWidth": 80,
"proseWrap": "always",
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"endOfLine": "lf"
}
+54
View File
@@ -1 +1,55 @@
# @ohif/extension-vtk
![npm (scoped)](https://img.shields.io/npm/v/@ohif/extension-vtk.svg?style=flat-square)
<!-- TODO: Simple image or GIF? -->
#### Index
Extension Id: `vtk`
- [Commands Module](#commands-module)
- [Toolbar Module](#toolbar-module)
- [Viewport Module](#viewport-module)
## Commands Module
| Command Name | Description | Store Contexts |
| ---------------------- | ----------- | -------------- |
| `axial` | | viewports |
| `coronal` | | viewports |
| `sagittal` | | viewports |
| `enableRotateTool` | | viewports |
| `enableCrosshairsTool` | | viewports |
| `enableLevelTool` | | viewports |
| `mpr2d` | | viewports |
## Toolbar Module
Our toolbar module contains definitions for:
- `Crosshairs`
- `WWWC`
- `Rotate`
All use the `ACTIVE_VIEWPORT::VTK` context.
## Viewport Module
Our Viewport wraps [OHIF/react-vtkjs-viewport][react-viewport] and is connected
the redux store. This module is the most prone to change as we hammer out our
Viewport interface.
## Resources
### Repositories
- [OHIF/react-vtkjs-viewport][react-viewport]
<!--
Links
-->
<!-- prettier-ignore-start -->
[react-viewport]: https://github.com/OHIF/react-vtkjs-viewport
<!-- prettier-ignore-end -->
+55 -43
View File
@@ -1,69 +1,86 @@
{
"name": "@ohif/extension-vtk",
"version": "0.0.2",
"version": "0.1.3",
"description": "OHIF extension for VTK.js",
"author": "OHIF",
"license": "MIT",
"repository": "OHIF/Viewers",
"main": "dist/index.umd.js",
"module": "dist/index.es.js",
"jsnext:main": "dist/index.es.js",
"engines": {
"node": ">=8",
"npm": ">=5"
},
"scripts": {
"build": "rollup -c",
"prepublishOnly": "npm run build",
"start": "rollup -c -w",
"build": "webpack --progress --colors --mode development",
"build:release": "webpack --progress --colors --mode production",
"start": "webpack --watch --progress --colors --mode development",
"prepare": "yarn run build:release",
"predeploy": "cd example && yarn install && yarn run build:release",
"prepublishOnly": "yarn install && yarn run build:release",
"lint": "eslint -c .eslintrc --fix src && prettier --single-quote --write src/**/*.{js,jsx,json,css}"
},
"peerDependencies": {
"@ohif/i18n": "0.2.2",
"cornerstone-core": "^2.2.8",
"cornerstone-wado-image-loader": "^2.2.3",
"dcmjs": "^0.3.6",
"dcmjs": "^0.4.7",
"dicom-parser": "^1.8.3",
"hammerjs": "^2.0.8",
"ohif-core": "^0.3.3",
"prop-types": "^15.6.2",
"react": "^15.0.0 || ^16.0.0",
"react-dom": "^15.0.0 || ^16.0.0",
"react-redux": "^6.0.0",
"react-resize-detector": "^3.4.0",
"react-viewerbase": "^0.6.0",
"i18next": "^17.0.3",
"i18next-browser-languagedetector": "^3.0.1",
"ohif-core": "^0.6.0",
"prop-types": "^15.7.2",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-i18next": "^10.11.0",
"react-redux": "^7.1.0",
"react-resize-detector": "^4.2.0",
"react-viewerbase": "^0.15.1",
"redux": "^4.0.1"
},
"dependencies": {
"@babel/runtime": "^7.4.5",
"react-vtkjs-viewport": "0.0.9",
"vtk.js": "^8.11.0"
},
"devDependencies": {
"@babel/core": "^7.2.2",
"@babel/core": "^7.4.5",
"@babel/plugin-external-helpers": "^7.2.0",
"@babel/plugin-proposal-class-properties": "^7.2.3",
"@babel/plugin-transform-runtime": "^7.2.0",
"@babel/preset-env": "^7.2.3",
"@babel/plugin-proposal-class-properties": "^7.4.4",
"@babel/plugin-transform-runtime": "^7.4.4",
"@babel/preset-env": "^7.4.5",
"@babel/preset-react": "^7.0.0",
"babel-eslint": "^10.0.1",
"babel-loader": "^8.0.6",
"cornerstone-tools": "^3.13.0",
"cornerstone-wado-image-loader": "^2.2.3",
"cross-env": "^5.2.0",
"eslint": "5.13.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^8.0.0",
"eslint-plugin-promise": "^4.0.1",
"eslint-plugin-react": "^7.11.1",
"dcmjs": "^0.4.7",
"dicom-parser": "^1.8.3",
"eslint": "5.16.0",
"eslint-plugin-import": "^2.17.3",
"eslint-plugin-node": "^9.1.0",
"eslint-plugin-promise": "^4.1.1",
"eslint-plugin-react": "^7.13.0",
"gh-pages": "^2.0.1",
"husky": "^1.3.1",
"lint-staged": "^8.1.0",
"prettier": "^1.15.3",
"husky": "^2.4.1",
"i18next": "^17.0.3",
"i18next-browser-languagedetector": "^3.0.1",
"lint-staged": "^8.2.0",
"ohif-core": "^0.7.0",
"prettier": "^1.18.2",
"react": "^16.6.3",
"react-dom": "^16.6.3",
"rollup": "^1.1.2",
"rollup-plugin-babel": "^4.2.0",
"rollup-plugin-commonjs": "^9.2.0",
"rollup-plugin-node-builtins": "^2.1.2",
"rollup-plugin-node-resolve": "^4.0.0",
"rollup-plugin-peer-deps-external": "^2.2.0",
"rollup-plugin-postcss": "^2.0.3",
"rollup-plugin-url": "^2.1.0",
"stylelint": "^9.9.0",
"stylelint-config-recommended": "^2.1.0",
"stylus": "^0.54.5"
"react-i18next": "^10.11.0",
"react-redux": "^7.1.0",
"react-viewerbase": "^0.15.1",
"redux": "^4.0.1",
"shader-loader": "^1.3.1",
"stylelint": "^10.1.0",
"stylelint-config-recommended": "^2.2.0",
"stylus": "^0.54.5",
"webpack": "^4.33.0",
"webpack-cli": "^3.3.4",
"worker-loader": "^2.0.0"
},
"husky": {
"hooks": {
@@ -88,10 +105,5 @@
],
"publishConfig": {
"access": "public"
},
"dependencies": {
"@babel/runtime": "^7.2.0",
"classnames": "^2.2.6",
"react-vtkjs-viewport": "^0.0.7"
}
}
@@ -6,6 +6,7 @@ import pkg from './package.json';
import postcss from 'rollup-plugin-postcss';
import resolve from 'rollup-plugin-node-resolve';
import url from 'rollup-plugin-url';
import copy from 'rollup-plugin-copy';
// Deal with https://github.com/rollup/rollup-plugin-commonjs/issues/297
@@ -24,7 +25,8 @@ const globals = {
dcmjs: 'dcmjs',
'dicom-parser': 'dicomParser',
'ohif-core': 'OHIF',
hammerjs: 'Hammer'
hammerjs: 'Hammer',
'@ohif/i18n': 'i18n'
};
export default {
@@ -56,6 +58,10 @@ export default {
externalHelpers: true,
runtimeHelpers: true
}),
copy({
targets: ['src/locales'],
outputFolder: 'dist',
}),
resolve(),
commonjs({
include: ['node_modules/**', '.yalc/**'],
@@ -1,37 +0,0 @@
import { connect } from 'react-redux';
import { ToolbarSection } from 'react-viewerbase';
import OHIF from 'ohif-core';
const { setToolActive } = OHIF.redux.actions;
const mapStateToProps = state => {
const activeButton = state.tools.buttons.find(tool => tool.active === true);
return {
buttons: [
{
command: 'Rotate',
type: 'tool',
text: 'Rotate',
icon: '3d-rotate',
active: true
}
],
activeCommand: 'Rotate'
};
};
const mapDispatchToProps = dispatch => {
return {
setToolActive: tool => {
//dispatch(setToolActive(tool.command))
}
};
};
const ConnectedToolbarSection = connect(
mapStateToProps,
mapDispatchToProps
)(ToolbarSection);
export default ConnectedToolbarSection;
@@ -1,15 +1,10 @@
import { connect } from 'react-redux';
import { VTKMPRViewport } from 'react-vtkjs-viewport';
import OHIF from 'ohif-core';
import { View2D } from 'react-vtkjs-viewport';
import { connect } from 'react-redux';
const {
setViewportActive,
setViewportSpecificData,
clearViewportSpecificData
} = OHIF.redux.actions;
const { setViewportActive, setViewportSpecificData } = OHIF.redux.actions;
const mapStateToProps = (state, ownProps) => {
const activeButton = state.tools.buttons.find(tool => tool.active === true);
let dataFromStore;
if (state.extensions && state.extensions.vtk) {
@@ -17,11 +12,8 @@ const mapStateToProps = (state, ownProps) => {
}
// If this is the active viewport, enable prefetching.
const { viewportIndex } = ownProps; //.viewportData;
const { viewportIndex } = ownProps;
const isActive = viewportIndex === state.viewports.activeViewportIndex;
const viewportSpecificData =
state.viewports.viewportSpecificData[viewportIndex] || {};
const viewportLayout = state.viewports.layout.viewports[viewportIndex];
const pluginDetails = viewportLayout.vtk || {};
@@ -29,7 +21,8 @@ const mapStateToProps = (state, ownProps) => {
layout: state.viewports.layout,
isActive,
...pluginDetails,
activeTool: activeButton && activeButton.command,
// Hopefully this doesn't break anything under the hood for this one
// activeTool: activeButton && activeButton.command,
...dataFromStore,
enableStackPrefetch: isActive,
};
@@ -46,16 +39,42 @@ const mapDispatchToProps = (dispatch, ownProps) => {
setViewportSpecificData: data => {
dispatch(setViewportSpecificData(viewportIndex, data));
},
clearViewportSpecificData: () => {
dispatch(clearViewportSpecificData(viewportIndex));
}
};
};
const mergeProps = (propsFromState, propsFromDispatch, ownProps) => {
const { afterCreation } = propsFromState;
const props = {
...propsFromState,
...propsFromDispatch,
...ownProps,
/**
* Our component sets up the underlying dom element on "componentDidMount"
* for use with VTK.
*
* The onCreated prop passes back an Object containing many of the internal
* components of the VTK scene. We can grab a reference to these here, to
* make playing with VTK's native methods easier.
*
* A similar approach is taken with the Cornerstone extension.
*/
onCreated: api => {
// Store the API details for later
//setViewportSpecificData({ vtkApi: api });
if (afterCreation && typeof afterCreation === 'function') {
afterCreation(api);
}
},
};
return props;
};
const ConnectedVTKViewport = connect(
mapStateToProps,
//mapDispatchToProps
)(VTKMPRViewport);
mapDispatchToProps,
mergeProps
)(View2D);
export default ConnectedVTKViewport;
@@ -1,5 +1,5 @@
.imageViewerLoadingIndicator {
color: #91B9CD;
color: #91b9cd;
}
.loadingIndicator {
@@ -1,17 +1,18 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import './LoadingIndicator.css';
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
class LoadingIndicator extends PureComponent {
static propTypes = {
percentComplete: PropTypes.number.isRequired,
error: PropTypes.object
error: PropTypes.object,
};
static defaultProps = {
percentComplete: 0,
error: null
error: null,
};
render() {
Loaded 100 of 189 files, more files were not shown because too many files have changed in this diff. Show more