2828<script >
2929import { scaleBand as d3_scaleBand } from ' d3-scale' ;
3030import { select as d3_select } from ' d3-selection' ;
31+ import { create as d3_create } from ' d3' ;
3132
3233
3334import CategoricalScale from ' ./../../scales/CategoricalScale.js' ;
@@ -37,9 +38,11 @@ import HistoryStack from './../../history/HistoryStack.js';
3738import ColorScalePicker from ' ./../modals/ColorScalePicker.vue' ;
3839import ColorPicker from ' ./../modals/ColorPicker.vue' ;
3940
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' ;
4142import { EVENT_TYPES , EVENT_SUBTYPES } from ' ../../history/base-events.js' ;
4243
44+ import { downloadSvg } from ' ./../../helpers.js' ;
45+
4346const STYLES = Object .freeze ({ " BAR" : 1 , " DOT" : 2 , " LINE" : 3 , " SHAPE" : 4 });
4447
4548let uuid = 0 ;
@@ -89,6 +92,14 @@ export default {
8992 },
9093 ' clickHandler' : {
9194 type: Function
95+ },
96+ ' showDownloadButton' : {
97+ type: Boolean ,
98+ default: false
99+ },
100+ ' downloadName' : {
101+ type: String ,
102+ default: ' legend'
92103 }
93104 },
94105 data () {
@@ -193,7 +204,7 @@ export default {
193204 [scaleKey]
194205 ));
195206 },
196- drawLegend () {
207+ drawLegend (d3Node ) {
197208 const vm = this ;
198209 vm .removeLegend ();
199210
@@ -204,43 +215,38 @@ export default {
204215 const textOffset = 30 ;
205216 const marginX = 4 ;
206217 const marginY = 2 ;
218+ const buttonWidth = 16 ;
207219
208220 vm .lHeight = vm .lItemHeight * varScale .domain .length + titleHeight;
209221
210222 /*
211223 * Create the SVG elements
212224 */
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+ }
218234
219235 const legend = container .append (" g" )
220236 .attr (" class" , " legend" )
221237 .attr (" transform" , " translate(" + vm .computedTranslateX + " ," + vm .computedTranslateY + " )" );
222-
223-
224238
225239 const title = legend .append (" g" )
226240 .attr (" width" , vm .lWidth );
227241
228242 const titleText = title .append (" text" )
229243 .style (" text-anchor" , " start" )
244+ .style (" font-family" , " Avenir" )
230245 .text (varScale .name );
231246 const titleTextBbox = titleText .node ().getBBox ();
232247 titleText .attr (" transform" , " translate(" + 0 + " ," + titleTextBbox .height + " )" );
233248
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+
244250
245251 const legendInner = legend .append (" g" )
246252 .attr (" class" , " legend-inner" );
@@ -254,7 +260,8 @@ export default {
254260 .attr (" width" , vm .lWidth )
255261 .attr (" height" , " 1px" )
256262 .attr (" fill" , " black" )
257- .attr (" fill-opacity" , 0 );
263+ .attr (" fill-opacity" , 0 )
264+ .style (" user-select" , " none" );
258265
259266 highlight .append (" rect" )
260267 .attr (" x" , 0 )
@@ -263,7 +270,8 @@ export default {
263270 .attr (" height" , 1 )
264271 .attr (" fill" , " black" )
265272 .attr (" fill-opacity" , 0 )
266- .attr (" transform" , " translate(0," + (vm .lItemHeight ) + " )" );
273+ .attr (" transform" , " translate(0," + (vm .lItemHeight ) + " )" )
274+ .style (" user-select" , " none" );
267275
268276
269277
@@ -299,6 +307,7 @@ export default {
299307
300308 const itemText = items .append (" text" )
301309 .style (" text-anchor" , " start" )
310+ .style (" font-family" , " Avenir" )
302311 .attr (" y" , scale .bandwidth () - 5 )
303312 .attr (" x" , (textOffset + marginX) + " px" )
304313 .style (" font-size" , " 13px" )
@@ -323,10 +332,49 @@ export default {
323332 .attr (" fill" , (d ) => varScale .color (d))
324333 .attr (" fill-opacity" , (d ) => varScale .domainFiltered .includes (d) ? 1 : 0 );
325334 }
326-
335+
336+ if (d3Node) {
337+ return ; /* SVG passed in to function, so not interactive */
338+ }
339+
327340
328341 // 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+ }
330378
331379 const filterButtons = items .append (" g" )
332380 .attr (" transform" , " translate(" + (vm .lWidth - 2 * (buttonWidth + 2 * marginX)) + " ,0)" )
@@ -409,6 +457,21 @@ export default {
409457 .attr (" transform" , " scale(0.7 0.7)" )
410458 .attr (" fill" , " silver" );
411459
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 );
412475 }
413476 }
414477}
0 commit comments