javascript-renderer-extension.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. "use strict";
  2. // Copyright (c) Jupyter Development Team.
  3. // Distributed under the terms of the Modified BSD License.
  4. var __importDefault = (this && this.__importDefault) || function (mod) {
  5. return (mod && mod.__esModule) ? mod : { "default": mod };
  6. };
  7. Object.defineProperty(exports, "__esModule", { value: true });
  8. const widgets_1 = require("@lumino/widgets");
  9. const plotly_1 = __importDefault(require("plotly.js/dist/plotly"));
  10. require("../style/index.css");
  11. /**
  12. * The CSS class to add to the Plotly Widget.
  13. */
  14. const CSS_CLASS = "jp-RenderedPlotly";
  15. /**
  16. * The CSS class for a Plotly icon.
  17. */
  18. const CSS_ICON_CLASS = "jp-MaterialIcon jp-PlotlyIcon";
  19. /**
  20. * The MIME type for Plotly.
  21. * The version of this follows the major version of Plotly.
  22. */
  23. exports.MIME_TYPE = "application/vnd.plotly.v1+json";
  24. class RenderedPlotly extends widgets_1.Widget {
  25. /**
  26. * Create a new widget for rendering Plotly.
  27. */
  28. constructor(options) {
  29. super();
  30. this.addClass(CSS_CLASS);
  31. this._mimeType = options.mimeType;
  32. // Create image element
  33. this._img_el = document.createElement("img");
  34. this._img_el.className = "plot-img";
  35. this.node.appendChild(this._img_el);
  36. // Install image hover callback
  37. this._img_el.addEventListener("mouseenter", (event) => {
  38. this.createGraph(this._model);
  39. });
  40. }
  41. /**
  42. * Render Plotly into this widget's node.
  43. */
  44. renderModel(model) {
  45. if (this.hasGraphElement()) {
  46. // We already have a graph, don't overwrite it
  47. return Promise.resolve();
  48. }
  49. // Save off reference to model so that we can regenerate the plot later
  50. this._model = model;
  51. // Check for PNG data in mime bundle
  52. const png_data = model.data["image/png"];
  53. if (png_data !== undefined && png_data !== null) {
  54. // We have PNG data, use it
  55. this.updateImage(png_data);
  56. return Promise.resolve();
  57. }
  58. else {
  59. // Create a new graph
  60. return this.createGraph(model);
  61. }
  62. }
  63. hasGraphElement() {
  64. // Check for the presence of the .plot-container element that plotly.js
  65. // places at the top of the figure structure
  66. return this.node.querySelector(".plot-container") !== null;
  67. }
  68. updateImage(png_data) {
  69. this.hideGraph();
  70. this._img_el.src = "data:image/png;base64," + png_data;
  71. this.showImage();
  72. }
  73. hideGraph() {
  74. // Hide the graph if there is one
  75. let el = this.node.querySelector(".plot-container");
  76. if (el !== null && el !== undefined) {
  77. el.style.display = "none";
  78. }
  79. }
  80. showGraph() {
  81. // Show the graph if there is one
  82. let el = this.node.querySelector(".plot-container");
  83. if (el !== null && el !== undefined) {
  84. el.style.display = "block";
  85. }
  86. }
  87. hideImage() {
  88. // Hide the image element
  89. let el = this.node.querySelector(".plot-img");
  90. if (el !== null && el !== undefined) {
  91. el.style.display = "none";
  92. }
  93. }
  94. showImage() {
  95. // Show the image element
  96. let el = this.node.querySelector(".plot-img");
  97. if (el !== null && el !== undefined) {
  98. el.style.display = "block";
  99. }
  100. }
  101. createGraph(model) {
  102. const { data, layout, frames, config } = model.data[this._mimeType];
  103. return plotly_1.default.react(this.node, data, layout, config).then((plot) => {
  104. this.showGraph();
  105. this.hideImage();
  106. this.update();
  107. if (frames) {
  108. plotly_1.default.addFrames(this.node, frames);
  109. }
  110. if (this.node.offsetWidth > 0 && this.node.offsetHeight > 0) {
  111. plotly_1.default.toImage(plot, {
  112. format: "png",
  113. width: this.node.offsetWidth,
  114. height: this.node.offsetHeight,
  115. }).then((url) => {
  116. const imageData = url.split(",")[1];
  117. if (model.data["image/png"] !== imageData) {
  118. model.setData({
  119. data: Object.assign(Object.assign({}, model.data), { "image/png": imageData }),
  120. });
  121. }
  122. });
  123. }
  124. // Handle webgl context lost events
  125. this.node.on("plotly_webglcontextlost", () => {
  126. const png_data = model.data["image/png"];
  127. if (png_data !== undefined && png_data !== null) {
  128. // We have PNG data, use it
  129. this.updateImage(png_data);
  130. return Promise.resolve();
  131. }
  132. });
  133. });
  134. }
  135. /**
  136. * A message handler invoked on an `'after-show'` message.
  137. */
  138. onAfterShow(msg) {
  139. this.update();
  140. }
  141. /**
  142. * A message handler invoked on a `'resize'` message.
  143. */
  144. onResize(msg) {
  145. this.update();
  146. }
  147. /**
  148. * A message handler invoked on an `'update-request'` message.
  149. */
  150. onUpdateRequest(msg) {
  151. if (this.isVisible && this.hasGraphElement()) {
  152. plotly_1.default.redraw(this.node).then(() => {
  153. plotly_1.default.Plots.resize(this.node);
  154. });
  155. }
  156. }
  157. }
  158. exports.RenderedPlotly = RenderedPlotly;
  159. /**
  160. * A mime renderer factory for Plotly data.
  161. */
  162. exports.rendererFactory = {
  163. safe: true,
  164. mimeTypes: [exports.MIME_TYPE],
  165. createRenderer: (options) => new RenderedPlotly(options),
  166. };
  167. const extensions = [
  168. {
  169. id: "@jupyterlab/plotly-extension:factory",
  170. rendererFactory: exports.rendererFactory,
  171. rank: 0,
  172. dataType: "json",
  173. fileTypes: [
  174. {
  175. name: "plotly",
  176. mimeTypes: [exports.MIME_TYPE],
  177. extensions: [".plotly", ".plotly.json"],
  178. iconClass: CSS_ICON_CLASS,
  179. },
  180. ],
  181. documentWidgetFactoryOptions: {
  182. name: "Plotly",
  183. primaryFileType: "plotly",
  184. fileTypes: ["plotly", "json"],
  185. defaultFor: ["plotly"],
  186. },
  187. },
  188. ];
  189. exports.default = extensions;