UNPKG

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