Jump to content
  • Landing page templates for TIBCO Spotfire

    Introduction

    The Landing Pages for  Spotfire are a set of templates to enhance the look and feel of existing dashboards. A landing page is useful to organize different Spotfire Pages.

     

    The purpose of this article is to provide easy to use scripts and templates to create landing pages in no time. Some Templates does not require any JavaScript. However, when HTML Sanitation is enabled you need to use JavaScript to add those 'unsupported' tags. In any case, it is always a good practice to use script keeping in mind that the dashboard should not be affected or crippled if the script fails to run.

     

    For simplicity and efficiency, I will try to get straight to the point without further explanation. If questions arise, feel free to comment.

    Template 1

    This simple template requires minimal scripting. The script is responsible to add the font-awesome library for the icons to show and to add additional layout options. To add more items, just duplicate any of the  <div class="grid"> . The colors, fonts and layout is defined in the embedded style within the script.

    template1.png.3554e227671d414721278a27eac969b3.png

    html

    <div id="css"></div>
    
    <div style="font-size:20px;margin: 0% 20%;">
    
    <div class="container">
       <div class="grid">
          <div class="icon"><i class="fa fa-3x fa-solid fa-chart-line"></i></div>
          <div class="desc">
             <h2>Stock screener and company analysis</h2>
             <p>
                Tool that helps investors filter stocks based on specific criteria and provides insights into the financial health of a company
             </p>
          </div>
       </div>
    
       <div class="grid">
          <div class="icon"><i class="fa fa-3x fa-solid fa-location-dot"></i></div>
          <div class="desc">
             <h2>Revenue by country</h2>
             <p>
                The revenue dashboard by country provides a <b>comprehensive</b> view of sales data for Africa, Europe, Asia, North America, and the rest of the world. It allows users to choose a specific region or see the entire world, making it easy to monitor revenue performance and identify potential growth opportunities.
             </p>
          </div>
       </div>
    
       <div class="grid">
          <div class="icon">
             <i class="fa fa-3x fa-solid fa-sitemap"></i>
          </div>
          <div class="desc">
             <h2>Sector and industry breakdown</h2>
             <p>
                A treemap visualization that enables drill-down analysis of stock prices by sector and industry. Users can select a sector and industry to drill down into specific stocks, allowing for deeper analysis and identification of investment opportunities.
             </p>
          </div>
       </div>
    
       <div class="grid">
          <div class="icon"><i class="fa fa-3x fa-solid fa-circle-nodes"></i></div>
          <div class="desc">
             <h2>K-means clustering</h2>
             <p>
                Analyze stock data by market capitalization and price-to-earnings (P/E) ratios. Filter stocks by market cap size and high or low P/E ratios.<br/><br/>Group the stocks into clusters based on their market cap and P/E ratio to identify patterns and similarities in the data.
             </p>
          </div>
       </div>
    </div>
     

     

    JavaScript

    css =  `
    
    <link rel="stylesheet" href=https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw==' crossorigin="anonymous" referrerpolicy="no-referrer" />
    
    <style>
    @import 'https://fonts.googleapis.com/css?family=Lato:400,700'
    
    #landingPage {
      background-color: #dfe9ff;
      font-family: "Lato", sans-serif;
    
    }
    
    .grid {
        display: flex;
        align-items: center;
        padding: 8px;
        margin: 10px;
    }
    
    
    .container .icon {
      display: flex;
      align-items: center;
      justify-content: center;
      height: 125px;
      width: 20vw;
      color: darkblue;
    }
    
    @media (max-width: 550px) {
      .container .icon {
        display: none;
      }
    }
    
    .container .desc {
        display: flex;
        flex-direction: column;
        width: 65vw;
    }
    
    @media (max-width: 550px) {
      .container .desc {
        width: 100%;
        text-align: center;
        padding: 0;
        height: 150px;
      }
    }
    
    @media (max-width: 650px) {
      .container {
        margin-top: 0;
      }
    }
    
    </style>`
    
    document.getElementById("css").innerHTML = css
     

    Template 2

    This other template is simpler to maintain as the html is straight forward. The JavaScript is responsible to convert the entire card clickable and parse the html markup to create all the elements layout and some formatting.

     

    template2.thumb.png.1eac95e04952adfd9a63249fe8fccd7a.png

    Adding more cards

    To add more cards, just duplicate the card markup  and it's contents   <div class="landing-page-card">.

    Changing the colors, background and font-size

    The colors, fonts and other styles can be done directly on the  <div class="landing-page-card" style="background:beige"> or the main <div id="landing-page" style="background:#dfe9ff;color:green;font-size:24px"> container. For additional tweaking, edit the <style> tag contentes on the script.

    Icons

    The icons for each card are set by the comma separated set of icons for each card on the   <img class="landing-page-card-icons fa-solid fa-chart-line,fa-solid fa-location-dot,fa-solid fa-sitemap,fa-solid fa-circle-nodes"/>

    HTML

    <div id="landing-page" style="background:#dfe9ff;color:green;font-size:24px">
     
     <div id="landing-page-banner-text">
       <h1>Analyzing Stock Performance</h1>
       <p>Interactive Application with <b>different visual tools</b> to enable investors to make <b>data-driven investment decisions</b> by analyzing stock. Data screening and company analysis to check revenue by country and options to analyze further via sector and industry breakdown and other analysis
       </p>
       <div class="banner-button"><a>Get Started</a></div>
     </div>
     
     <img id="landing-page-banner-image" />;
      
     <div class="landing-page-card" >
       <a href="#">Stock screener and company analysis</a> 
       Tool that helps investors filter stocks based on specific criteria and provides insights into the financial health of a company
     </div>
     
     <div class="landing-page-card">
       <a href="#">Revenue By Country</a> 
       The revenue dashboard by country provides a <b>comprehensive</b> view of sales data for Africa, Europe, Asia, North America, and the rest of the world. It allows users to choose a specific region or see the entire world, making it easy to monitor revenue performance and identify potential growth opportunities.    
     </div>
     
     <div class="landing-page-card">
       <a href="#">Sector and industry breakdown</a> 
       <p>A treemap visualization that enables drill-down analysis of stock prices by sector and industry. Users can select a sector and industry to drill down into specific stocks, allowing for deeper analysis and identification of investment opportunities.
       </p>
     </div>
     
     <div class="landing-page-card">
       <a href="#">K-means clustering</a>
       <p>Analyze stock data by market capitalization and price-to-earnings (P/E) ratios. Filter stocks by market cap size and high or low P/E ratios.<br/><br/>Group the stocks into clusters based on their market cap and P/E ratio to identify patterns and similarities in the data <a>another link</a>
       </p>
     </div>
     
     <span class="landing-page-card-icons fa-solid fa-chart-line,fa-solid fa-location-dot,fa-solid fa-sitemap,fa-solid fa-circle-nodes"></span>
    </div> 
     

    JavaScript

    (() => { //return
    	//script Params
    	landingPageId = "landing-page";
    	landingPageImage = 'https://preview.ibb.co/bMi5Y6/banner_img.png';
    	
    	 
    	//main element
    	landingPageDiv = document.getElementById(landingPageId);
    	 
    	//banner elements
    	landingPageBannerId= "#"+landingPageId+"-banner-"
    	landingPageTextDiv = document.querySelector(landingPageBannerId+"text");
    
    	//banner image
    	landingPageIamgeDiv = document.querySelector(landingPageBannerId+"image");
    	//landingPageIamgeDiv.src = landingPageImage
    
    	 
    	//card elements 
    	landingPageCardLinks = [...document.querySelectorAll(".landing-page-card > a")];
    	landingPageCardLinks.forEach(a=>a.remove)
    	 
    	landingPageCardContents = [...document.querySelectorAll(".landing-page-card")]
    	 
    	//icons
    	landingPageCardIcons = document.querySelector(".landing-page-card-icons").classList.value.split(",")
    	landingPageCardIcons[0] = landingPageCardIcons[0].replace("landing-page-card-icons ","");
    	 
    	 
    	template=`
    	<link rel="stylesheet" href=https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
    	 
    	  <div class="banner">
    	    <div class="banner-text"></div>
    	    <img class="banner-image" />
    	  </div>
    	  
    	<div class="cards"></div>
    	` 
    	 
    	 
    	//by now we "cut" all elements from main container, so we replace with template
    	landingPageDiv.innerHTML = template
    	 
    	//start 'pasting' elements
    	//banner text
    	templateBannerText = document.querySelector("#"+landingPageId+" .banner .banner-text")
    	templateBannerText.append(...landingPageTextDiv.childNodes);
    	 
    	//banner image
    	templateBannerImage = document.querySelector("#"+landingPageId+" .banner .banner-image")
    	templateBannerImage.src = landingPageImage
    	 
    	 
    	//cards
    	landingPageCardLinks.forEach((a,j)=>{
    	   div = document.createElement("div");
    	   //Object.assign(a.style,landingPageCardContents[j].style)
    	   a.className = "card";
    	   a.style.textDecoration = "none";
    
    	   i = document.createElement("i");
    	   i.className = landingPageCardIcons[j] + " fa-xl";
    	   i.style.color = "#9b3323";
    
    	   h3 = document.createElement("h3");
    	   h3.className = "card-title";
    	   h3.innerText = a.innerText;
    
    
    	    const p = document.createElement("p");
    	    let descriptionText = landingPageCardContents[j].innerText;
    	    const titleIndex = descriptionText.indexOf(a.innerText);
    	    if (titleIndex) {
    		descriptionText = descriptionText.slice(0, titleIndex) + descriptionText.slice(titleIndex + a.innerText.length);
    	    }
    	    p.innerText = descriptionText.trim(); 
    
    	 
    	   //footer
    	   a2 = document.createElement("a");
    	   a2.className = "card-link"
    	   a2.innerText = "Go to page";
    	 
    	   div.append(i);
    	   div.append(h3);
    	   div.append(p);
    	   div.append(a2);
    	 
    	   a.innerHTML=""
    	   a.append(div)
    	 
    	   document.querySelector(".cards").append(a);
    	    
    	   //apply inline style (if any)
    	   sourceStyle = landingPageCardContents[j].getAttribute('style');
    	   a.setAttribute('style', sourceStyle);
    	   p.setAttribute('style', sourceStyle);
    	 
    	})
    	 
    	 
    	cardCount = landingPageCardLinks.length + 1;
    	 
    	//Default Style that can be override by other themes / layouts
    style = `<style>
    #landing-page {
         background: #dfe9ff;
         font-family: Lato, sans-serif;
             height:100vh;
    }
     
    .banner{
        display:flex;
        padding:3%;
    }
    
     .banner .banner-image {
         opacity: 0.5;
         position: absolute;
         right: 0px;
         top: 0px;
         filter: drop-shadow(0 3rem 0.05rem rgba(191, 216, 255, 1));
    }
    
     @media (min-width: 300px) {
         .banner .banner-image {
             display: none;
             height: 400px;
             top: 0px;
             opacity: 0.5;
        }
    }
    
     @media (min-width: 900px) {
         .banner .banner-image {
             display: inherit;
             height: 400px;
             top: 0px;
             opacity: 0.5;
        }
    }
    
     @media (min-width: 1400px) {
         .banner .banner-image {
             display: inherit;
             height: 500px;
             top: 0px;
             opacity: 0.8;
        }
    }
    
    
     @media (min-width: 1800px) {
         .banner .banner-image {
             height: 600px;
             top: -50px;
             opacity: 1;
        }
    }
     
     
     .banner .banner-text {
         max-width: 850px;
         float: left;
    }
     .banner .banner-text h1 {
         color: #00106a;
         font-size: 3rem;
         font-weight: 700;
         letter-spacing: 3px;
         margin-bottom: 1rem;
    }
     .banner .banner-text p {
         color: #00106a;
         xfont-size: 1.05rem;
         line-height: 1.75;
       margin-bottom:35px;
    }
     .banner-button a{
         border: 0;
         border-radius: 50px;
         padding: 0.75rem 2.75rem;
         background: #4b71ff;    
         color: #fff !important; 
         box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, .25); 
         cursor: pointer;
         position: relative;
         font-size: 1rem;
         font-weight: 400;
         letter-spacing: 1px;
         transition: all 0.3s ease-in-out;
      color:white;
      text-decoration:none !important;
    }
     
     .banner-button a:hover {
         transform: translateY(-5px);
         box-shadow: 0 1rem 1.5rem rgba(0, 0, 0, .25);
    }
     
    .cards {
        display: flex;
        flex-wrap: wrap;
        justify-content:center;
      }
     
      .card {
        flex-basis: calc(100% / ${cardCount});
        background-color: #ddd;
        margin: 10px;
      }
     
      /* Media queries for smaller screens */
      @media (max-width: 768px) {
        .card {
          flex-basis: calc(100% / ${cardCount/2});
        }
      }
      @media (max-width: 480px) {
        .card {
          flex-basis: 100%;
        }
      }
     
     
    .card {
         padding: 16px 24px;
         background: #fff;
         position: relative;
         border: none;
         box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, .15);
         border: 2px solid transparent;
         transition: all 0.3s ease-in-out;
    }
     
    .cards a:hover{
        text-decoration:none;
    }
     
     .card h3.card-title {
         font-weight: 700;
         font-size: 1.3rem;
         color: #00106a;
    }
     .card p {
         color: #989dc5;
         font-size: 70%;
         line-height: 1.5;
         margin-bottom: 72px;
    }
     .card .card-link {
         position: absolute;
         bottom: 18px;
    }
     .card:hover {
       filter: brightness(95%);
         box-shadow: 0 1rem 1.5rem rgba(0, 0, 0, .15);
         cursor: pointer;
    }
     .card .card-icon {
         width: 60px; 
         margin-bottom: 8px;
         position: relative;
         top: 0;
         left: -12px;
    }
    </style>`
    landingPageDiv.insertAdjacentHTML("afterend",style)
    })()
     

    More Templates

    A quick and dirty tip is to find templates on the web or even design your own template on a web based editor such as google docs, google slides or even Excel and then select then copy and paste directly while editing a text area other than html mode.

     

    copypaste2.thumb.gif.3ab25040bbd1286f24280427e46503ec.gif

    Center Content

    To center the content, just edit the html and wrap everything with a div tag that flex it all centered

    <div style="display:flex;justify-content: center;align-items: center;">
      :
       <generated html content from pasting from Google Sheets goes here...>
      :
    </div>
     

    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.


    User Feedback

    Recommended Comments

    There are no comments to display.


×
×
  • Create New...