Create Document-related (Pushpin) Issues and RFIs in Your App
This tutorial demonstrates how to use the Viewer SDK to create pushpin issues and RFIs in your app. Pushpins are visual markers that denote the location of a BIM 360 issue or RFI in a document. The Viewer SDK includes an extension that renders pushpin issues and RFIs, or collects payload data for creating issues or RFIs. This tutorial demonstrates how to use the Viewer SDK to load BIM 360 documents and create issue or RFI pushpins from data specified by the end user. The steps include finding the ID of the document you want to add the pushpins to, initializing the Viewer, loading the document, enabling the end user to select a postion and object and creating the pushpin issues and RFIs (on the server side).
Note that you can add pushpins to documents in any BIM 360 Document Management folder. This tutorial demonstrates how to add a pusphin to a document in the Project Files folder, which is a simpler workflow than adding pushpins to documents in the Plans folder.
Before You Begin
- Register an app
- Acquire a 3-legged OAuth token with
viewables:read
data:create
data:read
anddata:write
scopes. - Upload the file to BIM 360 Document Management.
- Verify the name of the document you want to add the issue pushpins to. If you want to upload a new document, see the Upload a Document to BIM 360 Docs tutorial.
- Find the project ID of the document that the issues or RFIs were added to. See the initial steps of the Attachments tutorial for more details.
- Verify the ID of the project’s container. For more details see the Retrieve a Container ID tutorial.
- Verify that you have access to the relevant BIM 360 account and BIM 360 project.
- We recommend reading the Basic Application tutorial, if you are not familiar with the Viewer SDK.
This tutorial applies to both issue pushpins and RFI pushpins. The Viewer extension uses issue
for issue pushpins, rfi
for RFI pushpins. This tutorial describes an example of creating issue pushpins.
To see a working sample, see this viewer demo project (Demo project).
Step 1: Find the Item ID and Version ID
Use the project ID (b.cGVyc29uYWw6d2l
) and the folder ID of the folder that contains the document that the issues were added to (urn:adsk.wipprod:fs.folder:co.O7Zwai
) to call GET projects/:project_id/folders/:folder_id/contents with a 3-legged token. This provides the following:
- The item ID that is used when creating the pushpin in the document (step 5).
- The version ID that is used to render the document in the Viewer (step 3).
Request
curl -X GET -H "Authorization: Bearer nFRJxzCD8OOUr7hzBwbr06D76zAT"
"https://developer.api.autodesk.com/project/v1/projects/b.cGVyc29uYWw6d2l/folders/urn:adsk.wipprod:fs.folder:co.BJU3PTc4Sd2CmXM492XUiA/contents"
Response
{
"jsonapi": {
"version": "1.0"
},
},
"data": [
{
"type": "folders",
"id": "urn:adsk.wipprod:fs.folder:co.BJU3PTc4Sd2CmXM492XUiA",
"attributes": {
"name": "Project Files",
"displayName": "Project Files",
"createTime": "2017-07-17T13:06:56.0000000Z",
"createUserId": "",
"createUserName": "",
"lastModifiedTime": "2017-09-24T07:46:08.0000000Z",
"lastModifiedUserId": "X9WYLGPNCHSL",
"lastModifiedUserName": "John Smith",
"objectCount": 4,
"hidden": false,
"extension": {
"type": "folders:autodesk.bim360:Folder",
"version": "1.0",
"schema": {
"href": "https://developer.api.autodesk.com/schema/v1/versions/folders:autodesk.bim360:Folder-1.0"
}
},
{
"type": "items",
"id": "urn:adsk.wip:dm.lineage:7_5NcbL1Q1GSjRLJe9ffvw",
"attributes": {
"displayName": "My First Document",
"createTime": "2017-10-02T11:25:57.0000000Z",
"createUserId": "X9WYLGPNCHVK",
"createUserName": "John Smith",
"lastModifiedTime": "2017-10-02T11:27:22.0000000Z",
"lastModifiedUserId": "X9WYLGPNCHVK",
"lastModifiedUserName": "John Smith",
"hidden": false,
"extension": {
"type": "items:autodesk.bim360:File",
"version": "1.0",
"schema": {
"href": "https://developer.api.autodesk.com/schema/v1/versions/items:autodesk.bim360:File-1.0"
},
"data": {}
}
]
}
"included": [
{
"type": "versions",
"id": "urn:adsk.wipprod:fs.file:vf.7_5NcbL1Q1GSjRLJe9ffvw?version=1",
"attributes": {
"name": "My First Document",
"displayName": "My First Document",
"createTime": "2017-10-02T11:25:57.0000000Z",
"createUserId": "X9WYLGPNCHVK",
"createUserName": "John Smith",
"lastModifiedTime": "2017-10-02T11:27:22.0000000Z",
"lastModifiedUserId": "X9WYLGPNCHVK",
"lastModifiedUserName": "John Smith",
"hidden": false,
"versionNumber": 1,
"fileType": "ifc",
"extension": {
"type": "versions:autodesk.bim360:File",
"version": "1.0",
"schema": {
"href": "https://developer.api.autodesk.com/schema/v1/versions/versions:autodesk.bim360:File-1.0"
},
"data": {
"processState": "PROCESSING_COMPLETE",
"extractionState": "SUCCESS",
"splittingState": "NOT_SPLIT",
"reviewState": "NOT_IN_REVIEW",
"revisionDisplayLabel": "1",
}
}
Assume that the document is called My First Document, and note the following:
- The item ID (
data.id
) -urn:adsk.wipprod:dm.lineage:7_5NcbL1Q1GSjRLJe9ffvw
, which is used when creating the pusphin. (step 5). - The version ID (
included[i].id
) -urn:adsk.wipprod:fs.file:7_5NcbL1Q1GSjRLJe9ffvw?version=1
, which is used to render the document in the Viewer. Note that you do not need to encode the version ID to Base64 format, since it is already encoded when the document was uploaded to BIM 360 Document Management.
Step 2: Initialize the Viewer
Initialize the Viewer and load the document and the Pushpin extension using the Viewer SDK.
// Set up the following handles:
var viewer;
var PushPinExtensionHandle;
// Initialize the Viewer and load the document (model)
function launchViewer(urn) {
var options = {
env: 'AutodeskProduction',
// Replace <YOUR_ACCESS_TOKEN> with a 3-legged access token.
getAccessToken: <YOUR_ACCESS_TOKEN>
};
// Replace <YOUR_VERSION_ID> with a the version ID of the document.
var documentId = 'urn:' + <YOUR_VERSION_ID>;
Autodesk.Viewing.Initializer(options, function onInitialized() {
viewer = new Autodesk.Viewing.GuiViewer3D(document.getElementById('forgeViewer')); // setting viewer handle
viewer.start();
Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure); // loading document
});
}
// Select a sheet of the model to display in the Viewer.
function onDocumentLoadSuccess(viewerDocument) {
// viewerDocument is an instance of Autodesk.Viewing.Document
// The "geometry" type retrieves all of the document's 2D and 3D sheets.
var viewables = viewerDocument.getRoot().search({'type':'geometry'});
if (!viewables.length) {
return console.error('Document contains no viewables.');
}
// In this example, we are using the `viewer` handle to select and load the first sheet (view).
// Alternatively load a different sheet.
viewer.loadDocumentNode(viewerDocument, viewables[0]);
// Load the Pushpin extension
// Select pushpin buttons for the Viewer toolbar.
// By default, the buttons will not appear in the toolbar.
var extensionOptions = {
hideIssuesButton: false,
hideRfisButton: true,
hideFieldIssuesButton: true,
};
// Use the `viewer` reference to call `loadExtension` with the extension name and the extension options:
viewer.loadExtension('Autodesk.BIM360.Extension.PushPin', extensionOptions)
.then(function (extension) {
PushPinExtensionHandle = extension;
});
}
Step 3: Create the Pushpin
We recommend adding a Create Pushpin button to start the pushpin creation process. Use the button to invoke the following function:
// Define the following properties:
// `label` - An initial dummy identifier until it is saved; `status` - The color of the pushpin; `type` - the shape of the pushpin
PushPinExtensionHandle.startCreateItem({label: 'New', status: 'open', type: 'issues'});
We recommend creating a form for displaying the pushpin data. Note that it is obligatory to include a title
field. This is used when creating the pushpin in step 5. We will store the data in an object called userForm
.
After calling the startCreateItem
function, you need to set up an event listener for the pushpin.created
event. This completes the pinning process.
You could decide to set the event listener before calling startCreateItem
, however, you will need to make sure nothing else triggers the pushpin.created
event before completing the pinning process.
PushPinExtensionHandle.pushPinManager.addEventListener('pushpin.created', function (e) {
PushPinExtensionHandle.endCreateItem();
...
});
To sum things up - startCreateItem
allows us to place the pushpin in the document. Pinning the pushpin fires the pushpin.created
event. To complete the pinning process, you need to call endCreateItem
.
This tutorial will create a pushpin issue.
Step 4: Adjusting the Pushpin (optional)
The user can optionally adjust the coordinates and edit the form data before creating the actual pushpin issue. The following code should follow after the endCreateItem
function:
PushPinExtensionHandle.setDraggableById('0', true);
Our newly created Pushpin will have a default id
of 0
, which is how we grab hold of it. Setting setDraggableById
to true
allows us to move it around.
Note that you can listen to “dropping” events (after adjusting the pushpin) using the pushpin.modified
event.
Step 5: Prepare the Payload for Creating Issue and RFI Pushpins
Before creating the issue or RFI pushpins, you need to prepare the data. This tutorial demonstrates how to prepare the payload for creating issue pushpins. For information about preparing the payload for RFI pushpins, see POST rfis.
// Once the user clicks the ``Create Pushpin`` button (see step 3), you need to grab the current position of the newly created pushpin and the pushpin data using its ID, which is automatically set to ``0``.
var issue = PushPinExtensionHandle.getItemById('0');
// This is how the API expects to receive the data:
var payload = {
title: userForm.title, // In our example, this is the ``title`` the user sets in the form data (see step 3).
// The extension retrieved the ``type`` and ``status`` properties in step 3, concatenated them, added a dash, and
// assigned the new string to the ``status`` property of the newly created pushpin object. For example, ``issues-
// open``.
// You now need to extract the ``status`` (``open``) from the pushpin object.
status: issue.status.split('-')[1] || issue.status,
createdAtVersion: <YOUR_VERSION_ID>, // See step 1 for the version ID.
// The issue subtype ID. See GET issue-types for more details.
issueSubtypeId: <ISSUE_SUBTYPE_ID>
"linkedDocuments": [
{
type: "TwoDVectorPushpin",
// The ``urn`` is the ID of the document (``item``) associated with an issue; see step 1.
urn: <YOUR_ITEM_ID>,
createdAtVersion: <YOUR_VERSION_ID>, // See step 1 for the version ID.
details: {
viewable: {
id: viewer.model.getDocumentNode().data.guid,
name: viewer.model.getDocumentNode().data.name,
is3D: viewer.model.is3D
},
position: issue.position,// The x, y, z coordinates of the pushpin.
objectId: issue.objectId, // (Only for 3D models) The object the pushpin is situated on.
viewerState: issue.viewerState // The current viewer state. For example, angle, camera, zoom.
}
}
],
};
// See step 6 for details about how to implement the call in your server
createIssue(data);
Step 6: Create the Issue or RFI Pushpins
Within our server we will implement the POST issues call. If you are creating RFI pushpins, you need to implement POST rfis.
Step 7: Final Formatting
After calling POST issues, you can follow the Render Pushpin Issues and RFIs in Your App tutorial to rerender all the pushpins in the document. This will format the newly created pushpin in the following ways:
- Permanently pin the pushpin in the document (this is only necessary if you invoked the
setDraggableById
function in step 4) - Unselect the selected pushpin.
- Update the pushpin data with the data generated in the server.