11import * as hglib from "https://esm.sh/[email protected] ?deps=react@17,react-dom@17,pixi.js@6" ; 22import { v4 } from "https://esm.sh/@lukeed/[email protected] " ; 33
4- /** @import { HGC, PluginDataFetcherConstructor, GenomicLocation, Viewconf } from "./types.ts" */
4+ /** @import { HGC, PluginDataFetcherConstructor, GenomicLocation, Viewconf, DataFetcher } from "./types.ts" */
55
6- // Make sure plugins are registered and enabled
7- window . higlassDataFetchersByType = window . higlassDataFetchersByType ||
8- { } ;
6+ const NAME = "jupyter" ;
97
108/**
119 * @param {string } href
@@ -47,7 +45,8 @@ async function requireScripts(pluginUrls) {
4745 // @ts -expect-error - not on the window
4846 requirejs : window . requirejs ,
4947 } ;
50- for ( const field of Object . keys ( backup ) ) {
48+ for ( let field of Object . keys ( backup ) ) {
49+ // @ts -expect-error - not on the window
5150 window [ field ] = undefined ;
5251 }
5352
@@ -170,10 +169,10 @@ function resolveJupyterServers(viewConfig) {
170169 let copy = JSON . parse ( JSON . stringify ( viewConfig ) ) ;
171170 for ( let view of copy . views ) {
172171 for ( let track of Object . values ( view . tracks ) . flat ( ) ) {
173- if ( track ?. server === "jupyter" ) {
172+ if ( track ?. server === NAME ) {
174173 delete track . server ;
175174 track . data = track . data || { } ;
176- track . data . type = "jupyter" ;
175+ track . data . type = NAME ;
177176 track . data . tilesetUid = track . tilesetUid ;
178177 }
179178 }
@@ -182,32 +181,34 @@ function resolveJupyterServers(viewConfig) {
182181}
183182
184183/**
185- * @param {import("npm:@anywidget/types").AnyModel } model
186- * @returns {PluginDataFetcherConstructor }
187- */
188- function createDataFetcherForModel ( model ) {
189- /**
190- * @param {HGC } hgc
191- * @param {Record<string, unknown> } dataConfig
192- * @param {unknown } pubSub
193- */
194- const DataFetcher = function createDataFetcher ( hgc , dataConfig , pubSub ) {
195- let config = { ...dataConfig , server : "jupyter" } ;
184+ * @param {import("npm:@anywidget/[email protected] ").AnyModel<State> } model */ 185+ async function registerJupyterHiGlassDataFetcher ( model ) {
186+ if ( window ?. higlassDataFetchersByType ?. [ NAME ] ) {
187+ return ;
188+ }
189+
190+ let tModel = await model . widget_manager . get_model (
191+ model . get ( "_tileset_client" ) . slice ( "IPY_MODEL_" . length ) ,
192+ ) ;
193+
194+ /** @type {(...args: ConstructorParameters<PluginDataFetcherConstructor>) => DataFetcher } */
195+ function DataFetcher ( hgc , dataConfig , pubSub ) {
196+ let config = { ...dataConfig , server : NAME } ;
196197 return new hgc . dataFetchers . DataFetcher ( config , pubSub , {
197198 async fetchTilesetInfo ( { server, tilesetUid } ) {
198- assert ( server === "jupyter" , "must be a jupyter server" ) ;
199- let response = await sendCustomMessage ( model , {
199+ assert ( server === NAME , "must be a jupyter server" ) ;
200+ let response = await sendCustomMessage ( tModel , {
200201 payload : { type : "tileset_info" , tilesetUid } ,
201202 } ) ;
202203 return response . payload ;
203204 } ,
204205 async fetchTiles ( { tileIds } ) {
205- let response = await sendCustomMessage ( model , {
206+ let response = await sendCustomMessage ( tModel , {
206207 payload : { type : "tiles" , tileIds } ,
207208 } ) ;
208209 let result = hgc . services . tileResponseToData (
209210 response . payload ,
210- config . server ,
211+ NAME ,
211212 tileIds ,
212213 ) ;
213214 return result ;
@@ -216,9 +217,14 @@ function createDataFetcherForModel(model) {
216217 throw new Error ( "Not implemented" ) ;
217218 } ,
218219 } ) ;
219- } ;
220+ }
220221
221- return /** @type {any } */ ( DataFetcher ) ;
222+ /** @type {PluginDataFetcherConstructor } */
223+ // @ts -expect-error - classic function definition (above) supports `new` invocation
224+ let dataFetcher = DataFetcher ;
225+
226+ window . higlassDataFetchersByType ??= { } ;
227+ window . higlassDataFetchersByType [ NAME ] = { name : NAME , dataFetcher } ;
222228}
223229
224230/**
@@ -250,61 +256,49 @@ function addEventListenersTo(el) {
250256 * @typedef State
251257 * @property {Viewconf } _viewconf
252258 * @property {Record<string, unknown> } _options
253- * @property {`IPYMODEL_ ${string}` } _tileset_client
259+ * @property {`IPY_MODEL_ ${string}` } _tileset_client
254260 * @property {Array<number> | Array<Array<number>> } location
255261 * @property {Array<string> } _plugin_urls
256262 */
257263
258- export default ( ) => {
259- /** @type {Promise<void> } */
260- let scriptsPromise = Promise . resolve ( ) ;
261- return {
262- /** @type {import("npm:@anywidget/[email protected] ").Initialize<State> } */ 263- async initialize ( { model } ) {
264- scriptsPromise = requireScripts ( model . get ( "_plugin_urls" ) ) ;
265- let tilesetClientModel = await model . widget_manager . get_model (
266- model . get ( "_tileset_client" ) . slice ( "IPY_MODEL_" . length ) ,
267- ) ;
268- window . higlassDataFetchersByType [ "jupyter" ] = {
269- name : "jupyter" ,
270- dataFetcher : createDataFetcherForModel ( tilesetClientModel ) ,
271- } ;
272- } ,
273- /** @type {import("npm:@anywidget/types").Render<State> } */
274- async render ( { model, el } ) {
275- await scriptsPromise ;
276- let viewconf = resolveJupyterServers (
277- model . get ( "_viewconf" ) ,
278- ) ;
279- let options = model . get ( "_options" ) ?? { } ;
280- let api = await hglib . viewer ( el , viewconf , options ) ;
281- let unlisten = addEventListenersTo ( el ) ;
264+ export default {
265+ /** @type {import("npm:@anywidget/types").Render<State> } */
266+ async render ( { model, el } ) {
267+ await Promise . all ( [
268+ requireScripts ( model . get ( "_plugin_urls" ) ) ,
269+ registerJupyterHiGlassDataFetcher ( model ) ,
270+ ] ) ;
271+ let viewconf = resolveJupyterServers (
272+ model . get ( "_viewconf" ) ,
273+ ) ;
274+ let options = model . get ( "_options" ) ?? { } ;
275+ let api = await hglib . viewer ( el , viewconf , options ) ;
276+ let unlisten = addEventListenersTo ( el ) ;
282277
283- model . on ( "msg:custom" , ( msg ) => {
284- msg = JSON . parse ( msg ) ;
285- let [ fn , ...args ] = msg ;
286- api [ fn ] ( ...args ) ;
287- } ) ;
278+ model . on ( "msg:custom" , ( msg ) => {
279+ msg = JSON . parse ( msg ) ;
280+ let [ fn , ...args ] = msg ;
281+ api [ fn ] ( ...args ) ;
282+ } ) ;
288283
289- if ( viewconf . views . length === 1 ) {
290- api . on ( "location" , ( /** @type {GenomicLocation } */ loc ) => {
291- model . set ( "location" , locationToCoordinates ( loc ) ) ;
284+ if ( viewconf . views . length === 1 ) {
285+ api . on ( "location" , ( /** @type {GenomicLocation } */ loc ) => {
286+ model . set ( "location" , locationToCoordinates ( loc ) ) ;
287+ model . save_changes ( ) ;
288+ } , viewconf . views [ 0 ] . uid ) ;
289+ } else {
290+ viewconf . views . forEach ( ( view , idx ) => {
291+ api . on ( "location" , ( /** @type {GenomicLocation } */ loc ) => {
292+ let location = model . get ( "location" ) . slice ( ) ;
293+ location [ idx ] = locationToCoordinates ( loc ) ;
294+ model . set ( "location" , location ) ;
292295 model . save_changes ( ) ;
293- } , viewconf . views [ 0 ] . uid ) ;
294- } else {
295- viewconf . views . forEach ( ( view , idx ) => {
296- api . on ( "location" , ( /** @type {GenomicLocation } */ loc ) => {
297- let location = model . get ( "location" ) . slice ( ) ;
298- location [ idx ] = locationToCoordinates ( loc ) ;
299- model . set ( "location" , location ) ;
300- model . save_changes ( ) ;
301- } , view . uid ) ;
302- } ) ;
303- }
296+ } , view . uid ) ;
297+ } ) ;
298+ }
304299
305- return ( ) => {
306- unlisten ( ) ;
307- } ;
308- } ,
309- } ;
300+ return ( ) => {
301+ unlisten ( ) ;
302+ } ;
303+ } ,
310304} ;
0 commit comments