pill buttons

Change look and feel standard buttons




html
<Pre style="margin-left:500px">
Button     <span class='pill button'> <SpotfireControl id="baef049d975f4210af51b20c9a1c60b7" /> </span><br/>
Switch      off <span class='pill switch'>  <SpotfireControl id="0351da843e684914ab3978b18b0bade6" />  </span> on<br/>
Dropdown    <span class='pill dropdown'> <SpotfireControl id="afdad0889d0b4f00b3e72cbc7827a88c" /></span>
</Pre>


<style>
.pill{
 white-space:pre;
 cursor: pointer;
 background: #efefef;  
 border-radius: 100px;
}

.pill:hover {
 background: #fff;  
}

.switch{ border:1px inset #dfdfdf;}
.button, .dropdown{ border:1px outset #dfdfdf;}
.button:active, .dropdown:active{ border:1px inset #dfdfdf;}

.pill.dropdown .sf-element-dropdown,
.pill.dropdown .sf-element-dropdown:hover
{
border:none;
background-image:none;
}

.sf-element.sf-element-control.sfc-action.sfc-action-button
{
border:none;
background-image:none;
}

.sf-element.sf-element-control.sfc-action.sfc-action-button.sfpc-active
{
border:none;
background-image:none;
}
</style>


pill switch

Here is a simple way to create a pill switch without javascript. All you need is a calculated value that changes a boolean document property and some css to change the look and feel of it. The boolean doc property can then trigger another script when this property changes.

calculated value custom expression:
If(${myDocProp},"      🌑","🌑      ") as [click to toggle]

The colors can be changed with the calculated values rules

html
<span class='pill'> calculated value goes here </span>

<style>
.pill {
 white-space:pre;
 border:1px solid #dfdfdf;
 cursor: pointer;
 background: #efefef;  
 border-radius: 100px;
}
</style>




Dendogram












data
L0 L1 L2 L3 L4
x a a1
x a a2 a2a
x a a3
x b b1 b1a b1a1
x c c1
x c c2 c2a
x c c3

x d


script
#dataTable and ta (text area) are script parameters

#settings
delim = ","
cr = "\n"

#get list of filtered rows
rows = Document.ActiveFilteringSelectionReference.GetSelection(dataTable).AsIndexSet()

#generate tree
html = "<div class='tree'>"+cr # rendering text
r=0 # row #
l=0 # level
ll=0 # previous level
D=-1 # delta level change 
cc=[""]*(dataTable.Columns.Count+1) # previous level value


for row in rows:
c=0
for column in dataTable.Columns:
#get a cell value
v =  column.RowValues.GetFormattedValue(row) 
v = v if v!="(Empty)"  else ""

#is a node
isNode=v<>""

# record previous level and previous level value
if(isNode):
l=c+1

#calculate delta between levels
isBranch =v<>cc[l]
D=l-ll

if isBranch:

#construct text
if D>0 : html +=  "<ul>" * D + "<li><a>"+v+"</a>"+cr
if D<0 : html += "</ul>" * abs(D) + "<li><a>"+v+"</a>"+cr
if D==0 : html += "       <li><a>"+v+"</a></li</ul>"+cr


#record previous level and previous column value
ll=l
cc[l]=v

#increment col index
c+=1

#new row
#increment row index
r=0
#print cr + html + "</ul></div>"


#render results to a target textArea
from Spotfire.Dxp.Application.Visuals import HtmlTextArea
vis = ta.As[HtmlTextArea]()
vis.HtmlContent = html 

javascript (optional to make nodes collapsible)
//place this in the target textarea

$(function () {
    $('.tree li').hide();
    $('.tree li:first').show();
    $('.tree li').on('click', function (e) {
        var children = $(this).find('> ul > li');
        if (children.is(":visible")) children.hide('fast');
        else children.show('fast');
        e.stopPropagation();
    });

});


css (horizontal) 
/*Place this style in a different text area other than the target text area*/

<style>
* {margin: 0; padding: 0;}

.tree ul {
padding-top: 20px; position: relative;

transition: all 0.5s;
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
}

.tree li {
float: left; text-align: center;
list-style-type: none;
position: relative;
padding: 20px 5px 0 5px;

transition: all 0.5s;
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
}

.tree li::before, .tree li::after{
content: '';
position: absolute; top: 0; right: 50%;
border-top: 1px solid #ccc;
width: 50%; height: 20px;
}
.tree li::after{
right: auto; left: 50%;
border-left: 1px solid #ccc;
}

.tree li:only-child::after, .tree li:only-child::before {
display: none;
}

.tree li:only-child{ padding-top: 0;}

right connector from last child*/
.tree li:first-child::before, .tree li:last-child::after{
border: 0 none;
}

.tree li:last-child::before{ border-right: 1px solid #ccc;
border-radius: 0 5px 0 0;
-webkit-border-radius: 0 5px 0 0;
-moz-border-radius: 0 5px 0 0;
}
.tree li:first-child::after{
border-radius: 5px 0 0 0;
-webkit-border-radius: 5px 0 0 0;
-moz-border-radius: 5px 0 0 0;
}


.down-connector {
  position: absolute; top: -100; left: 50%;
border-left: 1px solid #ccc;
width: 0; 
  height: 20px;
}

.connector{
  position: absolute; 
  left: 50%;
border-left: 1px solid #ccc;
width: 0; 
  height: 20px;
}

.tree li a{
border: 1px solid #ccc;
padding: 5px 10px;
text-decoration: none;
color: #666;
font-family: arial, verdana, tahoma;
font-size: 11px;
display: inline-block;

border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;

transition: all 0.5s;
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
}

.tree li a:hover, .tree li a:hover + ul li a {
background: #c8e4f8; color: #000; border: 1px solid #94a0b4;
}

.tree li a:hover+ul li::after, 
.tree li a:hover+ul li::before, 
.tree li a:hover+ul::before, 
.tree li a:hover+ul ul::before{
border-color:  #94a0b4;
}

/*Time for some hover effects*/
/*We will apply the hover the the lineage of the element also*/
.tree li a:hover, .tree li a:hover + ul li a {
background: #c8e4f8; color: #000; border: 1px solid #94a0b4;
}

.tree li a:hover, .tree li a:hover + ul li a {
background: #c8e4f8; color: #000; border: 1px solid #94a0b4;
}

.tree li a:hover+div+ul li::after, 
.tree li a:hover+div+ul li::before, 
.tree li a:hover+div+ul::before, 
.tree li a:hover+div+ul ul::before{
border-color:  #94a0b4;
}


.tree li a:hover, .tree li a:hover + div+ ul li a {
background: #c8e4f8; color: #000; border: 1px solid #94a0b4;
}
</style>


css vertical (one or the other)
<style>
.tree li {
    margin: 0px 0;
    list-style-type: none;
    position: relative;
    padding: 20px 5px 0px 5px;
}
.tree li::before {
    content:'';
    position: absolute;
    top: 0;
    width: 1px;
    height: 100%;
    right: auto;
    left: -20px;
    border-left: 1px solid #ccc;
    bottom: 50px;
}
.tree li::after {
    content:'';
    position: absolute;
    top: 30px;
    width: 25px;
    height: 20px;
    right: auto;
    left: -20px;
    border-top: 1px solid #ccc;
}
.tree li a {
    display: inline-block;
    border: 1px solid #ccc;
    padding: 5px 10px;
    text-decoration: none;
    color: #666;
    font-family: arial, verdana, tahoma;
    font-size: 11px;
    border-radius: 5px;
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
}
 .tree > ul > li::before, .tree > ul > li::after {
    border: 0;
}
 .tree li:last-child::before {
    height: 30px;
}

 .tree li a:hover, .tree li a:hover+ul li a {
    background: #c8e4f8;
    color: #000;
    border: 1px solid #94a0b4;
}
 .tree li a:hover+ul li::after, .tree li a:hover+ul li::before, .tree li a:hover+ul::before, .tree li a:hover+ul ul::before {
    border-color: #94a0b4;
}

</style>

Popup filters (no js, no bs)






html

<style>
body {
  color: #333333;
  font-family: 'Helvetica', arial;
}
.wrap {
  padding: 40px;
  text-align: center;
}
hr {
  clear: both;
  margin-top: 40px;
  margin-bottom: 40px;
  border: 0;
}
h1 {
  font-size: 30px;
  margin-bottom: 40px;
}
p {
  margin-bottom: 20px;
}
.btn {
  background: #e06666;
  border: #e06666 solid 1px;
  border-radius: 3px;
  color: #fff;
  display: inline-block;
  font-size: 14px;
  padding: 8px 15px;
  text-decoration: none;
  text-align: center;
  min-width: 60px;
  position: relative;
  transition: color .1s ease;
}
.btn:hover {
  background: #555;
  border: #555 solid 1px;
}
.btn.btn-big {
  font-size: 18px;
  padding: 15px 20px;
  min-width: 100px;
}
.btn-close {
  color: #aaaaaa;
  font-size: 30px;
  text-decoration: none;
  position: absolute;
  right: 5px;
  top: 0;
}
.btn-close:hover {
  color: #919191;
}
.modal:before {
  content: "";
  display: none;
  background: rgba(0, 0, 0, 0.6);
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 10;
}
.modal:target:before {
  display: block;
}
.modal:target .modal-dialog {
  -webkit-transform: translate(0, 0);
  -ms-transform: translate(0, 0);
  transform: translate(0, 0);
  top: 20%;
}
.modal-dialog {
  background: #fefefe;
  border: #333333 solid 1px;
  border-radius: 5px;
  margin-left: -200px;
  position: fixed;
  left: 50%;
  top: -100%;
  z-index: 11;
  width: 360px;
  -webkit-transform: translate(0, -500%);
  -ms-transform: translate(0, -500%);
  transform: translate(0, -500%);
  -webkit-transition: -webkit-transform 0.3s ease-out;
  -moz-transition: -moz-transform 0.3s ease-out;
  -o-transition: -o-transform 0.3s ease-out;
  transition: transform 0.3s ease-out;
}
.modal-body {
  padding: 20px;
}
.modal-header,
.modal-footer {
  padding: 10px 20px;
}
.modal-header {
}
.modal-header h2 {
  font-size: 20px;
}
.modal-footer {
  text-align: right;
}
</style>


<!-- Button -->
<h1><center><a href="#modal-one" ><SpotfireControl id="6b028e3cabee4567b4e4081cd2459d63" /></a><center></h1>

<!-- Modal -->
<div class="modal" id="modal-one" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-header">
      <h2>Select Date</h2>
      <a href="#" class="btn-close" aria-hidden="true">x</a>
    </div>
    <div class="modal-body">
      <p><SpotfireControl id="369d6997db7249718618a82baa23023b" /></p>
    </div>
    <div class="modal-footer">
      <a href="#" class="btn">OK</a>
    </div>
  </div>
</div>


js
no javascrip required!

Send email with PDF

# This script sends a pdf via email
from System import IO, Net, DateTime
from System.Net import Mail, Mime
from System.Text import Encoding

#1. Configure email
#gmail settings    : smtp.gmail.com,  port:587 encription=True credentials=True)
#corporate settings: smtp.contoso.com,port:25  encription=False credentials=False)
SMTPClient = "smtp.gmail.com"
SMTPPort = 587
useEncription = True
useCredentials = True

fromEmail = "your@gmail.com"
toEmail ="someone@acompany.com"
fromEmailUsr = fromEmail
fromEmailPwd = "y0urP4$$w0rd!"
filename = "test.pdf"
myMailSubject = "PDF email from a spotfire geek"
myMailBody = "Attached find pdf"
PDFattachment= "C://temp//test.pdf"

#2. Prepare email
MyMailMessage = Mail.MailMessage()
MyMailMessage.From = Mail.MailAddress(fromEmail)
MyMailMessage.To.Add(toEmail)
MyMailMessage.Subject = myMailSubject
MyMailMessage.Body = myMailBody
ct = Mime.ContentType(Mime.MediaTypeNames.Application.Pdf)

#3. Attach PDF file
attach = Mail.Attachment(PDFattachment, ct) 
attach.ContentDisposition.FileName = filename 
MyMailMessage.Attachments.Add(attach)
Mail.Attachment(PDFattachment, ct)

#4. Send email
emailSender = Mail.SmtpClient(SMTPClient)
emailSender.Port = SMTPPort
if useCredentials: emailSender.Credentials = Net.NetworkCredential(fromEmailUsr, fromEmailPwd)
emailSender.EnableSsl = useEncription
emailSender.Send(MyMailMessage)

print "Email sent!"

Render HTML from Data Table

html
<span id='dropDownDocProp' style='display:none'>
<SpotfireControl id="calculatedValueGoesHere123" />
calculated value expression: first([myHTMLColumn])
</span>

<div id="here">html renders here</div>

js
MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

//this is the target element to monitor changes
//just put the span id here. You can remove next line and add a script param called targetDomId
var targetDomId = "dropDownDocProp"

//function when dropdown value changes
var myFunction = function(oldValue,newValue){
$("#here").html(newValue)
}


//no need to change after this line.
var target = document.getElementById(targetDomId)

//callback is the function to trigger when target changes
var oldVal = target.innerText.trim()
var callback = function(mutations) {
 newVal=$('#'+targetDomId+' ').text()
 if(newVal!=oldVal) myFunction(oldVal,newVal)
 oldVal = newVal;
}

//this is to glue these two together
var observer = new MutationObserver(callback);

var opts = {
    childList: true, 
    attributes: true, 
    characterData: true, 
    subtree: true
}


observer.observe(target,opts);




Sample Data
copy the text below and add a data table from clipboard in spotfire

ID Detail
2 "<div style=""position:relative;""> <div style=""opacity:0.5;position:absolute;left:50px;top:-30px;width:300px;height:150px;background-color:#40B3DF""></div> <div style=""opacity:0.3;position:absolute;left:120px;top:20px;width:100px;height:170px;background-color:#73AD21""></div> <div style=""margin-top:30px;width:360px;height:130px;padding:20px;border-radius:10px;border:10px solid #EE872A;font-size:120%;""> <h1>CSS = Styles and Colors</h1> <div style=""letter-spacing:12px;font-size:15px;position:relative;left:25px;top:25px;"">Manipulate Text</div> <div style=""color:#40B3DF;letter-spacing:12px;font-size:15px;position:relative;left:25px;top:30px;"">Colors, <span style=""background-color:#B4009E;color:#ffffff;""> Boxes</span></div> </div> </div>"
3 "<style> table { width:100%; } table, th, td { border: 1px solid black; border-collapse: collapse; } th, td { padding: 5px; text-align: left; } table.names tr:nth-child(even) { background-color: #eee; } table.names tr:nth-child(odd) { background-color:#fff; } table.names th { background-color: black; color: white } </style> </head> <body><table> <tr> <th>Firstname</th> <th>Lastname</th> <th>Age</th> </tr> <tr> <td>Jill</td> <td>Smith</td> <td>50</td> </tr> <tr> <td>Eve</td> <td>Jackson</td> <td>94</td> </tr> <tr> <td>John</td> <td>Doe</td> <td>80</td> </tr> </table><br><table class=""names""> <tr> <th>Firstname</th> <th>Lastname</th> <th>Age</th> </tr> <tr> <td>Jill</td> <td>Smith</td> <td>50</td> </tr> <tr> <td>Eve</td> <td>Jackson</td> <td>94</td> </tr> <tr> <td>John</td> <td>Doe</td> <td>80</td> </tr> </table>"
7 "<style> .flex-container { display: -webkit-flex; display: flex; -webkit-flex-flow: row wrap; flex-flow: row wrap; text-align: center; } .flex-container > * { padding: 15px; -webkit-flex: 1 100%; flex: 1 100%; } .article { text-align: left; } header {background: black;color:white;} footer {background: #aaa;color:white;} .nav {background:#eee;}.nav ul { list-style-type: none; padding: 0; } .nav ul a { text-decoration: none; }@media all and (min-width: 768px) { .nav {text-align:left;-webkit-flex: 1 auto;flex:1 auto;-webkit-order:1;order:1;} .article {-webkit-flex:5 0px;flex:5 0px;-webkit-order:2;order:2;} footer {-webkit-order:3;order:3;} } </style><div class=""flex-container""> <header> <h1>City Gallery</h1> </header><nav class=""nav""> <ul> <li><a href=""#"">London</a></li> <li><a href=""#"">Paris</a></li> <li><a href=""#"">Tokyo</a></li> </ul> </nav><article class=""article""> <h1>London</h1> <p>London is the capital city of England. It is the most populous city in the United Kingdom, with a metropolitan area of over 13 million inhabitants.</p> <p>Standing on the River Thames, London has been a major settlement for two millennia, its history going back to its founding by the Romans, who named it Londinium.</p> <p><strong>Resize this page to see what happens!</strong></p> </article></div>"
10 "<style> body {background-color: powderblue;} h1 {color: red;} p {color: blue;} </style> <h1>This is a Heading</h1> <p>This is a paragraph.</p> <script> function myFunction() { document.getElementById(""demo"").innerHTML = ""Hello JavaScript!""; } </script> </head> <body> <h1>My Web Page</h1> <p id=""demo"">A Paragraph</p> <button type=""button"" onclick=""myFunction()"">Try it</button><img src=""https://www.w3schools.com/images/html5.gif""> "

Change sparkline color on Graphical Table

from Spotfire.Dxp.Application. Visuals import VisualTypeIdentifiers
from Spotfire.Dxp.Application. Visuals.Miniatures import GraphicalTable, SparklineMiniatureVisualization 
from System.Drawing import Color 

#graphPlot is a GraphicalTable visualization script parameter
#color is a string document property holding values like "red", "blue" or "papayawhip" 

for column in graphPlot.As[GraphicalTable]() .Columns: 
    if column.Visualization.TypeId == VisualTypeIdentifiers. SparklineMiniatureVisualization: 
print column.Title
if column.Title == "Trend": 
#column.Visualization.LineColor = Color.FromArgb(R,G,B)
column.Visualization.LineColor = Color.FromName(color)



Thanks to Mike Akister and Adam W!

nice little round button



html
<span id="btn"><SpotfireControl id="fe2511f37ad94401ae64dc4f59d1cf24" /></span>

js
$("#btn input").css({
    "color": "#26A2ED",
    "border-radius": "60%",
    "height": "30px",
    "width": "30px",
    "font-size": "8px",
    "padding": "0px",
    "position": "absolute"
})

slideshow

To loop through pages automatically we need a javascript timer on each page to trigger an iron python script that changes to the next page.




html
<FONT size=6><SPAN>the iron python script switches to the next page</SPAN></FONT> 

<DIV id=switchPageBtn><SpotfireControl id="ff8993c967e049f580fed8aa9b25ec45" /></DIV>


js
$(function(){
clearTimeout(document.body.timeout);
document.body.timeout=setTimeout(function(){$('#switchPageBtn input').click();}, 3000)
});

script 
#current page number
cp = Document.Pages.IndexOf(Document.ActivePageReference)

#total pages
tp = Document.Pages.Count

#calculate next page
np = cp+1 if cp+1<tp else 0

#go to next page
Document.ActivePageReference = Document.Pages[np]


Slide menu



html

<script src='//cdn.muicss.com/mui-0.4.6/js/mui.js'></script>

<style>

#sidedrawer {
  position: fixed;
  top: 0;
  bottom: 0;
  width: 300px;
  left: -300px;
  overflow: auto;
  z-index: 2;
  background-color: #fff;
  border:1px solid lightblue;
  top:27px;
  transition: transform 0.2s;
}

@media (min-width: 768px) {
  #sidedrawer {
    transform: translate(300px);
  }

  body.hide-sidedrawer #sidedrawer {
    transform: translate(0px);
  }
}

