Jump to content
  • JavaScript Icon Menu for Spotfire


    Convert Action Control Links into icons to create a popup icon menu

    Introduction

    The JavaScript Icon Menu for Spotfire enhances page navigation for your analysis dashboard making it easy to maintain. This script converts the Action Control Links into clickable icons. It saves precious space on your dashboard and helps with navigation or to perform certain tasks available through Spotfire Action Link Controls such as running an Iron Python Script, Applying a bookmark, running a data function, exporting to PDF or anything else Action Controls have to offer .

     

    The way it works is that a JavaScript parses the markup and applies the comma separated list of icons from the image class element. The name of the link becomes the tooltip of the button when hovering over it. 

     

    menuicon.gif.227dd24e0f8ed1c2f7ed8f583727b3b1.gifmulti-menuicon-fullcircle.gif.7bda129b9876c28709b1008173469718.gifmulti-menuicon-horizontal.gif.63a7ab932ae004c4336f7ca2ee15754a.gif

     

    JavaScript

    The JavaScript is the same for all use cases. Some tweaking can be done to the source code as explained later on

    /*
    Converts spotfire links to an iconic menu. Supports font awesome and simple-line-icons
    usage:
    
    <div class="iconMenu" style="background:yellow;color:blue;font-size:50px">
       <a>spotfire link 1</a>
       <a>spotfire link 2</a>
       <a>spotfire link 3</a>
       <a>main menu</a>
    </div>
    <img class="icons icon-user,icon-fire,fa-solid fa-arrow-trend-up,icon-menu"/>
    
    */
    
    //script parameters
    spaceBetweenLayers = 40;
    itemsPerLayer = 5; 
    startingAngle = 0
    endingAngle= 120
    
    canvasPos = document.querySelector('[class^="sfx_canvas"]').getBoundingClientRect() ;
    iconMenu = document.querySelector(".iconMenu").style
    backgroundColor= iconMenu.background || "#fff"; 
    foregroundColor = iconMenu.color || "navy";
    fontSize = iconMenu.fontSize || "20px";
    
    
    
    style = `
    <link href='https://cdnjs.cloudflare.com/ajax/libs/simple-line-icons/2.4.1/css/simple-line-icons.css' rel='stylesheet' ></link>  
    <link href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css' rel='stylesheet'/>  
    <style>
    .iconMenu {
      position: fixed;
      top:${canvasPos.y+15}px;
      left:${canvasPos.x+15}px;
      z-index:1;
      height:0px;
    }
    
    .iconMenu a {
        position: fixed;
        display: flex;
        justify-content: center;
        align-items: center;
        text-decoration:none !important;
        cursor: pointer;
     
        /*animation*/
        transition-timing-function: cubic-bezier(0,0,0,1);
        transition-duration: .25s; 
    
        /*size and shape*/
        width: ${fontSize}; 
        height: ${fontSize};
        padding: calc(${fontSize}/3);
        border-radius: 100%;
    
        /*colors*/
        color:#747880 !important; 
        background-color: ${backgroundColor};
        box-shadow: 0 4px 18px #0000001a,0 4px 5px #0000001a;
    }
    
    .iconMenu a:last-child{
        opacity:100%
    }
    
    .iconMenu a:hover{
        color: #8498fa !important; 
    }
    </style>` 
    
    document.querySelector(".iconMenu").insertAdjacentHTML("afterend",style);
    
    //script
    timeOutPID=0;
    boxShadow = document.querySelector(".iconMenu a").style.boxShadow;
    
    function hover() {
      let gap = spaceBetweenLayers;
      let elements = document.querySelectorAll(".iconMenu a");
      elements.forEach((e, i) => {
        if(i==elements.length-1) return;
        let angle = (endingAngle / itemsPerLayer) * (i%itemsPerLayer) + startingAngle;
        i%itemsPerLayer||(gap+=spaceBetweenLayers)
        e.style.transform = `rotate(${angle}deg) translate(${gap}px) rotate(-${angle}deg)`;
        e.style.boxShadow=boxShadow;
        e.onmouseover = resetDelayClose;
        e.onmouseout = delayClose;
      });
      
     resetDelayClose();
    }
    
    function close(){
      let elements = document.querySelectorAll(".iconMenu a");
      elements.forEach((e, i) => {
        if (i==elements.length-1) return;
        e.style.transform = `translate(0px)`;
        e.style.boxShadow="unset";
      }); 
    } 
    
    function delayClose(){
      timeOutPID = setTimeout(close,1234)
    }
    
    function resetDelayClose(){
      timeOutPID && clearTimeout(timeOutPID);
    }
    
    document.querySelector(".iconMenu a:last-child").onmouseover = hover;
    document.querySelector(".iconMenu a:last-child").onmouseout = delayClose; 
    
    //setup icons on links
    icons = document.querySelector(".icons").classList.value.split(",")
    icons[0] = icons[0].replace("icons ",""); 
    
    document.querySelectorAll(".iconMenu a").forEach((e,i)=>{
      e.className = icons[i];
      e.title = e.innerText;
      e.innerText="" 
    })  
    
    hover();
    delayClose();
     

     

    Example 1: Simple home button example

     home.png.5be77018a14bb16f91757a317db74d3e.png

    The most basic form for this to work is to have only one action control link. I often have this on every page to go back to a landing page where I can organize the contents of my dashboard. The img element contains the icon to be used from Font Awesome. You can also use simple line icons or a combination of both. Simply put the class name after the <img class="icons your icon name"/>

    html

    <div class="iconMenu" >
       <a> SpotfireControl Action Control link goes here </a>
    </div>
    <img class="icons fa-solid fa-house"/>
     

    Example 2: Multiple links under one button

    You can add as many icons as you want. They will be displayed in the order they are placed. The last icon is always the top-most one when the menu is collapsed. The rest of the buttons are displayed when the mouse is put over this link. By default, the links are displayed radially. The number of icons must match the number of links <img class="icons first icon, second icon,....,last icon"/> 

    multi-menuicon.gif.f40b1167d98538d11e95775d4e4340f4.gif

    The default settings are 5 items per circle. This can be change from the script parameter section.

     

    //script parameters
    spaceBetweenLayers = 40;
    itemsPerLayer = 5; //◄ set to 1 for horizontal menu
    startingAngle = 0
    endingAngle= 120
     

    html

    <div class="iconMenu" style="background:yellow;color:blue;font-size:50px;">
     <a>Action Control Link 1</a>
     <a>Action Control Link 2</a>
     <a>Action Control Link 3</a>
     <a>Action Control Link 4</a>
     <a>Action Control Link 5</a>
     <a>Action Control Link 6</a>
     <a>Action Control Link 7</a>
     <a>Action Control Link 8</a>
     <a>Action Control Link 9</a>
     <a>Action Control Link 10</a>
     <a>Menu</a>
    </div>
    
    <img class="icons fa-solid fa-1, fa-solid fa-2,fa-solid fa-3,fa-solid fa-4,fa-solid fa-5,fa-solid fa-6,fa-solid fa-7,fa-solid fa-8,fa-solid fa-9, fa-solid fa-0, fa-solid fa-bars"/>
      

    Example 3: Horizontal, Vertical layout

    multi-menuicon-horizontal.gif.f7111533fdcc4a39478b25a733ff3491.gif

    Horizontal layout

    Change the itemsPerLayer = 1 from the script parameter section

    //script parameters
    spaceBetweenLayers = 40;
    itemsPerLayer = 1; //◄ set to 1 for horizontal menu
    startingAngle = 0
    endingAngle= 180
     

    Vertical layout

    //script parameters
    spaceBetweenLayers = 40;
    itemsPerLayer = 1; 
    startingAngle = 90 //◄ set to 90 for vertical menu
    endingAngle= 180
     

    Vertical and horizontal layout

     

    //script parameters
    spaceBetweenLayers = 40;
    itemsPerLayer = 2; //◄ set to 2 for vertical and horizontal menu
    startingAngle = 0  //◄ horizontal at 9 deg
    endingAngle= 180   //◄ vertical at 180 deg
     

    Example 4: Circular Layouts

    Half Circle

    semicircle.png.d435cf81cd70c6672bc3d0d931053800.png

    //script parameters
    spaceBetweenLayers = 50;
    itemsPerLayer = 10; 
    startingAngle = 5
    endingAngle= 187
     

    Full Circle

    fullcircle.png.0f11c5265acb19cd9e7e64fb1f16dd96.png

    //script parameters
    spaceBetweenLayers = 40;
    itemsPerLayer = 10; //◄ set to 1 for horizontal menu
    startingAngle = 0
    endingAngle= 360
     

    Positioning 

    Here are some examples on how to position the menu on different places of the screen. The canvasPos variable is looking at the first visual of the canvas and taking that as a point of reference. Without this, it might not look consistent on the webPlayer or the client. There is no need to change this as it is just for reference.

     canvasPos = document.querySelector('[class^="sfx_canvas"]').getBoundingClientRect()
     

    The default position is top left and this is defined on the .iconMenu style class found on the script.

    .iconMenu {
      position: fixed;
      top:${canvasPos.y+15}px;
      left:${canvasPos.x+15}px;
      z-index:1;
    }
     

    To override the top and left, you can use the viewport height and width unit of measure or any other units values as described here . You can either replace the top and left values or override them by adding them at the end. Here are some examples:

     

    Center of the screen

    To center the menu icon at the center of the screen, override the top and left style attributes by adding at the end of the .iconMenu css rule these values:

    .iconMenu {
      position: fixed;
      top:${canvasPos.y+15}px;
      left:${canvasPos.x+15}px;
      z-index:1;
      left:50vw; //◄ Overrides the horizontal reference position to 50% of the viewport width
      top:50vh;  //◄ Vertically centers the main icon
    }
     

    Top center

    .iconMenu {
      position: fixed;
      top:${canvasPos.y+15}px;
      left:${canvasPos.x+15}px;
      z-index:1;
      left:50vw; //◄ Overrides the horizontal reference position to 50% of the viewport width
    }
     

    Bottom left

    .iconMenu {
      position: fixed;
      top:${canvasPos.y+15}px;
      left:${canvasPos.x+15}px;
      z-index:1;
      top:90vh; 
    }
     

    Inline

    To place the icon menu within some text, remove the position or change it to inherit or static and change the display for the .iconMenu a class to inline

    .iconMenu {
      position: unset;
      top:${canvasPos.y+15}px;
      left:${canvasPos.x+15}px;
      z-index:1;
      top:90vh; 
    }
    
    .iconMenu a {
        position: fixed;
        display: inline;
        justify-content: center;
    :
    }
     

    Overriding and custom styles 

    To avoid changing the script or creating script parameters, you can override the default styles defined on the script by by adding a script or markup (if html sanitization is off). Here are some examples

    iconMenu-displlay-inline.js

    multi-menuicon-inline.gif.68c8cf99006994e883c96e84e6ea7eb7.gif

    style = `<style>
    .iconMenu {
        position: unset !important;
    }
    .iconMenu a {
        display: inline !important;
        position:absolute !important;
        z-index:1!important;
    }
    </style>`
    
    document.querySelector(".iconMenu").insertAdjacentHTML("afterend",style)
     

    iconMenu-blue-sphere.css

    sphere.png.1e0584d998ddfbb6028db43af939f3ec.png

    style = `<style>
    .iconMenu a{
        background: radial-gradient(circle at 65% 15%, white 1px, aqua 3%, darkblue 60%, aqua 100%);       
       color:white; 
       padding:15px;
    }
    </style>`
    document.querySelector(".iconMenu").inertAdjacentHTML("afterend",style)
     

    iconMenu-inset.css

     

    inset.png.93b7c94fef90245a0e8a0f1c41735c0f.png

     

    style = `<style>
    .iconMenu a {
       display:inline;
       position:absolute;
       box-shadow: -3px -3px 3px white inset , 3px 3px 3px  grey inset;
       background:white;
    }
    </style>`
    document.querySelector(".iconMenu").inertAdjacentHTML("afterend",style)
     

    Changing the style form markup

    Another way to change simple things, such as background color and font size is by changing the style on the iconMenu container element  by changing the css defined on the style variable of the script. To increase the font size, just add a style attribute to the main iconMenu div tag of the html markup. Not all rules work from the markup, so you might need to tweak the script directly;

    customiconmenu.png.e55365af0d0400cfa0011b7c85786280.png

    html

    <div class="iconMenu" style="background:yellow;color:blue;font-size:50px;">
       <a>spotfire link 1</a>
       <a>spotfire link 2</a>
       <a>spotfire link 3</a>
       <a>main menu</a>
    </div>
    <img class="icons icon-user,icon-fire,fa-solid fa-arrow-trend-up,icon-menu"/>
     

    Working with Popups

    checboxListpopupiconmenu.gif.2a37b6fa9efe8c4f113acf3321432a54.gif

     

    Checkout the JavaScript Checkbox List for Spotfire to see an example

     

     

    Back to the JavaScript Component Hub for Spotfire


    User Feedback

    Recommended Comments

    There are no comments to display.


×
×
  • Create New...