@jbrowse/plugin-circular-view 2.3.4 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/dist/BaseChordDisplay/components/Loading.js.map +1 -1
  2. package/dist/BaseChordDisplay/index.d.ts +2 -2
  3. package/dist/BaseChordDisplay/index.js +4 -4
  4. package/dist/BaseChordDisplay/index.js.map +1 -1
  5. package/dist/BaseChordDisplay/models/{baseChordDisplayConfig.js → configSchema.js} +1 -1
  6. package/dist/BaseChordDisplay/models/configSchema.js.map +1 -0
  7. package/dist/BaseChordDisplay/models/{BaseChordDisplayModel.d.ts → model.d.ts} +12 -0
  8. package/dist/BaseChordDisplay/models/{BaseChordDisplayModel.js → model.js} +33 -23
  9. package/dist/BaseChordDisplay/models/model.js.map +1 -0
  10. package/dist/BaseChordDisplay/models/renderReaction.d.ts +1 -1
  11. package/dist/BaseChordDisplay/models/renderReaction.js +4 -5
  12. package/dist/BaseChordDisplay/models/renderReaction.js.map +1 -1
  13. package/dist/CircularView/components/CircularView.js +9 -20
  14. package/dist/CircularView/components/CircularView.js.map +1 -1
  15. package/dist/CircularView/components/Controls.d.ts +2 -2
  16. package/dist/CircularView/components/Controls.js +60 -24
  17. package/dist/CircularView/components/Controls.js.map +1 -1
  18. package/dist/CircularView/components/ExportSvgDialog.d.ts +8 -0
  19. package/dist/CircularView/components/ExportSvgDialog.js +76 -0
  20. package/dist/CircularView/components/ExportSvgDialog.js.map +1 -0
  21. package/dist/CircularView/components/Ruler.d.ts +2 -2
  22. package/dist/CircularView/components/Ruler.js +12 -20
  23. package/dist/CircularView/components/Ruler.js.map +1 -1
  24. package/dist/CircularView/models/CircularView.d.ts +30 -26
  25. package/dist/CircularView/models/CircularView.js +66 -22
  26. package/dist/CircularView/models/CircularView.js.map +1 -1
  27. package/dist/CircularView/models/slices.d.ts +23 -10
  28. package/dist/CircularView/models/slices.js +10 -7
  29. package/dist/CircularView/models/slices.js.map +1 -1
  30. package/dist/CircularView/models/viewportVisibleRegion.js +2 -4
  31. package/dist/CircularView/models/viewportVisibleRegion.js.map +1 -1
  32. package/dist/CircularView/svgcomponents/SVGBackground.d.ts +6 -0
  33. package/dist/CircularView/svgcomponents/SVGBackground.js +13 -0
  34. package/dist/CircularView/svgcomponents/SVGBackground.js.map +1 -0
  35. package/dist/CircularView/svgcomponents/SVGCircularView.d.ts +4 -0
  36. package/dist/CircularView/svgcomponents/SVGCircularView.js +40 -0
  37. package/dist/CircularView/svgcomponents/SVGCircularView.js.map +1 -0
  38. package/dist/LaunchCircularView/index.js +1 -1
  39. package/dist/LaunchCircularView/index.js.map +1 -1
  40. package/dist/index.d.ts +1 -2
  41. package/dist/index.js +1 -0
  42. package/dist/index.js.map +1 -1
  43. package/esm/BaseChordDisplay/components/Loading.js.map +1 -1
  44. package/esm/BaseChordDisplay/index.d.ts +2 -2
  45. package/esm/BaseChordDisplay/index.js +2 -2
  46. package/esm/BaseChordDisplay/index.js.map +1 -1
  47. package/esm/BaseChordDisplay/models/{baseChordDisplayConfig.js → configSchema.js} +1 -1
  48. package/esm/BaseChordDisplay/models/configSchema.js.map +1 -0
  49. package/esm/BaseChordDisplay/models/{BaseChordDisplayModel.d.ts → model.d.ts} +12 -0
  50. package/esm/BaseChordDisplay/models/{BaseChordDisplayModel.js → model.js} +34 -24
  51. package/esm/BaseChordDisplay/models/model.js.map +1 -0
  52. package/esm/BaseChordDisplay/models/renderReaction.d.ts +1 -1
  53. package/esm/BaseChordDisplay/models/renderReaction.js +4 -5
  54. package/esm/BaseChordDisplay/models/renderReaction.js.map +1 -1
  55. package/esm/CircularView/components/CircularView.js +9 -20
  56. package/esm/CircularView/components/CircularView.js.map +1 -1
  57. package/esm/CircularView/components/Controls.d.ts +2 -2
  58. package/esm/CircularView/components/Controls.js +37 -24
  59. package/esm/CircularView/components/Controls.js.map +1 -1
  60. package/esm/CircularView/components/ExportSvgDialog.d.ts +8 -0
  61. package/esm/CircularView/components/ExportSvgDialog.js +50 -0
  62. package/esm/CircularView/components/ExportSvgDialog.js.map +1 -0
  63. package/esm/CircularView/components/Ruler.d.ts +2 -2
  64. package/esm/CircularView/components/Ruler.js +12 -20
  65. package/esm/CircularView/components/Ruler.js.map +1 -1
  66. package/esm/CircularView/models/CircularView.d.ts +30 -26
  67. package/esm/CircularView/models/CircularView.js +63 -22
  68. package/esm/CircularView/models/CircularView.js.map +1 -1
  69. package/esm/CircularView/models/slices.d.ts +23 -10
  70. package/esm/CircularView/models/slices.js +10 -7
  71. package/esm/CircularView/models/slices.js.map +1 -1
  72. package/esm/CircularView/models/viewportVisibleRegion.js +2 -4
  73. package/esm/CircularView/models/viewportVisibleRegion.js.map +1 -1
  74. package/esm/CircularView/svgcomponents/SVGBackground.d.ts +6 -0
  75. package/esm/CircularView/svgcomponents/SVGBackground.js +7 -0
  76. package/esm/CircularView/svgcomponents/SVGBackground.js.map +1 -0
  77. package/esm/CircularView/svgcomponents/SVGCircularView.d.ts +4 -0
  78. package/esm/CircularView/svgcomponents/SVGCircularView.js +33 -0
  79. package/esm/CircularView/svgcomponents/SVGCircularView.js.map +1 -0
  80. package/esm/LaunchCircularView/index.js +1 -1
  81. package/esm/LaunchCircularView/index.js.map +1 -1
  82. package/esm/index.d.ts +1 -2
  83. package/esm/index.js +1 -0
  84. package/esm/index.js.map +1 -1
  85. package/package.json +5 -3
  86. package/src/BaseChordDisplay/components/Loading.tsx +1 -0
  87. package/src/BaseChordDisplay/index.ts +2 -2
  88. package/src/BaseChordDisplay/models/{BaseChordDisplayModel.ts → model.tsx} +47 -25
  89. package/src/BaseChordDisplay/models/renderReaction.ts +4 -7
  90. package/src/CircularView/components/CircularView.tsx +11 -26
  91. package/src/CircularView/components/Controls.tsx +41 -28
  92. package/src/CircularView/components/ExportSvgDialog.tsx +132 -0
  93. package/src/CircularView/components/Ruler.tsx +187 -182
  94. package/src/CircularView/models/CircularView.ts +87 -45
  95. package/src/CircularView/models/slices.ts +32 -12
  96. package/src/CircularView/models/viewportVisibleRegion.ts +2 -4
  97. package/src/CircularView/svgcomponents/SVGBackground.tsx +21 -0
  98. package/src/CircularView/svgcomponents/SVGCircularView.tsx +58 -0
  99. package/src/LaunchCircularView/index.ts +1 -1
  100. package/src/index.ts +5 -5
  101. package/dist/BaseChordDisplay/models/BaseChordDisplayModel.js.map +0 -1
  102. package/dist/BaseChordDisplay/models/baseChordDisplayConfig.js.map +0 -1
  103. package/esm/BaseChordDisplay/models/BaseChordDisplayModel.js.map +0 -1
  104. package/esm/BaseChordDisplay/models/baseChordDisplayConfig.js.map +0 -1
  105. /package/dist/BaseChordDisplay/models/{baseChordDisplayConfig.d.ts → configSchema.d.ts} +0 -0
  106. /package/esm/BaseChordDisplay/models/{baseChordDisplayConfig.d.ts → configSchema.d.ts} +0 -0
  107. /package/src/BaseChordDisplay/models/{baseChordDisplayConfig.ts → configSchema.ts} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SVGCircularView.js","sourceRoot":"","sources":["../../../src/CircularView/svgcomponents/SVGCircularView.tsx"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { when } from 'mobx';