#sidedrawer ul {
  list-style: none;
}

#sidedrawer > ul {
  padding-left: 0px;
}

#sidedrawer > ul > li:first-child {
  padding-top: 15px;
}

#sidedrawer strong {
  display: block;
  padding: 15px 22px;
  cursor: pointer;
}

#sidedrawer strong:hover {
  background-color: #E0E0E0;
}

#sidedrawer strong + ul > li {
  padding: 6px 0px;
}

.closebtn{
  cursor: pointer;
}
</style>

<b  class="closebtn js-hide-sidedrawer"><font size=4>☰</font></b>  click the hamburger to to open the menu

<div id="sidedrawer" class="mui--no-user-select">
click the top right button to close the menu 
 <div style='float:right;cursor:hand;font-size:20px' class="closebtn js-hide-sidedrawer">☒</div>
<div class="mui-divider"></div> 
<ul>
  <li class="active">
    <strong>Options</strong> 
    <ul> 
      <li>This is a List Box filter </li>
      <li><SpotfireControl id="8e46dc29e17746e38b69ed088933e1fc" /></li>
    </ul>
  </li>
  <li>
    <strong>More Options</strong>
    <ul> 
      <li>This is a Check Box filter</li>
      <li><SpotfireControl id="a5d461b193084a338c6b4c4d0cfb0cea" /></li>
    </ul>
  </li>
</ul> 
</div>
</div>
</div>


js


var $bodyEl = $('body');
var $sidedrawerEl = $('#sidedrawer');
  
  
function showSidedrawer() {
  // show overlay
  var options = {
    onclose: function() {
      $sidedrawerEl
        .removeClass('active')
        .appendTo(document.body);
    }
  };
    
  var $overlayEl = $(mui.overlay('on', options));
    
  // show element
  $sidedrawerEl.appendTo($overlayEl);
  setTimeout(function() {
    $sidedrawerEl.addClass('active');
  }, 20);
}
  
  
function hideSidedrawer() {
  $bodyEl.toggleClass('hide-sidedrawer');
}
  
  
$('.js-show-sidedrawer').on('click', showSidedrawer);
$('.js-hide-sidedrawer').on('click', hideSidedrawer);
  
  
var $titleEls = $('strong', $sidedrawerEl);
  
$titleEls.next().hide();
  
$titleEls.on('click', function() {
  $(this).next().slideToggle(200);
});

$bodyEl.toggleClass('hide-sidedrawer');