28
28
<script >
29
29
import { scaleBand as d3_scaleBand } from ' d3-scale' ;
30
30
import { select as d3_select } from ' d3-selection' ;
31
+ import { create as d3_create } from ' d3' ;
31
32
32
33
33
34
import CategoricalScale from ' ./../../scales/CategoricalScale.js' ;
@@ -37,9 +38,11 @@ import HistoryStack from './../../history/HistoryStack.js';
37
38
import ColorScalePicker from ' ./../modals/ColorScalePicker.vue' ;
38
39
import ColorPicker from ' ./../modals/ColorPicker.vue' ;
39
40
40
- import { COLOR_PICKER_PATH , EYE_PATH , EYE_DISABLED_PATH , PAINT_BUCKET_PATH } from ' ./../../icons.js' ;
41
+ import { COLOR_PICKER_PATH , EYE_PATH , EYE_DISABLED_PATH , PAINT_BUCKET_PATH , DOWNLOAD_PATH } from ' ./../../icons.js' ;
41
42
import { EVENT_TYPES , EVENT_SUBTYPES } from ' ../../history/base-events.js' ;
42
43
44
+ import { downloadSvg } from ' ./../../helpers.js' ;
45
+
43
46
const STYLES = Object .freeze ({ " BAR" : 1 , " DOT" : 2 , " LINE" : 3 , " SHAPE" : 4 });
44
47
45
48
let uuid = 0 ;
@@ -89,6 +92,14 @@ export default {
89
92
},
90
93
' clickHandler' : {
91
94
type: Function
95
+ },
96
+ ' showDownloadButton' : {
97
+ type: Boolean ,
98
+ default: false
99
+ },
100
+ ' downloadName' : {
101
+ type: String ,
102
+ default: ' legend'
92
103
}
93
104
},
94
105
data () {
@@ -193,7 +204,7 @@ export default {
193
204
[scaleKey]
194
205
));
195
206
},
196
- drawLegend () {
207
+ drawLegend (d3Node ) {
197
208
const vm = this ;
198
209
vm .removeLegend ();
199
210
@@ -204,43 +215,38 @@ export default {
204
215
const textOffset = 30 ;
205
216
const marginX = 4 ;
206
217
const marginY = 2 ;
218
+ const buttonWidth = 16 ;
207
219
208
220
vm .lHeight = vm .lItemHeight * varScale .domain .length + titleHeight;
209
221
210
222
/*
211
223
* Create the SVG elements
212
224
*/
213
-
214
- const container = d3_select (vm .legendSelector )
215
- .append (" svg" )
216
- .attr (" width" , vm .computedWidth )
217
- .attr (" height" , vm .computedHeight );
225
+ let container;
226
+ if (d3Node) {
227
+ container = d3Node;
228
+ } else {
229
+ container = d3_select (vm .legendSelector )
230
+ .append (" svg" )
231
+ .attr (" width" , vm .computedWidth )
232
+ .attr (" height" , vm .computedHeight );
233
+ }
218
234
219
235
const legend = container .append (" g" )
220
236
.attr (" class" , " legend" )
221
237
.attr (" transform" , " translate(" + vm .computedTranslateX + " ," + vm .computedTranslateY + " )" );
222
-
223
-
224
238
225
239
const title = legend .append (" g" )
226
240
.attr (" width" , vm .lWidth );
227
241
228
242
const titleText = title .append (" text" )
229
243
.style (" text-anchor" , " start" )
244
+ .style (" font-family" , " Avenir" )
230
245
.text (varScale .name );
231
246
const titleTextBbox = titleText .node ().getBBox ();
232
247
titleText .attr (" transform" , " translate(" + 0 + " ," + titleTextBbox .height + " )" );
233
248
234
- title .append (" path" )
235
- .attr (" d" , PAINT_BUCKET_PATH )
236
- .attr (" width" , 20 )
237
- .attr (" height" , 20 )
238
- .attr (" transform" , " translate(" + (vm .lWidth - 1.5 * marginX) + " ," + (titleTextBbox .height / 2 ) + " ) scale(-0.7 0.7)" )
239
- .style (" cursor" , " pointer" )
240
- .attr (" fill" , " silver" )
241
- .on (" click" , () => {
242
- vm .showColorScalePicker = true ;
243
- });
249
+
244
250
245
251
const legendInner = legend .append (" g" )
246
252
.attr (" class" , " legend-inner" );
@@ -254,7 +260,8 @@ export default {
254
260
.attr (" width" , vm .lWidth )
255
261
.attr (" height" , " 1px" )
256
262
.attr (" fill" , " black" )
257
- .attr (" fill-opacity" , 0 );
263
+ .attr (" fill-opacity" , 0 )
264
+ .style (" user-select" , " none" );
258
265
259
266
highlight .append (" rect" )
260
267
.attr (" x" , 0 )
@@ -263,7 +270,8 @@ export default {
263
270
.attr (" height" , 1 )
264
271
.attr (" fill" , " black" )
265
272
.attr (" fill-opacity" , 0 )
266
- .attr (" transform" , " translate(0," + (vm .lItemHeight ) + " )" );
273
+ .attr (" transform" , " translate(0," + (vm .lItemHeight ) + " )" )
274
+ .style (" user-select" , " none" );
267
275
268
276
269
277
@@ -299,6 +307,7 @@ export default {
299
307
300
308
const itemText = items .append (" text" )
301
309
.style (" text-anchor" , " start" )
310
+ .style (" font-family" , " Avenir" )
302
311
.attr (" y" , scale .bandwidth () - 5 )
303
312
.attr (" x" , (textOffset + marginX) + " px" )
304
313
.style (" font-size" , " 13px" )
@@ -323,10 +332,49 @@ export default {
323
332
.attr (" fill" , (d ) => varScale .color (d))
324
333
.attr (" fill-opacity" , (d ) => varScale .domainFiltered .includes (d) ? 1 : 0 );
325
334
}
326
-
335
+
336
+ if (d3Node) {
337
+ return ; /* SVG passed in to function, so not interactive */
338
+ }
339
+
327
340
328
341
// Action buttons
329
- const buttonWidth = 16 ;
342
+
343
+ const colorScaleButtonG = title
344
+ .append (" g" )
345
+ .attr (" width" , 20 )
346
+ .attr (" height" , 20 )
347
+ .attr (" transform" , " translate(" + (vm .lWidth - 1.5 * marginX) + " ," + (titleTextBbox .height / 2 ) + " ) scale(-0.7 0.7)" )
348
+ .style (" cursor" , " pointer" )
349
+ .on (" click" , () => {
350
+ vm .showColorScalePicker = true ;
351
+ });
352
+ colorScaleButtonG .append (" rect" )
353
+ .attr (" width" , 20 )
354
+ .attr (" height" , 20 )
355
+ .attr (" fill" , " transparent" );
356
+ colorScaleButtonG .append (" path" )
357
+ .attr (" d" , PAINT_BUCKET_PATH )
358
+ .attr (" fill" , " silver" );
359
+
360
+ if (vm .showDownloadButton ) {
361
+ const downloadButtonG = title
362
+ .append (" g" )
363
+ .attr (" width" , 20 )
364
+ .attr (" height" , 20 )
365
+ .attr (" transform" , " translate(" + (vm .lWidth - 2 * (buttonWidth) + marginX/ 2 ) + " ," + (titleTextBbox .height / 2 ) + " ) scale(-0.7 0.7)" )
366
+ .style (" cursor" , " pointer" )
367
+ .on (" click" , vm .downloadViaButton );
368
+
369
+ downloadButtonG .append (" rect" )
370
+ .attr (" width" , 20 )
371
+ .attr (" height" , 20 )
372
+ .attr (" fill" , " transparent" );
373
+ downloadButtonG .append (" path" )
374
+ .attr (" d" , DOWNLOAD_PATH )
375
+ .attr (" fill" , " silver" );
376
+
377
+ }
330
378
331
379
const filterButtons = items .append (" g" )
332
380
.attr (" transform" , " translate(" + (vm .lWidth - 2 * (buttonWidth + 2 * marginX)) + " ,0)" )
@@ -409,6 +457,21 @@ export default {
409
457
.attr (" transform" , " scale(0.7 0.7)" )
410
458
.attr (" fill" , " silver" );
411
459
460
+ },
461
+ download () {
462
+ const svg = d3_create (" svg" )
463
+ .attr (" width" , this .computedWidth )
464
+ .attr (" height" , this .computedHeight )
465
+ .attr (" viewBox" , ` 0 0 ${ this .computedWidth } ${ this .computedHeight } ` );
466
+
467
+ this .drawLegend (svg);
468
+ this .drawLegend ();
469
+
470
+ return svg;
471
+ },
472
+ downloadViaButton () {
473
+ const svg = this .download ();
474
+ downloadSvg (svg, this .downloadName );
412
475
}
413
476
}
414
477
}
0 commit comments