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.
JavaScript
The JavaScript is the same for all use cases. Some tweaking can be done to the source code as explained later on
JavaScript
/* 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> <SpotfireControl id="spotfire link 2" /> <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"/> */ function iconMenu(){ var spaceBetweenLayers = 100; var itemsPerLayer = 1; var startingAngle = 0 var endingAngle= 120 var canvasPos = document.querySelector('[class^="sfx_canvas"]').getBoundingClientRect() ; var iconMenu = document.querySelector(".iconMenu"); if (iconMenu) { var iconMenuStyle = iconMenu.style; var backgroundColor= iconMenuStyle.background || "#fff"; var foregroundColor = iconMenuStyle.color || "navy"; var fontSize = iconMenuStyle.fontSize || "20px"; var 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:0; } .iconMenu a { font-size: ${fontSize} !important; 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> `; iconMenu.insertAdjacentHTML("afterend",style); //script var timeOutPID = 0; var menuLinks = document.querySelectorAll(".iconMenu a") if (menuLinks) { var boxShadow = document.querySelector(".iconMenu a").style.boxShadow; function hover() { let gap = spaceBetweenLayers; let elements = document.querySelectorAll(".iconMenu a"); if (elements) { 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"); if (elements) { 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 var icons = document.querySelector(".icons").classList.value.split(","); icons[0] = icons[0].replace("icons ",""); menuLinks.forEach((e,i)=>{ e.className = icons[i]; e.title = e.innerText; e.innerText = ""; }); hover(); delayClose(); }; }; } iconMenu();
Example 1: Simple home button example
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>Replace this entire <a> tag with a "Spotfire Control Action Control link" </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"/>
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
Remember to replace the entire <a> tag with Spotfifre action control of type "link"
<div class="iconMenu" style="background:yellow;color:blue;font-size:20px;"> <SpotfireControl id="actual action control link 1" /> <a>Action Control Link 2</a> <a>Action Control Link 3</a> <a>Action Control Link 4</a> <a>Action Control Link 5</a> <SpotfireControl id="action control link 6" /> <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
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 0 deg endingAngle= 180 //◄ vertical at 180 deg
Example 4: Circular Layouts
Half Circle
//script parameters spaceBetweenLayers = 50; itemsPerLayer = 10; startingAngle = 5 endingAngle= 187 : : <style> .iconMenu { position: fixed; top:${canvasPos.y+15}px; left:50% /*center the icon*/ z-index:1; height:0px; } : :
Full Circle
//script parameters spaceBetweenLayers = 40; itemsPerLayer = 10; //◄ set to 1 for horizontal menu startingAngle = 0 endingAngle= 360 : : <style> .iconMenu { position: fixed; top:50%; /*vertically centered*/ left:50%; /*center horizontally the icon*/ z-index:1; height:0px; } : :
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
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
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
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;
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
Checkout the JavaScript Checkbox List for Spotfire to see an example
Back to the JavaScript Component Hub for Spotfire
Disclaimer
This method makes assumptions about the inner workings of Spotfire version 12.0.0 LTS Any analyses created using this hack may cause instability and performance issues and are likely to break when Spotfire is upgraded or hotfixed in the future. Any issues resulting from applying this hack are not covered by Spotfire maintenance agreements and Support will not assist in troubleshooting problems with analysis files where this approach is used.
Recommended Comments
There are no comments to display.