Source code for svgsGrid

"""Display and selection of a list of SVG files"""
# Author(s): Davide.De-Marchi@ec.europa.eu
# Copyright © European Union 2022-2023
# 
# Licensed under the EUPL, Version 1.2 or as soon they will be approved by 
# the European Commission subsequent versions of the EUPL (the "Licence");
# 
# You may not use this work except in compliance with the Licence.
# 
# You may obtain a copy of the Licence at:
# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12

# Unless required by applicable law or agreed to in writing, software
# distributed under the Licence is distributed on an "AS IS"
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied.
# 
# See the Licence for the specific language governing permissions and
# limitations under the Licence.
import ipyvuetify as v
import traitlets
import os
import base64


# Given a path of an SVG file, it reads the content and returns a string containing a IMG tab with the SVG embedded in base64 format
def readSVGbase64(filepath, fill=None, stroke=None):
    svgtext = ''
    with open(filepath,'r') as f:
        svgtext = f.read()
        
    if (not fill is None) and (not stroke is None):
        svgtext.replace('<svg ','<svg fill="%s" stroke="%s"'%(fill,stroke))
    elif not fill is None:
        svgtext.replace('<svg','<svg fill="%s"'%fill)
    elif not stroke is None:
        svgtext.replace('<svg','<svg stroke="%s"'%stroke)

    base64_bytes  = base64.b64encode(bytes(svgtext,'utf-8'))
    base64_string = base64_bytes.decode("ascii")
    return "data:image/svg+xml;base64, %s" % base64_string


# Given a path of an SVG file, it reads the content and returns a string containing a IMG tab with the SVG embedded in base64 format
def readSVGimg(filepath, size=100):
    imgurl = readSVGbase64(filepath)
    return '<img src="%s", style="width:%dpx; height:%dpx; display: flex; justify-content: center; align-items: center; overflow: hidden;">'%(imgurl,size,size) + '</img>'


[docs]class svgsGrid(v.VuetifyTemplate): """ Display of a list of SVG files in rows and columns, with possibility to select one of the SVGs. Parameters ---------- filepaths : list of str File paths of the SVG files to display in the grid width : str, optional Width to use for the display of the SVGs (default is '80px') height : str, optional Heigth to use for the display of the SVGs (default is '100px' to accomodate for the title of the files) cols : int, optional Horizontal column span [1,12] for each of the SVGs (default is 1, meaning 12 files are displayed in every row) color : str, optional Background color of the SVGs (default is 'white') ripple : bool, optional If True the click on the SVG files is highlighted (default is False) svgsize : int, optional Size in pixel of the square area where the SVG is displayed (default is 80) on_click : function, optional Python function to call when the user clicks on one of the SVG files. The function will receive as parameter the index of the clicked SVG. (default is None) Example ------- Creation of a grid to display and select SVG files read from a subfolder:: from vois.vuetify import svgsGrid from ipywidgets import widgets from IPython.display import display import glob output = widgets.Output() def on_click(index): with output: print(index) filepaths = sorted(glob.glob("./maki/icons/*")) svgsize = 80 height = '%dpx'%(svgsize + 30) g = svgsGrid(filepaths=filepaths, cols=1, svgsize=svgsize, height=height, ripple=True, on_click=on_click) display(g) display(output) .. figure:: figures/svgsGrid.png :scale: 100 % :alt: svgsGrid widget Example of an svgsGrid to display a list of SVG files allowing selection """ svgitems = traitlets.Any([]).tag(sync=True) # SVG files to display (array of json objects containing "title" and "svg" tags) width = traitlets.Unicode('80px').tag(sync=True) # Width of the cards height = traitlets.Unicode('100px').tag(sync=True) # Height of the cards color = traitlets.Unicode('white').tag(sync=True) # Background color cols = traitlets.Int(6).tag(sync=True) # Horizontal column span [1,12] for each of the card ripple = traitlets.Bool(False).tag(sync=True) # Ripple flag (if True the click on the card is highlighted) on_click = traitlets.Any(None).tag(sync=False) # Name of a python function to call when one of the cards is clicked (it will receive as argument the index of the clicked card) @traitlets.default('template') def _template(self): return ''' <v-container fluid style="overflow: hidden;"> <v-row dense> <v-col v-for="card,index in svgitems" :key="card.title" :cols="cols" > <v-card class="pa-0 ma-1" :width="width" :color="color" :height="height" hover :ripple="ripple" link elevation=0 @click="clicked(index)" > <div style="display: flex; justify-content: center; align-items: center; overflow: hidden;" v-html="card.svg"/> <v-card-text class="pa-0 ma-0" style="font-size: 11; text-align: center;" v-html="card.title"/> </v-card> </v-col> </v-row> </v-container> ''' def __init__(self, *args, filepaths=[], width='80px', height='100px', color='white', cols=1, ripple=False, svgsize=80, on_click=None, **kwargs): self.svgitems = [{"svg": readSVGimg(x,svgsize), "title": os.path.basename(x).replace(".svg","").replace("_"," ")} for x in filepaths] self.width = width self.height = height self.color = color self.cols = cols self.ripple = ripple self.on_click = on_click super().__init__(*args, **kwargs) # Manage "click" event def vue_clicked(self, data): if not self.on_click is None: self.on_click(data)