Jump to content

Javascripting Buttons to Navigate Pages


apreble
Go to solution Solved by barchiel33,

Recommended Posts

Hello, 

I'm using information from the link I've attached... I really like the vertical menu option for ability for users to navigate to a page. However, when I apply my Spotfire action control links, the button labels will change. For example the "Action Control Link 1" now corresponds with the 2nd icon when the pop up happens. There seems to be no order here after the action control links are applied. How can this be fixed?

Here's the HTML from the link with one of my action controls applied-

<div class="iconMenu" style="background:yellow;color:blue;font-size:50px;">
 <a><SpotfireControl id="65b85707c5bd4da3843ca67d153e45e4" /></a> //This one doesn't correspond to the button labeled "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>
 <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"/>

Here's a visual of what happens when I apply my action control link (See how the link corresponds to button #2 and it should correspond to button #1)-

image.thumb.png.655c4678a10cf0b599020d0ce1017672.png

Here's the Javascript from the link-

spaceBetweenLayers = 40;
itemsPerLayer = 1; 
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();

 

Link to comment
Share on other sites

  • Solution

Hmm, so it looks like the article's script doesn't take into account having nested links (ie. <a><SpotfireControls id=blahblahblah></a> where the Spotfire control is a Link action control). So what's happening is that it's moving the link action control up out of the parent <a>.  So this HTML:

<div class="iconMenu" style="background:yellow;color:blue;font-size:50px;">
    <a><SpotfireControl id="7f4b2b132dc244a8b29b58297d16a13f" /></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"/>

Becomes this:

<div class="iconMenu" style="background:yellow;color:blue;font-size:50px;">
    <a class="fa-solid fa-1"></a>
    <a id="7f4b2b132dc244a8b29b58297d16a13f" href="javascript:void(0);" class="fa-solid fa-2" title="Home"> //This is the Spotfire Link action control.
    <a class="fa-solid fa-3">Action Control Link 2</a>
    <a class="fa-solid fa-4">Action Control Link 3</a>
    <a class="fa-solid fa-5">Action Control Link 4</a>
    <a class="fa-solid fa-6">Action Control Link 5</a>
    <a class="fa-solid fa-7">Action Control Link 6</a>
    <a class="fa-solid fa-8">Action Control Link 7</a>
    <a class="fa-solid fa-9">Action Control Link 8</a>
    <a class="fa-solid fa-0">Action Control Link 9</a>
    <a class="fa-solid fa-bars">Action Control Link 10</a>
    <a class="undefined">Menu</a> //Since the Spotfire control 'stole' one of the icons, this becomes undefined, since there are 12 elements and only 11 icon classes.
</div>

The easiest solution is to remove the container <a> around the Spotfire Link action control. However, there is some base styling applied to Link action controls, and, unfortunately, the styles are inline instead of in a style sheet. So you'd need to use !important to override them. The most notable is the font size, but there are a few others. A potential alternative would be to extract the action controls to their own hidden container and just use the icons as facades, but that would take a good bit more work.

I went through and rewrote the code to implement the overriding the font-size but also to implement some general best practices (such as using var when setting variables, checking that elements exist, etc.):

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();
    };
};

The HTML for this method would look like this:

<div class="iconMenu" style="background:yellow;color:blue;font-size:50px;">
	<SpotfireControl id="7f4b2b132dc244a8b29b58297d16a13f" />
	<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"/>

You'd just replace each <a>Action Control Link #</a> with a Spotfire Link action control with the desired title.

Link to comment
Share on other sites

@apreble That's great to hear! I'm glad I was able to help :) The Spotfire articles section honestly needs some coding guidelines/standards, alot of the code there is either 1) outdated, 2) messily written, 3) contains syntax mistakes, or 4) some combination of the previous three, especially when it comes to the Javascripting/HTML. I hope they have plans to implement some kind of code review for articles. I know alot of people come to the articles thinking they can copy and paste the code with a few small tweaks, but they're more like case studies that tell you potential things you can do and give you an idea how to implement them.

  • Like 1
Link to comment
Share on other sites

Hello @barchiel33 We sincerely appreciate your thoughtful feedback on the Spotfire articles. Your points about code quality are well-received. We're actively working on improvements, including a possible code review process. Our articles aim to inspire, and we'll strive to communicate this more clearly. Thank you again for your valuable insights and we hope the articles are as valuable as your feedback. Thanks again.

I made minor modification to the main article so it is clear to replace the entire <a> placeholder with the link action control. The font size and other attributes can be overridden directly on the markup itself:

<div class="iconMenu" style="background:yellow;color:blue;font-size:50px;">
Edited by Jose Leviaguirre
  • Like 1
Link to comment
Share on other sites

Hello @Jose Leviaguirre! Thank you for the response, I appreciate the information. 

Also thank you for making the modification to the article! However, the font size and other attributes can't be overridden using the snippet you show in your comment (at least it doesn't work for me). Applying the style to the parent element only affects elements that don't have their own styles applied. When you insert a Spotfire action control, the Spotfire javascripting seems to apply it's own styles directly to that control, overriding the parent element's styling. I suppose you could individually style each action control using the "Format..." interface, but that's fairly limited in what you're able to do and would require doing it for each control. I've attached a screenshot showing how, even with the styling snippet, the action control's icon's text is a different size.

Capture.PNG

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...