2
2
  export default (pluginManager) => {
3
3
  pluginManager.addToExtensionPoint('LaunchView-CircularView',
4
- // @ts-ignore
4
+ // @ts-expect-error
5
5
  async ({ session, assembly, loc, tracks = [], }) => {
6
6
  const { assemblyManager } = session;
7
7
  const view = session.addView('CircularView', {});
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/LaunchCircularView/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAS3B,eAAe,CAAC,aAA4B,EAAE,EAAE;IAC9C,aAAa,CAAC,mBAAmB,CAC/B,yBAAyB;IACzB,aAAa;IACb,KAAK,EAAE,EACL,OAAO,EACP,QAAQ,EACR,GAAG,EACH,MAAM,GAAG,EAAE,GAMZ,EAAE,EAAE;QACH,MAAM,EAAE,eAAe,EAAE,GAAG,OAAO,CAAA;QACnC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAQ,CAAA;QAEvD,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QAElC,IAAI,CAAC,QAAQ,EAAE;YACb,MAAM,IAAI,KAAK,CACb,0DAA0D,CAC3D,CAAA;SACF;QAED,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAA;QAC3D,IAAI,CAAC,GAAG,EAAE;YACR,MAAM,IAAI,KAAK,CACb,aAAa,QAAQ,iDAAiD,CACvE,CAAA;SACF;QAED,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAA;QAE3C,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;IAChD,CAAC,CACF,CAAA;AACH,CAAC,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/LaunchCircularView/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAS3B,eAAe,CAAC,aAA4B,EAAE,EAAE;IAC9C,aAAa,CAAC,mBAAmB,CAC/B,yBAAyB;IACzB,mBAAmB;IACnB,KAAK,EAAE,EACL,OAAO,EACP,QAAQ,EACR,GAAG,EACH,MAAM,GAAG,EAAE,GAMZ,EAAE,EAAE;QACH,MAAM,EAAE,eAAe,EAAE,GAAG,OAAO,CAAA;QACnC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAQ,CAAA;QAEvD,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QAElC,IAAI,CAAC,QAAQ,EAAE;YACb,MAAM,IAAI,KAAK,CACb,0DAA0D,CAC3D,CAAA;SACF;QAED,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAA;QAC3D,IAAI,CAAC,GAAG,EAAE;YACR,MAAM,IAAI,KAAK,CACb,aAAa,QAAQ,iDAAiD,CACvE,CAAA;SACF;QAED,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAA;QAE3C,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;IAChD,CAAC,CACF,CAAA;AACH,CAAC,CAAA"}
package/esm/index.d.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  import PluginManager from '@jbrowse/core/PluginManager';
2
2
  import Plugin from '@jbrowse/core/Plugin';
3
- import { CircularViewModel, CircularViewStateModel } from './CircularView/models/CircularView';
4
3
  export default class CircularViewPlugin extends Plugin {
5
4
  name: string;
6
5
  install(pluginManager: PluginManager): void;
7
6
  configure(pluginManager: PluginManager): void;
8
7
  }
9
8
  export { baseChordDisplayConfig, BaseChordDisplayModel, BaseChordDisplayComponent, } from './BaseChordDisplay';
10
- export type { CircularViewModel, CircularViewStateModel };
9
+ export { type CircularViewModel, type CircularViewStateModel, } from './CircularView/models/CircularView';
package/esm/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { isAbstractMenuManager } from '@jbrowse/core/util';
2
2
  import Plugin from '@jbrowse/core/Plugin';
3
+ // locals
3
4
  import CircularViewF from './CircularView';
4
5
  import LaunchCircularViewF from './LaunchCircularView';
5
6
  // icons
package/esm/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAEhF,OAAO,MAAM,MAAM,sBAAsB,CAAA;AAOzC,OAAO,aAAa,MAAM,gBAAgB,CAAA;AAC1C,OAAO,mBAAmB,MAAM,sBAAsB,CAAA;AAEtD,QAAQ;AACR,OAAO,aAAa,MAAM,+BAA+B,CAAA;AAEzD,MAAM,CAAC,OAAO,OAAO,kBAAmB,SAAQ,MAAM;IAAtD;;QACE,SAAI,GAAG,oBAAoB,CAAA;IAkB7B,CAAC;IAhBC,OAAO,CAAC,aAA4B;QAClC,aAAa,CAAC,aAAa,CAAC,CAAA;QAC5B,mBAAmB,CAAC,aAAa,CAAC,CAAA;IACpC,CAAC;IAED,SAAS,CAAC,aAA4B;QACpC,IAAI,qBAAqB,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE;YAClD,aAAa,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,EAAE;gBAC/C,KAAK,EAAE,eAAe;gBACtB,IAAI,EAAE,aAAa;gBACnB,OAAO,EAAE,CAAC,OAA6B,EAAE,EAAE;oBACzC,OAAO,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAA;gBACrC,CAAC;aACF,CAAC,CAAA;SACH;IACH,CAAC;CACF;AAED,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,oBAAoB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAEhF,OAAO,MAAM,MAAM,sBAAsB,CAAA;AAEzC,SAAS;AAET,OAAO,aAAa,MAAM,gBAAgB,CAAA;AAC1C,OAAO,mBAAmB,MAAM,sBAAsB,CAAA;AAEtD,QAAQ;AACR,OAAO,aAAa,MAAM,+BAA+B,CAAA;AAEzD,MAAM,CAAC,OAAO,OAAO,kBAAmB,SAAQ,MAAM;IAAtD;;QACE,SAAI,GAAG,oBAAoB,CAAA;IAkB7B,CAAC;IAhBC,OAAO,CAAC,aAA4B;QAClC,aAAa,CAAC,aAAa,CAAC,CAAA;QAC5B,mBAAmB,CAAC,aAAa,CAAC,CAAA;IACpC,CAAC;IAED,SAAS,CAAC,aAA4B;QACpC,IAAI,qBAAqB,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE;YAClD,aAAa,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,EAAE;gBAC/C,KAAK,EAAE,eAAe;gBACtB,IAAI,EAAE,aAAa;gBACnB,OAAO,EAAE,CAAC,OAA6B,EAAE,EAAE;oBACzC,OAAO,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAA;gBACrC,CAAC;aACF,CAAC,CAAA;SACH;IACH,CAAC;CACF;AAED,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,oBAAoB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/plugin-circular-view",
3
- "version": "2.3.4",
3
+ "version": "2.4.1",
4
4
  "description": "JBrowse 2 circular view",
5
5
  "keywords": [
6
6
  "jbrowse",
@@ -38,7 +38,9 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@mui/icons-material": "^5.0.1",
41
- "clone": "^2.1.2"
41
+ "@types/file-saver": "^2.0.0",
42
+ "clone": "^2.1.2",
43
+ "file-saver": "^2.0.0"
42
44
  },
43
45
  "peerDependencies": {
44
46
  "@jbrowse/core": "^2.0.0",
@@ -56,5 +58,5 @@
56
58
  "distModule": "esm/index.js",
57
59
  "srcModule": "src/index.ts",
58
60
  "module": "esm/index.js",
59
- "gitHead": "98ae48be91ee2371e1b2768a907b4997995e9915"
61
+ "gitHead": "747c50c4edc0184827efa4f8dfc576ca9a72caeb"
60
62
  }
@@ -32,6 +32,7 @@ const useStyles = makeStyles()(theme => {
32
32
  stroke: primary.light,
33
33
  },
34
34
  },
35
+
35
36
  '@keyframes dash': {
36
37
  '0%': {
37
38
  strokeDashoffset: offset,
@@ -1,3 +1,3 @@
1
1
  export { default as BaseChordDisplayComponent } from './components/BaseChordDisplay'
2
- export { BaseChordDisplayModel } from './models/BaseChordDisplayModel'
3
- export { baseChordDisplayConfig } from './models/baseChordDisplayConfig'
2
+ export { BaseChordDisplayModel } from './models/model'
3
+ export { baseChordDisplayConfig } from './models/configSchema'
@@ -15,7 +15,7 @@ import {
15
15
  makeAbortableReaction,
16
16
  AnyReactComponentType,
17
17
  Feature,
18
- Region,
18
+ ReactRendering,
19
19
  } from '@jbrowse/core/util'
20
20
  import {
21
21
  getParentRenderProps,
@@ -25,7 +25,11 @@ import {
25
25
 
26
26
  // locals
27
27
  import { renderReactionData, renderReactionEffect } from './renderReaction'
28
- import { CircularViewModel } from '../../CircularView/models/CircularView'
28
+ import {
29
+ CircularViewModel,
30
+ ExportSvgOptions,
31
+ } from '../../CircularView/models/CircularView'
32
+ import { ThemeOptions } from '@mui/material'
29
33
 
30
34
  /**
31
35
  * #stateModel BaseChordDisplay
@@ -48,19 +52,17 @@ export const BaseChordDisplayModel = types
48
52
  assemblyName: types.maybe(types.string),
49
53
  }),
50
54
  )
51
- .volatile(() => {
52
- return {
53
- // NOTE: all this volatile stuff has to be filled in at once
54
- // so that it stays consistent
55
- filled: false,
56
- reactElement: undefined as React.ReactElement | undefined,
57
- data: undefined,
58
- html: undefined as string | undefined,
59
- message: '',
60
- renderingComponent: undefined as undefined | AnyReactComponentType,
61
- refNameMap: undefined as Record<string, string> | undefined,
62
- }
63
- })
55
+ .volatile(() => ({
56
+ // NOTE: all this volatile stuff has to be filled in at once
57
+ // so that it stays consistent
58
+ filled: false,
59
+ reactElement: undefined as React.ReactElement | undefined,
60
+ data: undefined,
61
+ html: undefined as string | undefined,
62
+ message: '',
63
+ renderingComponent: undefined as undefined | AnyReactComponentType,
64
+ refNameMap: undefined as Record<string, string> | undefined,
65
+ }))
64
66
  .actions(self => {
65
67
  const { pluginManager } = getEnv(self)
66
68
  const track = self
@@ -78,20 +80,19 @@ export const BaseChordDisplayModel = types
78
80
  * #getter
79
81
  */
80
82
  get blockDefinitions() {
81
- const origSlices = (getContainingView(self) as CircularViewModel)
82
- .staticSlices
83
+ const view = getContainingView(self) as CircularViewModel
84
+ const origSlices = view.staticSlices
83
85
  if (!self.refNameMap) {
84
86
  return origSlices
85
87
  }
86
88
 
87
89
  const slices = clone(origSlices)
88
90
 
89
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
90
- slices.forEach((slice: any) => {
91
+ slices.forEach(slice => {
91
92
  const regions = slice.region.elided
92
93
  ? slice.region.regions
93
94
  : [slice.region]
94
- regions.forEach((region: Region) => {
95
+ regions.forEach(region => {
95
96
  const renamed = self.refNameMap?.[region.refName]
96
97
  if (renamed && region.refName !== renamed) {
97
98
  region.refName = renamed
@@ -243,7 +244,7 @@ export const BaseChordDisplayModel = types
243
244
  self,
244
245
  renderReactionData,
245
246
 
246
- // @ts-ignore
247
+ // @ts-expect-error
247
248
  renderReactionEffect,
248
249
  {
249
250
  name: `${self.type} ${self.id} rendering`,
@@ -254,10 +255,11 @@ export const BaseChordDisplayModel = types
254
255
  self.renderSuccess,
255
256
  self.renderError,
256
257
  )
258
+
257
259
  makeAbortableReaction(
258
260
  self,
259
261
  () => ({
260
- assemblyNames: getTrackAssemblyNames(self.parentTrack) as string[],
262
+ assemblyNames: getTrackAssemblyNames(self.parentTrack),
261
263
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
262
264
  adapter: getConf(getParent<any>(self, 2), 'adapter'),
263
265
  assemblyManager: getSession(self).assemblyManager,
@@ -275,9 +277,7 @@ export const BaseChordDisplayModel = types
275
277
  fireImmediately: true,
276
278
  },
277
279
  () => {},
278
- refNameMap => {
279
- self.setRefNameMap(refNameMap)
280
- },
280
+ refNameMap => self.setRefNameMap(refNameMap),
281
281
  error => {
282
282
  console.error(error)
283
283
  self.setError(error)
@@ -285,3 +285,25 @@ export const BaseChordDisplayModel = types
285
285
  )
286
286
  },
287
287
  }))
288
+ .views(self => ({
289
+ /**
290
+ * #method
291
+ */
292
+ async renderSvg(
293
+ opts: ExportSvgOptions & {
294
+ theme: ThemeOptions
295
+ },
296
+ ) {
297
+ const data = renderReactionData(self)
298
+ const rendering = await renderReactionEffect(
299
+ {
300
+ ...data,
301
+ exportSVG: opts,
302
+ theme: opts.theme || data.renderProps.theme,
303
+ },
304
+ undefined,
305
+ self,
306
+ )
307
+ return <ReactRendering rendering={rendering} />
308
+ },
309
+ }))
@@ -27,7 +27,7 @@ export function renderReactionData(self: any) {
27
27
  export async function renderReactionEffect(
28
28
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
29
  props: any,
30
- signal: AbortSignal,
30
+ signal: AbortSignal | undefined,
31
31
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
32
  self: any,
33
33
  ) {
@@ -41,6 +41,7 @@ export async function renderReactionEffect(
41
41
  cannotBeRenderedReason,
42
42
  renderArgs,
43
43
  renderProps,
44
+ exportSVG,
44
45
  } = props
45
46
 
46
47
  if (cannotBeRenderedReason) {
@@ -48,11 +49,7 @@ export async function renderReactionEffect(
48
49
  }
49
50
 
50
51
  // don't try to render 0 or NaN radius or no regions
51
- if (
52
- !props.renderProps.radius ||
53
- !props.renderArgs.regions ||
54
- !props.renderArgs.regions.length
55
- ) {
52
+ if (!renderProps.radius || !renderArgs.regions?.length) {
56
53
  return { message: 'Skipping render' }
57
54
  }
58
55
 
@@ -66,7 +63,7 @@ export async function renderReactionEffect(
66
63
  const { html, ...data } = await rendererType.renderInClient(rpcManager, {
67
64
  ...renderArgs,
68
65
  ...renderProps,
69
- signal,
66
+ exportSVG,
70
67
  })
71
68
 
72
69
  return {
@@ -17,17 +17,10 @@ const useStyles = makeStyles()(theme => ({
17
17
  position: 'relative',
18
18
  marginBottom: theme.spacing(1),
19
19
  overflow: 'hidden',
20
- background: 'white',
21
20
  },
22
21
  scroller: {
23
22
  overflow: 'auto',
24
23
  },
25
- sliceRoot: {
26
- background: 'none',
27
- // background: theme.palette.background.paper,
28
- boxSizing: 'content-box',
29
- display: 'block',
30
- },
31
24
  }))
32
25
 
33
26
  const Slices = observer(({ model }: { model: CircularViewModel }) => {
@@ -36,7 +29,6 @@ const Slices = observer(({ model }: { model: CircularViewModel }) => {
36
29
  {model.staticSlices.map(slice => (
37
30
  <Ruler
38
31
  key={assembleLocString(
39
- // @ts-ignore
40
32
  slice.region.elided ? slice.region.regions[0] : slice.region,
41
33
  )}
42
34
  model={model}
@@ -97,29 +89,22 @@ const CircularViewLoaded = observer(function ({
97
89
  return (
98
90
  <div className={classes.root} style={{ width, height }} data-testid={id}>
99
91
  <div className={classes.scroller} style={{ width, height }}>
100
- <div
92
+ <svg
101
93
  style={{
102
- transform: [`rotate(${offsetRadians}rad)`].join(' '),
94
+ transform: `rotate(${offsetRadians}rad)`,
103
95
  transition: 'transform 0.5s',
104
96
  transformOrigin: centerXY.map(x => `${x}px`).join(' '),
97
+ position: 'absolute',
98
+ left: 0,
99
+ top: 0,
105
100
  }}
101
+ width={figureWidth}
102
+ height={figureHeight}
106
103
  >
107
- <svg
108
- style={{
109
- position: 'absolute',
110
- left: 0,
111
- top: 0,
112
- }}
113
- className={classes.sliceRoot}
114
- width={figureWidth + 'px'}
115
- height={figureHeight + 'px'}
116
- version="1.1"
117
- >
118
- <g transform={`translate(${centerXY})`}>
119
- <Slices model={model} />
120
- </g>
121
- </svg>
122
- </div>
104
+ <g transform={`translate(${centerXY})`}>
105
+ <Slices model={model} />
106
+ </g>
107
+ </svg>
123
108
  </div>
124
109
  <Controls model={model} />
125
110
  {hideVerticalResizeHandle ? null : (
@@ -1,8 +1,8 @@
1
- import React from 'react'
1
+ import React, { useState } from 'react'
2
2
  import { observer } from 'mobx-react'
3
3
  import { IconButton } from '@mui/material'
4
4
  import { makeStyles } from 'tss-react/mui'
5
- import { grey } from '@mui/material/colors'
5
+ import JBrowseMenu from '@jbrowse/core/ui/Menu'
6
6
 
7
7
  // icons
8
8
  import ZoomOutIcon from '@mui/icons-material/ZoomOut'
@@ -11,96 +11,109 @@ import RotateLeftIcon from '@mui/icons-material/RotateLeft'
11
11
  import RotateRightIcon from '@mui/icons-material/RotateRight'
12
12
  import LockOpenIcon from '@mui/icons-material/LockOpen'
13
13
  import LockIcon from '@mui/icons-material/Lock'
14
+ import PhotoCamera from '@mui/icons-material/PhotoCamera'
15
+ import MoreVert from '@mui/icons-material/MoreVert'
14
16
  import { TrackSelector as TrackSelectorIcon } from '@jbrowse/core/ui/Icons'
15
17
 
16
18
  // locals
17
19
  import { CircularViewModel } from '../models/CircularView'
20
+ import { getSession } from '@jbrowse/core/util'
21
+ import ExportSvgDlg from './ExportSvgDialog'
18
22
 
19
- const useStyles = makeStyles()({
20
- iconButton: {
21
- padding: '4px',
22
- margin: '0 2px 0 2px',
23
- },
23
+ const useStyles = makeStyles()(theme => ({
24
24
  controls: {
25
- overflow: 'hidden',
26
- whiteSpace: 'nowrap',
27
25
  position: 'absolute',
28
- background: grey[200],
29
- boxSizing: 'border-box',
30
- borderRight: '1px solid #a2a2a2',
31
- borderBottom: '1px solid #a2a2a2',
26
+ borderRight: `1px solid ${theme.palette.divider}`,
27
+ borderBottom: `1px solid ${theme.palette.divider}`,
32
28
  left: 0,
33
29
  top: 0,
34
30
  },
35
- })
31
+ }))
36
32
 
37
- const Controls = observer(function ({ model }: { model: CircularViewModel }) {
33
+ export default observer(function ({ model }: { model: CircularViewModel }) {
38
34
  const { classes } = useStyles()
35
+ const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null)
39
36
  return (
40
37
  <div className={classes.controls}>
41
38
  <IconButton
42
39
  onClick={model.zoomOutButton}
43
- className={classes.iconButton}
44
40
  title={model.lockedFitToWindow ? 'unlock to zoom out' : 'zoom out'}
45
41
  disabled={model.atMaxBpPerPx || model.lockedFitToWindow}
46
- color="secondary"
47
42
  >
48
43
  <ZoomOutIcon />
49
44
  </IconButton>
50
45
 
51
46
  <IconButton
52
47
  onClick={model.zoomInButton}
53
- className={classes.iconButton}
54
- title="zoom in"
55
48
  disabled={model.atMinBpPerPx}
56
- color="secondary"
49
+ title="zoom in"
57
50
  >
58
51
  <ZoomInIcon />
59
52
  </IconButton>
60
53
 
61
54
  <IconButton
62
55
  onClick={model.rotateCounterClockwiseButton}
63
- className={classes.iconButton}
64
56
  title="rotate counter-clockwise"
65
- color="secondary"
66
57
  >
67
58
  <RotateLeftIcon />
68
59
  </IconButton>
69
60
 
70
61
  <IconButton
71
62
  onClick={model.rotateClockwiseButton}
72
- className={classes.iconButton}
73
63
  title="rotate clockwise"
74
- color="secondary"
75
64
  >
76
65
  <RotateRightIcon />
77
66
  </IconButton>
78
67
 
79
68
  <IconButton
80
69
  onClick={model.toggleFitToWindowLock}
81
- className={classes.iconButton}
82
70
  title={
83
71
  model.lockedFitToWindow
84
72
  ? 'locked model to window size'
85
73
  : 'unlocked model to zoom further'
86
74
  }
87
75
  disabled={model.tooSmallToLock}
88
- color="secondary"
89
76
  >
90
77
  {model.lockedFitToWindow ? <LockIcon /> : <LockOpenIcon />}
91
78
  </IconButton>
92
79
 
80
+ <IconButton onClick={event => setAnchorEl(event.currentTarget)}>
81
+ <MoreVert />
82
+ </IconButton>
83
+
93
84
  {model.hideTrackSelectorButton ? null : (
94
85
  <IconButton
95
86
  onClick={model.activateTrackSelector}
96
87
  title="Open track selector"
97
88
  data-testid="circular_track_select"
98
- color="secondary"
99
89
  >
100
90
  <TrackSelectorIcon />
101
91
  </IconButton>
102
92
  )}
93
+
94
+ {anchorEl ? (
95
+ <JBrowseMenu
96
+ anchorEl={anchorEl}
97
+ menuItems={[
98
+ {
99
+ label: 'Export SVG',
100
+ icon: PhotoCamera,
101
+ onClick: () => {
102
+ getSession(model).queueDialog(handleClose => [
103
+ ExportSvgDlg,
104
+ { model, handleClose },
105
+ ])
106
+ },
107
+ },
108
+ ]}
109
+ onMenuItemClick={(_event, callback) => {
110
+ callback()
111
+ setAnchorEl(null)
112
+ }}
113
+ open={Boolean(anchorEl)}
114
+ onClose={() => setAnchorEl(null)}
115
+ />
116
+ ) : null}
103
117
  </div>
104
118
  )
105
119
  })
106
- export default Controls
@@ -0,0 +1,132 @@
1
+ import React, { useState } from 'react'
2
+ import {
3
+ Button,
4
+ Checkbox,
5
+ CircularProgress,
6
+ DialogActions,
7
+ DialogContent,
8
+ FormControlLabel,
9
+ MenuItem,
10
+ TextField,
11
+ Typography,
12
+ } from '@mui/material'
13
+ import { Dialog, ErrorMessage } from '@jbrowse/core/ui'
14
+
15
+ // locals
16
+ import { ExportSvgOptions } from '../models/CircularView'
17
+ import { getSession, useLocalStorage } from '@jbrowse/core/util'
18
+
19
+ function LoadingMessage() {
20
+ return (
21
+ <div>
22
+ <CircularProgress size={20} style={{ marginRight: 20 }} />
23
+ <Typography display="inline">Creating SVG</Typography>
24
+ </div>
25
+ )
26
+ }
27
+
28
+ function useSvgLocal<T>(key: string, val: T) {
29
+ return useLocalStorage('svg-' + key, val)
30
+ }
31
+
32
+ export default function ExportSvgDlg({
33
+ model,
34
+ handleClose,
35
+ }: {
36
+ model: { exportSvg(opts: ExportSvgOptions): Promise<void> }
37
+ handleClose: () => void
38
+ }) {
39
+ const session = getSession(model)
40
+ const offscreenCanvas = typeof OffscreenCanvas !== 'undefined'
41
+ const [rasterizeLayers, setRasterizeLayers] = useState(offscreenCanvas)
42
+ const [loading, setLoading] = useState(false)
43
+ const [error, setError] = useState<unknown>()
44
+ const [filename, setFilename] = useSvgLocal('file', 'jbrowse.svg')
45
+ const [themeName, setThemeName] = useSvgLocal(
46
+ 'theme',
47
+ session.themeName || 'default',
48
+ )
49
+ return (
50
+ <Dialog open onClose={handleClose} title="Export SVG">
51
+ <DialogContent>
52
+ {error ? (
53
+ <ErrorMessage error={error} />
54
+ ) : loading ? (
55
+ <LoadingMessage />
56
+ ) : null}
57
+ <TextField
58
+ helperText="filename"
59
+ value={filename}
60
+ onChange={event => setFilename(event.target.value)}
61
+ />
62
+ <br />
63
+
64
+ {session.allThemes ? (
65
+ <TextField
66
+ select
67
+ label="Theme"
68
+ value={themeName}
69
+ onChange={event => setThemeName(event.target.value)}
70
+ >
71
+ {Object.entries(session.allThemes()).map(([key, val]) => (
72
+ <MenuItem key={key} value={key}>
73
+ {
74
+ // @ts-expect-error
75
+ val.name || '(Unknown name)'
76
+ }
77
+ </MenuItem>
78
+ ))}
79
+ </TextField>
80
+ ) : null}
81
+ {offscreenCanvas ? (
82
+ <FormControlLabel
83
+ control={
84
+ <Checkbox
85
+ checked={rasterizeLayers}
86
+ onChange={() => setRasterizeLayers(val => !val)}
87
+ />
88
+ }
89
+ label="Rasterize canvas based tracks? File may be much larger if this is turned off"
90
+ />
91
+ ) : (
92
+ <Typography>
93
+ Note: rasterizing layers not yet supported in this browser, so SVG
94
+ size may be large
95
+ </Typography>
96
+ )}
97
+ </DialogContent>
98
+ <DialogActions>
99
+ <Button
100
+ variant="contained"
101
+ color="secondary"
102
+ onClick={() => handleClose()}
103
+ >
104
+ Cancel
105
+ </Button>
106
+ <Button
107
+ variant="contained"
108
+ color="primary"
109
+ type="submit"
110
+ onClick={async () => {
111
+ setLoading(true)
112
+ setError(undefined)
113
+ try {
114
+ await model.exportSvg({
115
+ rasterizeLayers,
116
+ filename,
117
+ themeName,
118
+ })
119
+ handleClose()
120
+ } catch (e) {
121
+ console.error(e)
122
+ setError(e)
123
+ setLoading(false)
124
+ }
125
+ }}
126
+ >
127
+ Submit
128
+ </Button>
129
+ </DialogActions>
130
+ </Dialog>
131
+ )
132
+ }