Last week, we took a look at how to create interactive mashups with Visio diagrams without writing any code. If you need more flexibility in creating rich diagram mashups than offered out of the box by web part connections, you can use the Visio Services JavaScript Mashup API.
In this post we'll review the breadth of possibilities by the Visio Services Mashup API and show you how to get started coding with a few simple examples.
In a nutshell, the Visio Services JavaScript Mashup API enables developers to access and manipulate the Visio web drawing, its pages and shapes. Some key scenarios enabled by the Mashup API are:
The class diagram below summarizes the available objects in the API. Notice that related class members are collected into functional groups – each group is discussed in more detail in the API in the appendix of this article.
Like many JavaScript APIs, it's important to note that the Visio Services JavaScript API is event-based. To program against the Visio Web Access web part, you must catch the events it exposes by writing event handler functions. The diagram below is the state chart of VwaControl events:
Typically, when the onApplicationLoad event fires you'll want to get a reference to the vwaControl object and set-up handlers for ondiagramcomplete. Note that vwaControl is the only valid object in the object model until ondiagramcomplete fires. Then, when the ondiagramcomplete event fires you'll want to get a reference to the currently loaded page and set-up handlers for the various mouse events.
Now that you understand the object and event model of the API, let's get started coding. Before you can interact programmatically with a Visio Web drawing you must add a Visio Web Access web part to a web part page, load a VDW file into it and add a Content Editor Web part to the page to contain your JavaScript.
To do so, assuming you have "Contribute", "Design" or "Full Control" permissions to a page in SharePoint Server 2010, you should:
1: <script language="javascript">
2: // A hook into AJAX's Sys.Application.load event, raised after all scripts
3: // have been loaded and the objects in the application have been created
4: // and initialized.
5: Sys.Application.add_load(onApplicationLoad)
6:
7: // Global variables for the application
8: var webPartElementID = "WebPartWPQ3"; //Change this to the appropriate web part ID.
9: var vwaControl;
10: var vwaPage;
11: var vwaShapes;
12:
13: // Function Name: onApplicationLoad()
14: // Parameters: None
15: // Description: This function handles the AJAX's Sys.Application.load event
16: // When this event fires the function captures references to
17: // the Visio Web Access web part object and registers
18: // the following Visio Web Access specific event handlers:
19: //
20: // 1. diagramcomplete: raised when the request for a web
21: // drawing page finishes.
22: function onApplicationLoad() {
23: try{
24: vwaControl= new Vwa.VwaControl(webPartElementID)
25: vwaControl.addHandler("diagramcomplete", onDiagramComplete);
26: }
27: catch(err){
28: }
29: }
30:
31: // Function Name: onDiagramComplete
32: // Parameters: None
33: // Description: This function handles the onDiagramComplete event which is
34: // raised when a request for a web drawing page completes.
35: // When the event fires, this function captures references
36: // to script's global variables such as the current page, the
37: // collection of shapes on the page. It also sets the page zoom to
38: // "fit page to view" to give a full view of the page to
39: // users and registers the following Visio Web Access specific
40: // event handlers:
41: //
42: // 1. shapemouseleave: raised when the mouse enters a shape.
43: //
44: // 2. shapemouseenter: raised when the mouse leaves a shape.
45: //
46: // 3. shapeselectionchanged: raised when the active selection
47: // is changed from one shape
48: // to another.
49: function onDiagramComplete() {
50: try {
51: vwaPage = vwaControl.getActivePage();
52: vwaPage.setZoom(-1);
53: vwaShapes = vwaPage.getShapes();
54: vwaControl.addHandler(“shapeselectionchanged”, onShapeSelectionChanged);
55: vwaControl.addHandler(“shapemouseenter” , onShapeMouseEnter);
56: vwaControl.addHandler(“shapemouseleave”, onShapeMouseLeave);
57: }
58: catch(err) {
59: }
60: }
61:
62: // Put the sample code discussed later in the blog below...
63: </script>
Tada! You have the basics of a mash-up. That said, it doesn't do much except get references to a few basic objects and setup some event handlers. The next section gives you a few useful examples that build on this base.
In this example we will explore how to create an overlay that appears when a user hovers over a shape. In this scenario, the manager of a grocery store visualizes sales data on a floor plan of his store: sales figures are represented as colors on a store shelf. Now, let’s say we want to show a picture of the best-selling product of the day on each shelf as a user hovers his mouse over a shelf. This product changes daily and is calculated at night by running database queries; this data is then exposed through shape data when the drawing is refreshed.
To solve this problem, you'll want to draw an overlay on the shape when the mouse enters the shape, and remove the overlay when the mouse leaves the shape. Let's take a look at one possible implementation:
1: // Function Name: shapeMouseEnter
2: // Parameters:
3: // source -- a reference to the base HTML element of the vwaControl.
4: // args -- the shape ID of the shape the mouse entered.
5: // Description:
6: // On entering a shelf shape (a shape that contains a "Best Seller" shape
7: // data), this function extracts that shape data then overlays the
8: // corresponding image on the shape.
9: shapeMouseEnter = function(source, args)
10: {
11: //Get the name of the shape that was just entered
12: var shape = vwaShapes.getItemById(args);
13:
14: //Determine the best seller for that shelf. This information is stored in a shape data //named “Best Seller” item that updates over time.
15: var bestSeller;
16: var shapeData = shape.getShapeData();
17: for (var j=0; j<shapeData.length; j++) {
18: if (shapeData[j].label = "Best Seller") {
19: bestSeller = shapeData[j].value;
20: }
21: }
22:
23: //Depending on which shape this is, draw the correct overlay.
24: switch(bestSeller)
25: {
26: case "productA":
27: shape.addOverlay(
28: "myOverlay" ,
29: "<Image Source=\"productA.jpg\" Width=\"50\" Height=\"70\"><\/Image>",
30: vwaVerticalAlignment.Top,
31: vwaHorizontalAlignment.Left,
32: shape.getBounds().width,
33: shape.getBounds().height);
34: break;
35:
36: //If the best seller is product B, then display an overlay with product B.
37: case "productB":
38: shape.addOverlay(
39: "myOverlay" ,
40: "<Image Source=\"productB.jpg\" Width=\"50\" Height=\"70\"><\/Image>",
41: vwaVerticalAlignment.Top,
42: vwaHorizontalAlignment.Left,
43: shape.getBounds().width,
44: shape.getBounds().height);
45: break;
46:
47: //You can add more cases below as needed for different shelves.
48:
49: default:
50: }
51: }
52:
53: // Function Name: shapeMouseLeave
54: // Parameters:
55: // source -- a reference to the base HTML element of the vwaControl.
56: // args -- the shape ID of the shape the mouse just left.
57: // Description:
58: // On leaving a shelf shape (a shape that contains a "Best Seller" shape
59: // data), this function removes the existing overlay on that shape.
60: shapeMouseLeave = function(source, args)
61: {
62: //Get the name of the shape that was just entered
63: var shape = vwaShapes.getItemById(args)
64:
65: //And remove the overlay
66: shape.removeOverlay("myOverlay");
67: }
To add this to your solution, copy/paste the above code presented in the earlier “Getting Started”. Note that this code makes the following assumptions:
In this second example, the scenario is a network diagram mashup that allows a network administrator to find computers in a network diagram that have a particular string and to highlight them; this is useful when looking at a computer topology to quickly spot computers that meet a particular spec, or contain a particular set of characters in their name. We are effectively “scraping” the diagram to find shapes that contain a particular piece of text in either shape text or shape data.
To solve this problem, the algorithm iterates through all the shapes on the page and does a string compare against the name/shape data of that shape and highlight the shapes that contain that string. One implementation of this scenario is detailed below:
1: // Creates the user interface for this code sample which consists of a
2: // text box to enter the find-text and a button to trigger the
3: // find operation.
4: document.write("Find text:");
5: document.write("<BR><input type=\"text\" id=\"findText\"><\/input>");
6: document.write("<BR><Button id=\"findButton\" type=\"button\""+
7: "onClick=\"find()\">Find<\/Button>");
8:
9: // Function Name: find
10: // Parameters: None
11: // Description: This function iterates through vwaShapes and highlights
12: // the shapes who's name, shape data or shape hyperlinks
13: // contains the find-text. The search is case insensitive.
14: function find() {
15: // Iterate through the collection of shapes on the page, if either the
16: // shape name, shape data or shape hyperlinks contain the find-text,
17: // highlight it and jump back to the "shapeContainsFindText:" label
18: // to process the next shape.
19:
20: shapeContainsFindText:
21: for (var i=0; i<vwaShapes.getCount(); i++) {
22: // Extract the find-text from the text box and covert it to lower case.
23: var findText = document.getElementById('findText').value.toLowerCase();
24:
25: // Get a reference to the shape at index "i" of the shape collection
26: // and remove existing highlights.
27: var shape = vwaShapes.getItemAtIndex(i);
28: shape.removeHighlight();
29:
30: // Get a reference to the shape name, shape data and shape hyperlinks
31: // collections.
32: var shapeName = shape.getName();
33: var shapeData = shape.getShapeData();
34: var shapeHyperlinks = shape.getHyperlinks();
36: // Highlight the shape if the find text is found within the shape name
37: // and return to the top of the loop to process the next shape.
38: if(shapeName.toLowerCase().indexOf(findText) != -1) {
39: shape.addHighlight(2,"#00FF00");
40: continue shapeContainsFindText;
41: }
42:
43: // If the shape name did not contain the find-text, search through the
44: // the shape's shape data values for the find-text. If the find-text
45: // is found highlight the shape and return to the top of the loop to
46: // process the next shape.
47: for (var j=0; j<shapeData.length; j++) {
48: if (shapeData[j].value.toLowerCase().indexOf(findText) !=-1) {
49: shape.addHighlight(2,"#00FF00");
50: continue shapeContainsFindText;
52: }
53:
54: // If the shape name or shape data did not contain the find-text,
55: // search through the shape's hyperlinks for the find-text. If the
56: // find-text is found, highlight the shape and return to the top of
57: // the loop to process the next shape.
58: for (var j=0; j<shapeHyperlinks.length; j++) {
59: if (shapeHyperLinks[j].value.toLowerCase().indexOf(findText) !=-1) {
60: shape.addHighlight(2,"#00FF00");
61: continue shapeContainsFindText;
62: }
63: }
65: // If the text hasn't been found in the web drawing, then warn the user.
66: alert("Text not found in this web drawing!");
68: }
To add this to your solution, copy/paste the above code presented in the earlier “Getting Started” section. Note that using the code above, the find text box and button will appear in the place of the Content Editor web part.
For our third example, we’d like to highlight an in-house use of the Visio Services JavaScript OM, namely the new SharePoint workflow visualization feature in SharePoint 2010. In a nutshell, using this feature, you can now create a workflow using Visio/SharePoint Designer and visualize the progress of an instance of that workflow in SharePoint.
The progress visualization is in fact an example of using the Visio mash-up to overlay data on an existing diagram. The SharePoint workflow team used the JavaScript API to overlay workflow instance data in the context of the workflow diagram. Taking a look at the picture below, all the visuals and the text highlighted in the green box are not actually part of the published diagram but are actually drawn over the workflow shape at run-time using the mash-up API. As the data changes during the lifetime of a workflow, so will the overlay.
As you can see, the integration between the Visio published diagram and the overlays is pretty seamless!
We’re in the process of developing a full MSDN reference for the JavaScript Mashup API, including samples and an overview document. We’ll make sure to announce this on the blog when it’s made publicly available. Please note that the contents of this blog entry are preliminary and may change by the time Visio Services 2010 is officially released.
We hope this blog post has given you enough to get started building your own JavaScript solutions. Feel free to share your thoughts either through send-a-smile or by commenting on this blog post.
Object
Description
Vwa.VwaControl
The VwaControl object represents an instance of the Visio Web Access (VWA) web part. It has the following functional groups:
· Web part properties: using getVersion() and getDisplayMode() you can access web part properties such as the web part's version and its rendering technology (Silverlight or raster).
· Drawing-level: using getDiagramUrl()/setDiagramUrl(string diagramUrl) in tandem with openDiagram()* you can assign which diagram to display in the web part and then load it. External data connections in a drawing can be refreshed using refreshDiagram()*.
· Page-level: using getAllPageIds() in tandem with setActivePage(string pageId)* you can iterate through all the pages in a drawing. You can retrieve a reference to a particular page by using getActivePage().
· Events: using addHandler(string eventName, function functionName), removeHandler(string eventName, function functionName), clearHandlers() you can manage user interaction with the drawing by adding and removing event handlers to events such as:
o diagramcomplete – fired when a drawing finishes loading.
o shapeselectionchange – fired when a new shape is selected.
o shapemouseenter – fired when the mouse enters a shape's outline.
o shapemouseleave – fired when the mouse exits a shape's outline.
More details about the API's event model seciton.
· Errors: using displayCustomMessage(string HTML)and hideCustomMessage() you can show and hide and your applications' custom HTML error message pages.
* These methods are asynchronous which means that they trigger a non-blocking call back to Visio Services to replace the page currently displayed with another one. These operations have the side effect of making the current VwaControl object invalid which effectively stops you from coding against the OM after these statements. The best way to follow-up such calls is to create a handler for diagramcomplete, which fires when the VwaControl has finished loading the new page, and to put your code in that event handler. More details about the API's event model section.
Page
The Page object represents the active Web drawing page currently displayed in the web part. It has the following functional groups:
· Page: using getId() and getSize() you can access properties of the currently displayed page such as its page id and its size in pixels
· View: using getPosition()/setPosition(int x, int y) and getZoom()/setZoom(double zoom%) you can change the zoom center and zoom percentage of the web part's viewport. You can also use centerViewonShape(string shapeID) to focus the view on a particular shape and isShapeInView(string shapeID) to determine if a shape is in the current view.
· Shapes: using getSelectedShape() and setSelectedShape(string shapeID) you can change the currently selected shape. You can also get a reference to the collection of shapes in the currently displayed page by using getShapes().
ShapeCollection
The ShapeCollection object represents the collection of shape objects on the currently displayed page. It has the following functional groups:
· Shapes: using getCount() in tandem with getItemAtIndex(int index) you can easily iterate through all the shapes on a page; the array is 0 based. You can also use getItemByName(string shapeName), getItemById(string shapeId) or getItemByGuid(string shapeGuid) to index into the page’s shape collection using different Visio shape identifiers.
Shape
The Shape object represents a single shape on the active Web drawing page. It has the following functional groups:
· Shape Properties: using getName(), getId() & getGuid() you can access the shape's various Visio identifiers such as shape name, Id and Guid. You can also access a shape's meta-data by using getHyperlinks(), getShapeData() and getBounds().
· Markup: using addHighlight(integer width, string color), removeHighlight(), addOverlay(string overlayID, string content, Vwa.VerticalAlignment vPos, Vwa.HorizontalAlignment hPos, integer overlayHeight, integer overlayWidth), addPredefinedOverlay(Vwa.OverlayType overlayType, string overlayID, string content, [Vwa.VerticalAlignment vPos], [Vwa.HorizontalAlignment hPos], [integer overlayHeight], [integer overlayWidth]) and removeOverlay(string overlayID) you can manage shape markup.
Highlighting a shape draws a colored rectangle around the bounding box of the Shape as seen below:
A shape overlay is a way of adorning a particular shape with a developer visual. An example of this concept is a pushpin icon that is placed on top of a map in an online mapping application. With this set of functions, you can tag a Visio shape with your own overlay to bring attention to it:
Using the various arguments of addOverlay() and addPredefined() overlay you can configure the contents, size of the overlay as well as its alignment relative to the bounding box of the shape. Each shape may have more than one overlay; these overlays cannot however have the same developer-defined overlayID.
Note that when the underlying drawing is rendered in PNG, overlays be either HTML or an image. If the diagram is rendered in Silverlight, the overlay can be XAML or an image.
Great resource. These are valuable information to begin to use Visio services with all its power.
Thank's
I use the google web page but the why of each URL that was published there so long but it's not my owner anymore strange, new this time I'll see you goole whether the rule is so sorry you know do not make web pages because it was useless, when you make up your web pages is useless, only used for the google ads are a agremen if I click on Google ads, this violates my upside down, the web page I created for my house occupied by someone else without my permission I am not sorry for the time you play a game most cunning stage
Is possible show tooltop from shape data just as Overlays on hover?
Why do the code samples here have freeky line numbers!?! Editing them back out is a pain in the @$#^.
Nice post! I'm not sure if its just me, but if I have the <script> -tags inside the .js file won't work. Maybe something has changed in Sharepoint's Content Editor Web Part..
we're doing a demo for a local SharePoint event and wanted to know if we can use the Javascript API in Visio Services to update the contents of a connected Excel Services web part.
Basically, when the user clicks a 'bubble' element on the Visio diagram we update the visible named range of the Excel web part, which is configured to be connected to the Visio web part. This click event, however, requires a page postback and refresh.
We would like to accomplish that via Javascript to avoid the page refresh. Is this possible?
Hi Thiago,
Absolutely, you should be able to accomplish your scenario with the Excel Services JSOM as well as the Visio Services API. With the use of JavaScript, you can eliminate the page refresh.
This blog post from the Excel blog should help you out :
blogs.office.com/.../introducing-the-javascript-object-model-for-excel-services-in-sharepoint-2010.aspx
The Excel API allows you to set a range to view, and the Visio Services API allows you to capture clicks on shapes.
This MSDN article should also help: msdn.microsoft.com/.../ee554877.aspx
Thanks for reading the blog
Suneet Shah
Program Manager, Visio Team
Its a nice post . I have created a function . I am not able to call it in OnApplicationLoad. I am able to call it in OnDiagramComplete. If i call the function in OnDiagramComplete and click any visio with in 5 seconds i get an error because its taking time to load the function . If i click any visio after few seconds i dont get error . Is there any solution to overcome this .