User Experience. Data Representation on Complex Graphics

experience
#1

Hello! What will be the best approach to represent device state values on a complex graphical object in user experience page/dashboard? For instance, something like that:
2019_03%20Graphics%20Losant%20Example
Basically, need to repeat traditional SCADA GUI approach, when equipment plus real time values are shown to an operator as one visual object.
Thanks

#2

Hi @Alexander_Kondrov,

This is definitely possible. Here is how it would work from the highest level:

In an Experience Page, you can render an image. Then, using HTML and CSS, overlay that image with the values of said device. Those values can come from the page data you send to the Experience Page, or it can be done with client-side Javascript using an Experience API Endpoint.

To make it easy for you, we are going to work on an example for you, and I’ll post here!

Just to make you aware: You can also do some complex charting using the Custom Chart Block.

This is a very flexible and powerful block we made to allow you to make some really interesting visualizations. Behind the scenes, we leverage a library called Vega Lite. Here are some examples of the kinds of visualizations you can make:

Happy to answer any questions in the meantime.

1 Like
#3

Hi Taron,
I was able to paste Vega-lite examples to my test user experience pages as well as try to copy some tables from third-party table generators available online. The last thing that seems to start working is sending pagedata from experience workflow to experience page. I was able to publish a constant value. Thank you for your post.

1 Like
#4

Here’s an example I’m working on that does something similar to what you wanted.

It uses Leaflet to handle the zooming, panning, and rendering the overlays (thanks to @anaptfox for the recommendation).

I followed this guide for rending an image instead of the typical map tiles.

I then used the DivIcon to render completely custom overlays.

The small spark graphs are built directly using Vega-Lite.

I use the External Website Block to add a custom Experience Page to the dashboard. This visual is implemented as an Experience Page. This dashboard is intended to be viewed as an Experience Dashboard Page, which means the user’s authentication details are automatically available to the embedded block as well (because they’re hosted from the same domain). This lets me have a fully secure and authenticated dashboard even when embedding an external page like this.

There’s JavaScript in the Experience Page that polls an Experience Endpoint for the updated status values for whatever device is being displayed.

2 Likes
#5

To follow up on this, here’s the main page’s HTML, which provides a little insight into how I organize my resources:

<html>
  <head>
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://unpkg.com/leaflet@1.4.0/dist/leaflet.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vega@5.0.0/build/vega.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vega-lite@3.0.0-rc14/build/vega-lite.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vega-embed@3.29.1/build/vega-embed.js"></script>

    <script type="text/javascript">
      {{component "script"}}
    </script>

    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.4.0/dist/leaflet.css" />
    <style>
      {{component "style"}}
    </style>
  </head>
  <body style="padding:0px; margin:0px; width:100%; height:100%; overflow:hidden;">
    <div id="map" style="width:100%; height:100%;"></div>
  </body>
</html>

My JavaScript file and style sheet are implemented as Components, which I then include into the header using the {{component}} helper. I write everything using the Losant CLI. I really like the losant experience watch command, which automatically uploads all changes to any Page or Component I edit.

Almost all of the actual rendering is done client-side in my JavaScript file.

2 Likes
#6

Hi Brandon,

I am still struggling with making live value updates on HTML/Javascript custom experience. I checked leaflet plugin and mapbox, but left it for more advanced graphics later. So, I am just using SVG formatted graphics with textfield for now. Could you provide me an example of what seems to be the last piece of my solution? That’s what I have:

  1. Experience Workflow is triggered with Get /pagename endpoint. After token, group check it pushes back some live data to {{pageData}} with end-Point node reply
  2. The workflow runs for a while in a loop making sure values in {{pageData}} are updated and published to end-Point reply node
  3. Page is loaded with {{pageData}} and an initial loaded value from {{pageData}} is shown. The text field on a WebPage is updated with Javascript/SetInterval function every second. It works fine for on-page generated values such as current time, but not for {{pageData}}.
  4. Updates of {{pageData}} are not shown, only the initial loaded value

It seems that I need to make End-Point reply to push data to the open web-page or make web-page to request/track html data updates to implement these live values. Could you recommend me both the easiest and the correct approach to fix it?

Thanks

#7

Hey Alexander,

I can definitely see the confusion. The Endpoint Reply Node only works the first time for a given request. All subsequent calls will be ignored.

The solution you’re building would require two separate endpoints. One returns the HTML, CSS, and JavaScript of the page itself. The second is an API endpoint that the setInterval calls over and over again.

So I’d recommend something like this:

GET /pagename -> Endpoint Reply Node sends an Experience Page.

GET /api/devices/{deviceid} -> Called over and over again by setInterval from the Experience Page. Queries the required data from the specified device ID and responds with JSON. Your client-side JavaScript (the same code doing the setInterval) then updates elements on the page with the new values.

I can create a simple example if that would help.

1 Like
#8

Brandon, your advice helped, thanks. I was able to create dynamic value updates on the page (Finally :slight_smile: ) . I was using a simple additional GET End Point though with repeated authentication. Is GET /api/devices/{deviceid} a part of standard Losant API? I need to try it. One more question. Is there a way to push data to a page from a workflow once values change, but not just run cyclic get requests from the page? Thank you once again.

#9

/api/devices/{deviceid} is not part of standard Losant. It’s a custom Endpoint you’d create to retrieve whatever information you require for {deviceid}. I like the /api prefix convention just as a way to separate your HTML Endpoints from your API Endpoints.

There is currently no way to push data to a page. The polling mechanism is the recommended approach. We’ve been designing a streaming endpoint system for a little while that would address this requirement.

1 Like