Jump to content
  • Create a Custom Panel in Spotfire®


    Back to main C# extensions page

    Introduction

    A custom panel is a general-purpose UI components in Spotfire® that can be used to visualize contextual information, adding controls or other domain specific functionality. Custom panels cna be embedded in the Spotfire web clients, Spotfire Business Author and Spotfire Consumer, as well as in Spotfire Analyst. All with one single implementation.

    Prerequisites

    • Spotfire® Developer (SDK), see download instructions here.
    • Spotfire® Analyst, download from here.
    • Microsoft Visual Studio® 2013 or higher. The free Community edition is available for download here.

    See also

    • SDK example: CustomPanelExample - contains code examples related to what is described in this article.

    Using the API

    The following procedure describes how to create a custom panel in Spotfire:

    1. Derive from the CustomPanel class (called MyPanel below) and register a corresponding factory instance in the CustomPanelAddin class.
    2. Register a view in the RegisterViews method., for example:
      protected override void RegisterViews(ViewRegistrar registrar)
      {
            base.RegisterViews(registrar);
            registrar.Register(typeof(CustomPanelView), typeof(MyPanel), typeof(MyPanelView));
      }
      where MyPanelView inherits from CustomPanelView<MyPanel>.
    3. Initialize the visualization by overriding the GetResourceCore method.
    4. Add some interaction, see Client-driven interaction and Server-driven interaction.

    Initialization of the panel

    Conceptually, the CustomPanelView class can be seen as an embedded web server that provides an html file, together with some resources such as JavaScript files, images, etc.

    To initialize the panel, override the GetResourceCore method:

    protected override HttpContent GetResourceCore(string path, NameValueCollection query, MyVisual snapshotNode)
    {
        if (string.IsNullOrEmpty(path))
        {
            path = "Mypanel.html";
        }
    
        var bytes = GetEmbeddedResource("SpotfireDeveloper.MyPanelExample.webroot." + path);
        return new HttpContent("text/html", bytes);
    }
     
    Technically, when the end user opens a panel of your custom type, what will happen internally is that an "embedded web client" (an iFrame html element) will appear on the current page, and that web client will make an http request with the URL "/". That request will be routed to call the above method GetResourceCore. In the example above, Mypanel.html will be retrieved.

    Note: in order to enable GetEmbeddedResource to find resources specified as in the above example, create a webroot folder in the root of the Visual Studio project. Put the html file and other embedded resources in that folder. Then make sure to set the build action for each of your files is set to "Embedded Resource":

    The retrieved html file may in turn load any resource:

    <script src=”http://code.jquery.com/jquery-1.11.2.min.js”></script>
    <script src=”myscript.js”></script>
     
    The request for myscript.js is specified with a relative path so it will be handled by the overridden GetResourceCore method. In the example above, the location of the JavaScript file in the webroot folder is looked up and the file is embedded. However, the JavaScript file could be fetched in any fashion. For example, in the case of debugging, it could be useful to fetch the file from a hardcoded path to avoid a rebuild of the project, for example:
    // For easy debugging:
    var bytes = File.ReadAllBytes(@"C:\Data\MyVisualStudioProject\webroot\MyFile.html");
    
    // Guess mimetypes based on registered mimetypes
    var mimeType = "application/unknown";
    var ext = Path.GetExtension(path).ToLower();
    var regKey = Registry.ClassesRoot.OpenSubKey(ext);
    if (regKey != null && regKey.GetValue("Content Type") != null)
    mimeType = regKey.GetValue("Content Type").ToString();
    
    return new HttpContent(mimeType, bytes);
     
    This example also shows one way of setting the mime type of the resource.

    Client-driven interaction

    Your custom panel can be regarded as if it is divided into a client side and a server side, where the client side is a "view" and the server side is a "model".

    Some utilities are provided to simplify communication with the server.

    Reading data

    Take a look at this example:

    $(window).on("SpotfireLoaded", function()
        {
            Spotfire.read("GetData", {"argument": "value"}, function(data)
            {
                if (data)
                {
                    // typically re-render the panel UI, but this example
                    // just displays the returned value 
                    alert(data);
                }
            });
        });
     
    When the "SpotfireLoaded" event is triggered, the communication channel is open between the client and the server. In this example, the Spotfire.read function fetches data from the server.

    The Spotfire.read function takes three arguments:

    • A method identifier
    • An argument object
    • A callback

    On the server side, the read call is handled by the ReadCore method:

    protected override string ReadCore(string method, string args, MyPanel snapshotNode)
    {
        if (method.Equals("GetData", StringComparison.OrdinalIgnoreCase))
        {
            // typically retrieve some data from the document, 
            // but this example just echoes the input argument
            return args;
        }
            
        return base.ReadCore(method, args, snapshotNode);
    }
     
    Note that when reading data, the serving code is executed on a background thread. This allows multiple simultaneous read operations.
     

    Writing data

    When the client needs to modify the document, for example, as a result of user input, use the Spotfire.modify method.

    The  Spotfire.modify method takes two arguments:

    • A method identifier
    • An argument object

    Example that sets a document property:

     Spotfire.modify("SetProperty", {"propertyName": pName, "propertyValue": pValue});
     
    On the server side, the modify call is handled by the ModifyCore method:
     
    protected override void ModifyCore(string method, string args, MyPanel liveNode)
    {
        if ("SetProperty".Equals(method, StringComparison.Ordinal))
        {
            // Call MyPanel for further processing.
            liveNode.SetProperty(/* … */);
        }
    }
     
    Note that the modification of the document is performed on the main thread, so it is safe to modify the document.
     

    Server-driven interaction

    From the server, it is possible to trigger event handlers on the client side. For example:

    private void UpdatePanelUI()
    {
        this.InvokeClientEventHandler("render", null);
    }
     
    At the client:
     
    var render = function(data)
    {                
        // Typically call Spotfire.read(...)
        // data will be the argument from the server invocation - null in this example
    };
    
    Spotfire.addEventHandler("render", render);
     
    • Like 1

    User Feedback

    Recommended Comments

    There are no comments to display.


×
×
  • Create New...