A bit longer than I wanted between parts 3 and 4 but here it is. Better late than never.


In case you're new to this blog series then I would encourage you to start at the beginning:

Part 1: Project "Coresight Candy" - move over VBA we have a new way to do stuff.

Part 2: Project "Coresight Candy" - part 2 has code in it, and a lot of waffling...

Part 3: Project "Coresight Candy" - part 3, time for a little bit of fun.


A quick tidy up

The last item we experimented with in the previous blog was to play an alarm sound whenever the user clicked anywhere on the display. The example was a simple example of playing a sound and introducing some familiar events to a PI Coresight display. I did omit some tidying up of events when navigating between displays that I am going to run through as one of the first things in this blog post. If you don't tidy up then the events will be triggered against any other display that you navigate to and could give some undesired functionality on those other displays.


If you remember back to part 3 (or re-read it) then we added a click event handler:

$(document).on('click', 'body', function Display_Click(event) {  
        // Check if a new object is selected  
        if (event.target != null)  
            var xPos = event.pageX; var yPos = event.pageY;  


The event binding will remain unless we first remove it. Unfortunately I had all kinds of issues getting a neat way to unbind the event so I took a simple approach by adding a function for removing the events to the display brains file that gets called before injecting the new display brains file; if there was a display brains file already injected then the function will already exist from the last loaded brains file.


function Display_BeforeClose() {
    $(document).off('click', 'body');


Simple enough, right? I even called it "Display_BeforeClose" just like ProcessBook, although technically the display would have already closed and "BeforeClose" isn't exactly a correct name. Now all we need to do is have the wrapper (CoresightCandy- call the function before adding a new display brains file. We'll catch any errors but do nothing with them, this is just in case there was no display brains file already injected.


                var pbDisplayNumber = currentElement[0].split('#')[1].replace('/pbdisplays/', '').split('?')[0];
                var pbScriptRoot = "http://webserver/Coresight/CoresightCandy-PBDisplay-";
                var pbScriptPath = pbScriptRoot + pbDisplayNumber + ".js";

                try {
                catch (err){}

                // Inject
                var script = iframe.get(0).contentWindow.document.createElement('script');


Now when you navigate away the click event is removed...unless of course the display you navigate to has a display brains file, in which case you'll get the new click event added.


We also added a timer to act as the Display_DataUpdate event so we'll need to remove that too.

First we need to get the Id of the timer then use the clearInterval() function.


var timerId;

$(document).ready(function () {


We'll hold the Id in timerId then get the Id when we call setInterval:


    // Set up the 5 second timer for Display_DataUpdate()
    timerId = setInterval(Display_DataUpdate, 5000);


Then make sure we clear up the timer in our new Display_BeforeClose function:


function Display_BeforeClose() {
    $(document).off('click', 'body');


Different symbols

Next I wanted to take a look at how some of the symbols from ProcessBook actually get displayed in PI Coresight, just so we know how to structure our code to deal with them. I'm only going to look at a few of the common symbols to keep this blog post simple.

Let's drop some onto a display "SymbolTypes.pdi":


I've included the names of the Symbols, which are the defaults from ProcessBook, and the ProcessBook enums for each of the symbol types.

Check out the pbSymbolBitmap, that's a cool looking logo.


Let's drop this into PI Coresight and have a peek at what happens during the SVG conversion process to how it finally ends up...


Pretty cool, it looks almost exactly the same. That will do for now. So let's take a look at the symbols individually.

Note, for now I am going to ignore multistating of these symbols. I will cover that on a later blog post.



We first need to have a look at the HTML and find our Line symbol that we can do quickly by searching for the Id of "Line1" (or alternatively in Chrome you can right-click on the Line and select Inspect Element). Got it.

The HTML <g> tag is used to group SVG shapes together. Once grouped you can transform the whole group of shapes...we can think of this as being similar to a composite in ProcessBook. The group holds the symbol type in the attribute "data-symboltype". In the case of the line then this is set to "1", which is not the same as ProcessBook where a line symbol is "9". This means we are going to have a lookup in our code somewhere to deal with the differences - it is possible this is the only symbol that doesn't match, we'll see as we go along.


Within the group tag we see that there is indeed an SVG Line tag which contains the definition of the Line. Note, the Id on this element is suffixed with "_Line" after the original symbol name from ProcessBook, which is logical enough.

The position of the line is a little different to the ProcessBook Left, Top, Width and Height approach. In PI Coresight we get the x1, x2, y1, y2 positions. A slight compication here is that ProcessBook uses -15000 as the most left part of a display and 15000 as the top. In PI Coresight the top left postion is 0,0.


We don't need to worry about that so much right now but it is good to know as we build up some knowledge of how to manipulate the symbols.


Summary: Container element = SVG group with an Id that matches the ProcessBook symbol name. Actual line in a sub element of type SVG Line with some properties that don't directly translate to ProcessBook definitions. We will need to translate between the two defintions.



My immediate thought here was that we should see an SVG Rectangle element, but we don't. It seems that the SVG Polygon is used instead. Perhaps this was to cover the conversion of the polygon shape in ProcessBook too.

At least the "data-symboltype" value matches that used in ProcessBook; both use "2" as the value.

The points attribute just defines the points of each corner in a polygon, again with the same issue of coordinate differences as the Line symbol.

Of course the stroke and fill of the rectangle can be manipulated - this will be manipulated by PI Coresight if you have multi-stated the Rectangle, but we'll look at that later.


Summary: Container element = SVG polygon.



Here we deal with a couple of different symbols that make up a Text object. What we have to remember is that in ProcessBook you can assign a Background colour or a Line colour for the text, and the background colour can be different to the background colour of the display.

The "data-symboltype" matches that of ProcessBook, "4". However, there are a couple of elements involved that are child elements of the container SVG group element.

Firstly there is the "Bounding Rectangle" which provides the fill colour functionality from ProcessBook. It is an SVG Rectangle symbol with an Id of the Symbol name suffixed with "_pbTextBoundingRectE1". I haven't yet figured out what the "E1" part is supposed to represent, but I'm not worried about that at the moment. This Rectangle element allows you to set background colour of the Text.

Secondly there is the "Text" SVG element that defines the actual text that was set. In this case the text is set as the inner HTML of the Text SVG element. Note, the Id of this symbol is the Symbol name suffixed with "_pbTextE1". There is that "E1" text again, now I am starting to be bothered by what that is. My hunch is that these symbols are used within a group of symbols where there may be multiple Text symbols so they need an index suffixing to them. We'll try and find out later.


Summary: Container element = SVG group. Background = SVG Rectangle. Text = SVG Text.



I am fully expecting this to be similar to the Text symbol because really they are the same thing except the value will continuously update.

Looks very similar to me, and the "data-symboltype" is "7" just like ProcessBook. Perhaps it was just the line symbol that is different.

Like the Text symbol we have an SVG group to hold everything together, an SVG Rectangle using the suffix "_pbTextBoundingRectE1" just like the Text symbol (there's that bloody "E1" haunting me again), the value's value is using an SVG Text symbol using the suffix "_pbTextE1" again just like the Text symbol. The difference with the Value symbol is that the actual value is presented in a Text Span <tspan> element. The Id of the text span is suffixed with "_pbTextE1_Value". Now using a Text Span means that several text spans can be used and individually identified to represent different parts of a value symbol - remember you can choose to show the timestamp or units of a value, which would be seperate text.


Summary: Container element = SVG group. Background = SVG Rectangle. Text = SVG Text, Value = SVG Text Span.



At this point in the blog post I was getting a little bored with typing so much so I decided to have a little break. With what I've just learned about the symbols I reckon I could build an Analog clock that updates every second in PI Coresight. So the next section is how I did that. I'll come back to the symbol definitions shortly.


The Analog Clock in PI Coresight - well Coresight Candy.

I've built numerous clocks in PI ProcessBook because clients have wanted them, but usually they only updated at the same rate as the DataUpdate event of the display. You could use timers to run them faster but that was always risky in ProcessBook displays that were already busy with data symbols. Anyway, I'm wandering off topic, let's build the clock.


In ProcessBook I am going to draw my clock face using an Ellipse and the hour/minute/second hands using Line symbols. You can use a rotation property in ProcessBook symbols to rotate them which is always useful and it looks as though I can do something similar in SVG using transforms.


Now time to build the display in ProcessBook. I am going to keep it simple and use 1 Ellipse and 3 Line symbols.

  • I've added an Ellipse as the Clock Face background, it is white with a black thick stroke.
  • I've added a Line as the second hand and named it "SecondHand". It is red with a thick stroke.
  • I've added a Line as the minute hand and named it "MinuteHand". It is dark grey with a thick stroke.
  • I've added a Line as the Hour hand and named it "HourHand". It is dark grey with a thick stroke.


I've lined up all the Line to point at 12, aligned them up at the centre point of the circle.

Saved the display as "Clock.pdi".

Job done.



Hmmm, the second hand isn't moving though. Now I could add some VBA to do that but I want to view this in PI Coresight ideally and not in ProcessBook. I'm just using ProcessBook to design my PI Coresight screen.


Let me upload it to PI Coresight and get the display number. Remember I need the display number in order to create a Coresight Candy brains file for the display!


Okay, here it is in PI Coresight (via Coresight Candy):

It looks the same, right? Also it has the same problem that nothing is moving. Let's solve that.


First thing I do is create a new brains file for my display, which for arguments sake is display number "246".

I now create a brains file called "CoresightCandy-PBDisplay-246.js".


This is where the Coresight Candy framework really starts to help with rapid development of PI Coresight automation! Watch how quick and how little coding I have to do to make this clock work!


In the "Display_Open" event I am going to add a 1 second timer and update the rotation property of the clock hands based on the current time. In order to do that I need to set the "transform" attribute and set how I want the rotate. A little bit of simple maths to get the right degree of rotation and it is done. Remember from our look at how the pbSymbolLine symbol is represented in SVG that we need to manipulate the element suffixed with "_Line". For example, as we named our second hand line "SecondHand" that means we need to manipulate "SecondHand_Line" element.


function Display_Open() {
    // Add your code here...
    setInterval(function TickTock() {
        var d = new Date()
        var x1 = $('#SecondHand_Line').attr('x1');
        var y1 = $('#SecondHand_Line').attr('y1');
        $('#SecondHand_Line')[0].setAttribute('transform', 'rotate(' + 6 * d.getSeconds() + ' ' + x1 + ' ' + y1 + ')');
        $('#MinuteHand_Line')[0].setAttribute('transform', 'rotate(' + 6 * d.getMinutes() + ' ' + x1 + ' ' + y1 + ')');
        $('#HourHand_Line')[0].setAttribute('transform', 'rotate(' + 30 * (d.getHours() % 12) + d.getMinutes() / 2 + ' ' + x1 + ' ' + y1 + ')');
    }, 1000)


If you notice then I need to have a center point for the rotation and because I already aligned the lines in ProcessBook then I can simply use the x1 and y1 attributes of one of the lines. Then based on the current time set the rotation. Very simple yet very effective, and all I had to so was add some javascript to the "Display_Open" event.


So what does it look like in PI Coresight, well like this:


I decided to take a lo-tech video of the PI Coresight display in action. There is no audio with the video but you can see it updating every second, and at the top of the minute you can see the minute hand nudge itself too.



I'm going to call it a day on this blog post for now, I'll be back with a part 4b very shortly.

Edit: When I said shortly, well I think I've taken longer than I expected already. Bear with me folks.


Stay tuned!


Rhys Kirk