This is the first part of a four part series that discusses how to display product photos in SAS Visual Analytics.
The data-driven content object in SAS Visual Analytics enables you to display your data in a custom third-party visualization within your Visual Analytics report. These third-party visualizations can be developed in any JavaScript charting framework, like D3.js, Google Charts, or CanvasJS. The visualization receives its data from Visual Analytics and can interact with filters, ranks, and actions in the same manner as other objects in your report. The data-driven content is not limited to unique or complex visualizations, however. You can use the data-driven content to present any content that can be displayed in an iFrame.
Suppose you would like to display an image of a selected product in a report. Because the image is updated based on viewer selections, a data-driven content object is needed for this task. You can use this code to display images for any scenario: to show a picture of an employee, an office location, or even a state flag.
To use the data-driven content object, you will need some knowledge of HTML, CSS, and JavaScript to create the file that will display the image. The file will also need to be hosted on a web server. In addition, if you want to send messages from the HTML file to Visual Analytics, SAS Viya must be accessed using the HTTPS protocol.
Note: For testing purposes I used the Five Server extension in Visual Studio Code to use my machine as a web server.
To create the visualization, follow these steps:
Note: In this post, I will discuss on the required pieces of code. Future posts will cover optional pieces.
Note: The entire code is available (via a link) at the end of this post.
I’ll start with a simple HTML page that contains a div (for the photo).
Select any image to see a larger version.
Mobile users: To view the images, select the "Full" version at the bottom of the page.
A link is included to Bootstrap so special classes can be used to define the layout of the page and modify the content included in the page. These classes make it easier develop a responsive, mobile-first web page. In this example, Bootstrap will be used to display the image at 100% width, regardless of the screen size.
Script tags that reference the utilities from the SAS GitHub repository for third-party visualizations are included to help when creating the visualization. These utilities will be used in the JavaScript code to receive messages from Visual Analytics (using the setOnDataReceivedCallback function), send messages to Visual Analytics (using the postInstructionalMessage function), and validate the data received from Visual Analytics (using the validateRoles function).
A div is created with an id of photo to hold the image.
Note: For this example, I copied the utilities from the SAS GitHub repository for third party visualizations and stored them in a util folder where the web page is hosted. This is a best practice.
Note: Only the setOnDataReceivedCallback function is used in this example. The other functions will be explored in future posts.
Inside the script tag (in the body), an event listener is added to execute a function when the HTML document is loaded and parsed. This is a best practice when working with JavaScript.
Inside the event listener function, several dynamic variables are created: vaMessage to hold the data passed from Visual Analytics to the third-party visualization and rowCount to hold the number of rows of data passed from Visual Analytics.
The rowCount variable will be used to determine if the viewer selects a product line. If they do, only one row will be passed from Visual Analytics and a picture of that product line will be displayed. If they do not, multiple rows will be passed from Visual Analytics and the company logo will be displayed.
This code also creates some selection variables that will be used to add the photo to the web page: photoDiv to hold the div for the photo and itemPhoto to hold the img element that will contain either the product image or the company logo.
Next, create a callback function to get the data from Visual Analytics.
The setOnDataReceivedCallback function (located in the messagingUtil.js file) creates a callback function that can be used to handle messages received from Visual Analytics. You must define a function (in this example, onDataReceived) that specifies what actions will be performed on the data received from Visual Analytics.
The onDataReceived function takes the data from Visual Analytics (messageFromVA) and initializes the dynamic variables: vaMessage contains the message in its entirety and rowCount contains the number of rows of data passed from Visual Analytics.
After the data variables are initialized, code is added to include the product photo on the web page.
The getElementById method is used to create an object that references the div in the body that has an id of photo. Then, the div is cleared (using the innerText property). Next, an if statement checks to see if the data passed from Visual Analytics contains one row (rowCount == 1). If it does, then a single product line is selected in the report. When this occurs, a new img element is created (using the createElement property), attributes of the element are modified (src and alt), and the element is added to the DOM (using the appendChild method).
The src attribute points to the image for the selected product line in the images folder. Note that the toLowerCase method is needed convert the product line passed from Visual Analytics (which is proper case) to the case used for the image file (which is in lower case). The alt attribute is the value of the selected product line. A Bootstrap class (img-fluid) is also added to the image to ensure the image takes up 100% of the width of the screen.
When the code is complete, you can test it in Visual Analytics. I added a page prompt to the report to select a product line and added a data-driven content object (that references the code) to the canvas.
Notice that Promo is selected in the drop-down list control.
Adding Product Line to the Variables role will send the selected product line to the third-party visualization. If one row is passed, an image for the selected product line will be displayed.
If multiple rows are passed (nothing is selected in the drop-down list control), the company logo will be displayed.
This example is relatively simple because the data from Visual Analytics is only used when one row is passed to the visualization. If you are working on an example that requires the use of multiple rows, you will need to restructure the data from Visual Analytics into a two-dimensional array of objects so it can easily be referenced in your JavaScript code.
In addition, images don’t require any axes to display the data and Bootstrap is used to handle the responsiveness of the image for different screen sizes. In many cases, you will need to extend your code to create axes based on the scale of data assigned to the object and to redraw elements when the screen (or object) is resized. For examples on how to do this, see the samples in the SAS GitHub repository for third-party visualizations.
You can use this code to display images for any selected value in your report: a product, an employee, an office location, or even a state flag. In this example, we used a page prompt to filter the values, but it will even work with actions between objects. Suppose I have a report that contains a bar chart that filters the data-driven content object. When I select a product line (Plush), the image of that product line is displayed.
In the next part of this series, we will discuss how Visual Analytics communicates with the visualization and see how to validate the data passed from Visual Analytics
Documentation: Working with Data-Driven Content
Documentation: Programming Considerations for Data-Driven Visualizations
SAS GitHub repository for third-party visualizations
Book: Interactive Reports in SAS Visual Analytics
Below is the code in its entirety.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- Bootstrap -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<!-- Utilities for DDC -->
<script type="text/javascript" src="util/messagingUtil.js"></script>
<script type="text/javascript" src="util/contentUtil.js"></script>
</head>
<body>
<!-- Container for Photo -->
<div class="container" id="photo">
</div>
<!-- Custom JavaScript -->
<script>
// Listening for HTML document completely loaded and parsed, best practice
document.addEventListener("DOMContentLoaded", function() {
/******************************* Declare variables ***************************************/
// Dynamic data variables
let vaMessage; // Data message from VA
let rowCount; // Number of rows passed from VA
// Selection variables
let photoDiv; // Div for photo
let itemPhoto; // Element for photo
/******************************* Setup Callback Functions ***************************************/
// Attach event for data message from VA
va.messagingUtil.setOnDataReceivedCallback(onDataReceived);
// Take action on received data
function onDataReceived(messageFromVA) {
// Initialize data variables
vaMessage = messageFromVA;
rowCount = messageFromVA.rowCount;
// Add photo to DOM
const photoDiv = document.getElementById("photo");
photoDiv.innerText = "";
// Display photo for selected item
if (
rowCount == 1
) {
itemPhoto = document.createElement("img");
itemPhoto.src="images/"+vaMessage.data[0][0].toLowerCase()+".jpg"; // check this!
itemPhoto.alt = vaMessage.data[0][0];
itemPhoto.classList.add("img-fluid");
photoDiv.appendChild(itemPhoto);
} else {
itemPhoto = document.createElement("img");
itemPhoto.src="images/insight_toys_logo.png";
itemPhoto.alt = "Insight Toys Logo";
itemPhoto.classList.add("img-fluid");
photoDiv.appendChild(itemPhoto);
};
};
});
</script>
</body>
</html>
Find more articles from SAS Global Enablement and Learning here.
Thanks! Plan on giving this a try.
@lhartjordan I would love to see your end result!
Thanks for the information!
@melissa69 any time!
Thanks i will try it
@Cayden Would love to see how it turns out!
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
Data Literacy is for all, even absolute beginners. Jump on board with this free e-learning and boost your career prospects.