@@ -62,6 +62,45 @@ function downloadFile(content: BlobPart, fileName: string, mimeType: string) {
62
62
document . body . removeChild ( downloadLink ) ;
63
63
}
64
64
65
+ function getSelectedLayer ( tracker : JupyterGISTracker ) : { model : IJupyterGISModel ; selectedLayer : any ; sources : any } | null {
66
+ const model = tracker . currentWidget ?. model as IJupyterGISModel ;
67
+ if ( ! model ) {
68
+ return null ;
69
+ }
70
+
71
+ const localState = model . sharedModel . awareness . getLocalState ( ) ;
72
+ if ( ! localState || ! localState [ 'selected' ] ?. value ) {
73
+ return null ;
74
+ }
75
+
76
+ const selectedLayerId = Object . keys ( localState [ 'selected' ] . value ) [ 0 ] ;
77
+ const layers = model . sharedModel . layers ?? { } ;
78
+ const sources = model . sharedModel . sources ?? { } ;
79
+
80
+ const selectedLayer = layers [ selectedLayerId ] ;
81
+ if ( ! selectedLayer || ! selectedLayer . parameters ) {
82
+ return null ;
83
+ }
84
+
85
+ return { model, selectedLayer, sources } ;
86
+ }
87
+
88
+ async function getGeoJSONString ( source : any , model : IJupyterGISModel ) : Promise < string | null > {
89
+ if ( source . parameters . path ) {
90
+ const fileContent = await loadFile ( {
91
+ filepath : source . parameters . path ,
92
+ type : source . type ,
93
+ model
94
+ } ) ;
95
+ return typeof fileContent === 'object' ? JSON . stringify ( fileContent ) : fileContent ;
96
+ } else if ( source . parameters . data ) {
97
+ return JSON . stringify ( source . parameters . data ) ;
98
+ }
99
+ console . error ( "Source is missing both 'path' and 'data' parameters." ) ;
100
+ return null ;
101
+ }
102
+
103
+
65
104
/**
66
105
* Add the commands to the application's command registry.
67
106
*/
@@ -1178,64 +1217,78 @@ export function addCommands(
1178
1217
}
1179
1218
} ) ;
1180
1219
1181
- commands . addCommand ( CommandIDs . exportLayer , {
1182
- label : trans . __ ( 'Export Layer ' ) ,
1220
+ commands . addCommand ( CommandIDs . downloadGeoJSON , {
1221
+ label : trans . __ ( 'Download as GeoJSON ' ) ,
1183
1222
isEnabled : ( ) => {
1184
- const model = tracker . currentWidget ?. model ;
1185
- const localState = model ?. sharedModel . awareness . getLocalState ( ) ;
1186
-
1187
- if ( ! model || ! localState || ! localState [ 'selected' ] ?. value ) {
1188
- return false ;
1223
+ const selectedLayer = getSelectedLayer ( tracker ) ;
1224
+ return selectedLayer ? [ 'VectorLayer' , 'ShapefileLayer' ] . includes ( selectedLayer . selectedLayer . type ) : false ;
1225
+ } ,
1226
+ execute : async ( ) => {
1227
+ const selectedData = getSelectedLayer ( tracker ) ;
1228
+ if ( ! selectedData ) {
1229
+ return ;
1189
1230
}
1190
1231
1191
- const selectedLayers = localState [ 'selected' ] . value ;
1232
+ const { model, selectedLayer, sources } = selectedData ;
1233
+ const exportSchema = { ...( formSchemaRegistry . getSchemas ( ) . get ( 'ExportGeoJSONSchema' ) as IDict ) } ;
1192
1234
1193
- if ( Object . keys ( selectedLayers ) . length > 1 ) {
1194
- return false ;
1195
- }
1235
+ const formValues = await new Promise < IDict > ( resolve => {
1236
+ const dialog = new ProcessingFormDialog ( {
1237
+ title : 'Download GeoJSON' ,
1238
+ schema : exportSchema ,
1239
+ model,
1240
+ sourceData : { exportFormat : 'GeoJSON' } ,
1241
+ cancelButton : false ,
1242
+ syncData : ( props : IDict ) => {
1243
+ resolve ( props ) ;
1244
+ dialog . dispose ( ) ;
1245
+ }
1246
+ } ) ;
1196
1247
1197
- const layerId = Object . keys ( selectedLayers ) [ 0 ] ;
1198
- const layer = model . getLayer ( layerId ) ;
1248
+ dialog . launch ( ) ;
1249
+ } ) ;
1199
1250
1200
- if ( ! layer ) {
1201
- return false ;
1251
+ if ( ! formValues ) {
1252
+ return ;
1202
1253
}
1203
1254
1204
- return [ 'VectorLayer' , 'ShapefileLayer' ] . includes ( layer . type ) ;
1205
- } ,
1206
- execute : async ( ) => {
1207
- const layers = tracker . currentWidget ?. model . sharedModel . layers ?? { } ;
1208
- const sources = tracker . currentWidget ?. model . sharedModel . sources ?? { } ;
1255
+ const exportFileName = formValues . exportFileName ;
1256
+ const sourceId = selectedLayer . parameters . source ;
1257
+ const source = sources [ sourceId ] ;
1209
1258
1210
- const model = tracker . currentWidget ?. model ;
1211
- const localState = model ?. sharedModel . awareness . getLocalState ( ) ;
1212
- if ( ! model || ! localState || ! localState [ 'selected' ] ?. value ) {
1259
+ const geojsonString = await getGeoJSONString ( source , model ) ;
1260
+ if ( ! geojsonString ) {
1213
1261
return ;
1214
1262
}
1215
1263
1216
- const selectedLayerId = Object . keys ( localState [ 'selected' ] . value ) [ 0 ] ;
1217
- const selectedLayer = layers [ selectedLayerId ] ;
1264
+ downloadFile ( geojsonString , `${ exportFileName } .geojson` , 'application/geo+json' ) ;
1265
+ }
1266
+ } ) ;
1218
1267
1219
- if ( ! selectedLayer || ! selectedLayer . parameters ) {
1220
- console . error ( 'Selected layer not found.' ) ;
1268
+ commands . addCommand ( CommandIDs . downloadGeoTIFF , {
1269
+ label : trans . __ ( 'Download as GeoTIFF' ) ,
1270
+ isEnabled : ( ) => {
1271
+ const selectedLayer = getSelectedLayer ( tracker ) ;
1272
+ return selectedLayer ? [ 'VectorLayer' , 'ShapefileLayer' ] . includes ( selectedLayer . selectedLayer . type ) : false ;
1273
+ } ,
1274
+ execute : async ( ) => {
1275
+ const selectedData = getSelectedLayer ( tracker ) ;
1276
+ if ( ! selectedData ) {
1221
1277
return ;
1222
1278
}
1223
1279
1224
- const exportSchema = {
1225
- ...( formSchemaRegistry . getSchemas ( ) . get ( 'ExportSchema' ) as IDict )
1226
- } ;
1280
+ const { model, selectedLayer, sources } = selectedData ;
1281
+ const exportSchema = { ...( formSchemaRegistry . getSchemas ( ) . get ( 'ExportGeoTIFFSchema' ) as IDict ) } ;
1282
+ console . log ( exportSchema ) ;
1283
+
1227
1284
1228
1285
const formValues = await new Promise < IDict > ( resolve => {
1229
1286
const dialog = new ProcessingFormDialog ( {
1230
- title : 'Export Layer ' ,
1287
+ title : 'Download GeoTIFF ' ,
1231
1288
schema : exportSchema ,
1232
- model : tracker . currentWidget ?. model as IJupyterGISModel ,
1233
- sourceData : {
1234
- exportFormat : 'GeoJSON' ,
1235
- resolutionX : 1200 ,
1236
- resolutionY : 1200
1237
- } ,
1238
- cancelButton : true ,
1289
+ model,
1290
+ sourceData : { resolutionX : 1200 , resolutionY : 1200 } ,
1291
+ cancelButton : false ,
1239
1292
syncData : ( props : IDict ) => {
1240
1293
resolve ( props ) ;
1241
1294
dialog . dispose ( ) ;
@@ -1250,88 +1303,43 @@ export function addCommands(
1250
1303
}
1251
1304
1252
1305
const exportFileName = formValues . exportFileName ;
1253
- const exportFormat = formValues . exportFormat ;
1254
1306
const resolutionX = formValues . resolutionX ?? 1200 ;
1255
1307
const resolutionY = formValues . resolutionY ?? 1200 ;
1256
-
1257
1308
const sourceId = selectedLayer . parameters . source ;
1258
1309
const source = sources [ sourceId ] ;
1259
1310
1260
- if ( ! source . parameters ) {
1261
- console . error ( `Source with ID ${ sourceId } not found or missing path.` ) ;
1262
- return ;
1263
- }
1264
-
1265
- let geojsonString : string ;
1266
- if ( source . parameters . path ) {
1267
- const fileContent = await loadFile ( {
1268
- filepath : source . parameters . path ,
1269
- type : source . type ,
1270
- model : tracker . currentWidget ?. model as IJupyterGISModel
1271
- } ) ;
1272
-
1273
- geojsonString =
1274
- typeof fileContent === 'object'
1275
- ? JSON . stringify ( fileContent )
1276
- : fileContent ;
1277
- } else if ( source . parameters . data ) {
1278
- geojsonString = JSON . stringify ( source . parameters . data ) ;
1279
- } else {
1280
- throw new Error (
1281
- `Source ${ sourceId } is missing both 'path' and 'data' parameters.`
1282
- ) ;
1283
- }
1284
-
1285
- if ( exportFormat === 'GeoJSON' ) {
1286
- downloadFile ( geojsonString , `${ exportFileName } .geojson` , 'application/geo+json' ) ;
1311
+ const geojsonString = await getGeoJSONString ( source , model ) ;
1312
+ if ( ! geojsonString ) {
1287
1313
return ;
1288
1314
}
1289
1315
1290
1316
const Gdal = await getGdal ( ) ;
1291
- const datasetList = await Gdal . open (
1292
- new File ( [ geojsonString ] , 'data.geojson' , {
1293
- type : 'application/geo+json'
1294
- } )
1295
- ) ;
1296
-
1297
- const dataset = datasetList . datasets [ 0 ] ; // Extract the first dataset
1317
+ const datasetList = await Gdal . open ( new File ( [ geojsonString ] , 'data.geojson' , { type : 'application/geo+json' } ) ) ;
1318
+ const dataset = datasetList . datasets [ 0 ] ;
1298
1319
1299
1320
if ( ! dataset ) {
1300
1321
console . error ( 'Dataset could not be opened.' ) ;
1301
1322
return ;
1302
1323
}
1303
1324
1304
- let options : string [ ] = [ ] ;
1305
-
1306
- if ( exportFormat === 'GeoTIFF' ) {
1307
- options = [
1308
- '-of' ,
1309
- 'GTiff' ,
1310
- '-ot' ,
1311
- 'Float32' ,
1312
- '-a_nodata' ,
1313
- '-1.0' ,
1314
- '-burn' ,
1315
- '0.0' ,
1316
- '-ts' ,
1317
- resolutionX . toString ( ) ,
1318
- resolutionY . toString ( ) ,
1319
- '-l' ,
1320
- 'data' ,
1321
- 'data.geojson' ,
1322
- 'output.tif'
1323
- ] ;
1324
- }
1325
+ const options = [
1326
+ '-of' , 'GTiff' ,
1327
+ '-ot' , 'Float32' ,
1328
+ '-a_nodata' , '-1.0' ,
1329
+ '-burn' , '0.0' ,
1330
+ '-ts' , resolutionX . toString ( ) , resolutionY . toString ( ) ,
1331
+ '-l' , 'data' , 'data.geojson' , 'output.tif'
1332
+ ] ;
1325
1333
1326
1334
const outputFilePath = await Gdal . gdal_rasterize ( dataset , options ) ;
1327
-
1328
1335
const exportedBytes = await Gdal . getFileBytes ( outputFilePath ) ;
1329
- downloadFile ( exportedBytes , `${ exportFileName } .${ exportFormat . toLowerCase ( ) } ` , 'application/octet-stream' ) ;
1336
+ downloadFile ( exportedBytes , `${ exportFileName } .tif ` , 'application/octet-stream' ) ;
1330
1337
1331
1338
Gdal . close ( dataset ) ;
1332
1339
}
1333
1340
} ) ;
1334
1341
1342
+
1335
1343
loadKeybindings ( commands , keybindings ) ;
1336
1344
}
1337
1345
0 commit comments