This commit is contained in:
Alan Rynne
2021-07-08 17:35:42 +02:00
parent ee9f45c23c
commit 9fc6bb1923
11 changed files with 491 additions and 70 deletions
+101 -19
View File
@@ -2,45 +2,127 @@
using Speckle.Core.Kits;
using Speckle.Core.Credentials;
using Speckle.Core.Api;
using System.Threading;
using Objects;
using Speckle.Core.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
using Objects.Geometry;
using Objects.Primitive;
using Speckle.Core.Transports;
using System.Linq;
namespace CSharpStarter
{
class Program
{
// Running this program will pull the latest commit from the main branch
// of the specified stream and duplicate it inside a different branch.
// (branch should exist already or the program will fail)
static void Main(string[] args)
{
Console.WriteLine("Hello Speckle!");
// The id of the stream to work with (we're assuming it already exists in your default account's server)
var streamId = "c1800d795b";
// The name of the branch we'll send data to.
var branchName = "processed";
// Get default account on this machine
var defaultAccount = AccountManager.GetDefaultAccount();
// Or get all the accounts and manually choose the one you want
// var accounts = AccountManager.GetAccounts();
// var defaultAccount = accounts.ToList().FirstOrDefault();
// Create a new "base" object
var commitObj = new Base();
// Base objects are dynamic, so you can assign any properties just like a Dictionary
commitObj["myProp"] = "myPropValue";
commitObj["myOtherProp"] = new List<string> { "A", "list", "of", "values" };
// Authenticate using the account
var client = new Client(defaultAccount);
var boxes = new List<Point>();
for (int i = 0; i < 10; i++)
// Get the main branch with it's latest commit reference
var branch = client.BranchGet(streamId, "main", 1).Result;
// Get the id of the object referenced in the commit
var hash = branch.commits.items[0].referencedObject;
// Create the server transport for the specified stream.
var transport = new ServerTransport(defaultAccount, streamId);
// Receive the object
var receivedBase = Operations.Receive(hash, transport).Result;
// Process the object however you'd like
Console.WriteLine("Received object:" + receivedBase);
// Sending the object will return it's unique identifier.
var newHash = Operations.Send(receivedBase, new List<ITransport> { transport }).Result;
// Create a commit in `processed` branch (it must previously exist)
var commitId = client.CommitCreate(new CommitCreateInput()
{
for (int j = 0; j < 10; j++)
{
boxes.Add(new Point(i, j, 0));
}
}
commitObj["boxes"] = boxes;
// Send the object to Speckle, get back the commit id
var commitId = Helpers.Send("2d9b814ed6", commitObj, "Upload from my console app", null, 0, defaultAccount, false).Result;
branchName = branchName,
message = "Automatic commit created by AEC Tech Demo C# console app.",
objectId = newHash,
streamId = streamId,
sourceApplication = "AEC Tech C# Script"
// To receive the latest commit
var receivedObj = Helpers.Receive("2d9b814ed6", defaultAccount).Result;
Console.WriteLine(receivedObj["myProp"]);
}).Result;
Console.WriteLine($"Successfully created commit with id: {commitId}");
// Remember to dispose of the client once you've finished with it.
client.Dispose();
}
static void ReactToCommit(string[] args)
{
// Get default account on this machine
var defaultAccount = AccountManager.GetDefaultAccount();
var client = new Client(defaultAccount);
var streamId = "42c06de34f";
var branch = client.BranchGet(streamId, "main", 1).Result;
var hash = branch.commits.items[0].referencedObject;
var exit = false;
client.OnCommitCreated += (sender, e) =>
{
// Ignore commits from any branch other than 'main'
if (e.branchName != "main") return;
Console.WriteLine("Commit was created in Main! Processing data...");
// Create the server transport for the specified stream.
var transport = new ServerTransport(defaultAccount, streamId);
// Receive the object
var receivedBase = Operations.Receive(hash, transport).Result;
var newHash = Operations.Send(receivedBase, new List<ITransport> { transport }).Result;
// Create a commit in `processed` branch (it must previously exist)
var commitId = client.CommitCreate(new CommitCreateInput()
{
branchName = "processed",
message = "Automatic commit created by AEC Tech Demo C# console app.",
objectId = newHash,
streamId = streamId,
sourceApplication = "C#"
}).Result;
Console.WriteLine($"Successfully created commit with id: {commitId}");
exit = true;
};
// Subscribe to commits created on the stream.
client.SubscribeCommitCreated(streamId);
// HACK: This is a super hacky way to get a C# console app to wait for an event to happen.
// YOU SHOULD NOT DO THIS IN A PRODUCTION APPLICATION 🤣
Console.WriteLine("Waiting for commit created event...");
while (!exit)
{
Thread.Sleep(500);
Console.WriteLine("Still waiting...");
}
// Remember to dispose of the client once you've finished with it.
client.Dispose();
}
}
}
+2 -10
View File
@@ -1,12 +1,4 @@
# Using Speckle Core
# AEC C# Starter
```
dotnet new console -f netcoreapp3.1
```
Add Speckle.Core
```
dotnet add package Speckle.Core --version 2.1.22
```
>
+14
View File
@@ -0,0 +1,14 @@
# AEC Tech Python Starter
# Usage
This is a demo script
# Prerequisites
Install `specklepy`
```
pip install specklepy
```
+25 -20
View File
@@ -1,51 +1,56 @@
# Running this script will pull the latest commit from the main branch
# of the specified stream and duplicate it inside a different branch.
# (branch should exist already or the script will fail
from specklepy.api.client import SpeckleClient
from specklepy.api.credentials import get_default_account, get_local_accounts
from specklepy.transports.server import ServerTransport
from specklepy.api import operations
# The id of the stream to work with (we're assuming it already exists in your default account's server)
streamId = "c1800d795b"
branchName = "processed"
# Initialise the Speckle client pointing to your specific server.
client = SpeckleClient(host="https://speckle.xyz")
# Get the default account
# If you have more than one account, or the account is not the default, use get_local_accounts
account = get_default_account()
# If you have more than one account, or the account is not the default, use get_local_accounts
# accounts = get_local_accounts()
# account = accounts[0]
# Authenticate using the account token
client.authenticate(token=account.token)
# Your account email
print('Welcome!!',account.userInfo.email, account.serverInfo.url)
# use that stream id to get the stream from the server
streamId = "42c06de34f"
# Get the main branch with it's latest commit reference
branch = client.branch.get(streamId, "main", 1)
# Get the id of the object referenced in the commit
hash = branch.commits.items[0].referencedObject
# next create a server transport - this is the vehicle through which you will send and receive
# Create the server transport for the specified stream.
transport = ServerTransport(client=client, stream_id=streamId)
# this receives the object back from the transport.
# the received data will be deserialised back into a `Block`
# Receive the object
received_base = operations.receive(obj_id=hash, remote_transport=transport)
for list in received_base["@data"]:
for item in list:
item.z += 1
# The received object, process it as you wish.
print("Received object:", received_base)
# this serialises the modified points and sends it to the transport
hash = operations.send(base=received_base, transports=[transport])
newHash = operations.send(base=received_base, transports=[transport])
# you can now create a commit on your stream with this object
commit_id = client.commit.create(
stream_id=streamId,
branch_name="python",
branch_name=branchName,
object_id=hash,
message="Points were modified by AECTechDemo.py script",
message="Automatic commit created by AEC Tech Demo by AECTechDemo.py script",
source_application="AEC Tech Python Script"
)
print("Successfully created commit with id:", commit_id)
print("Successfully created commit with id: ", commit_id)
+3 -1
View File
@@ -1 +1,3 @@
# AEC Tech Presentation Repo
# AEC Tech Speckle Repo
This repo contains all code and files related to
+27
View File
@@ -0,0 +1,27 @@
# Starter Speckle web viewer project
> This is a basic `html/js/css` webpage that uses our `@speckle/viewer` package and some basic queries through our `graphQL` API.
> If you want to know more about Speckle as a developer platform, check our [Developer Docs](https://speckle.guide/dev)
The app allows you to view the main geometry of a stream and combine it with different design options (which would exist as different `branches` in the stream)
![alt](https://link)
The stream will be organised as follows:
- `main` branch: Will contain the main geometry.
- Any other existing branches should contain the different design options to visualise along side the `main` geometry.
![Stream branches screenshot](https://link)
## Usage
This demo should run directly in your browser. Just double click the `index.html` file on this folder.
## Repo structure
- `index.html`: Main html file
- `app.js`: Main `js` module for the website
- `speckleQueries.js` contains several `graphQL` queries we'll be using.
- `speckleUtils.js` contains the functions to interact with the Speckle API.
- `styles.css`: Styles to used by `index.html`
+139 -8
View File
@@ -1,22 +1,153 @@
let token = "096315ee1bf8c961444b270746becd1e8474baa79e"
let objUrl =
"http://localhost:3000/streams/2d9b814ed6/objects/d679e6ff0efb8c9c102b8f8136b0f68a"
import { getStreamCommits, getUserData } from "./speckleUtils.js"
let token = null
let streamId = null
let stream = null
let mainBranch = null
let beams = null
let columns = null
let selectedBeam = null
let selectedColumn = null
let isDropdownLoaded = false
document
.getElementById("alternative-selector")
.addEventListener("change", onBeamAlternativeSelected)
document
.getElementById("alternative-selector-2")
.addEventListener("change", onColumnAlternativeSelected)
document.getElementById("reloadButton").addEventListener("click", reload)
let objUrl = (streamId, objId) =>
`https://speckle.xyz/streams/${streamId}/objects/${objId}`
// Create the viewer instance
let viewer = new window.Speckle.Viewer({
container: document.getElementById("viewer"),
showStats: true
showStats: false
})
viewer.loadObject(objUrl, token)
viewer.interactions.zoomExtents(0.95, false)
// Handle selection events
viewer.on("select", objects => {
console.info(`Selection event. Current selection count: ${objects.length}.`)
console.log(objects)
let el = document.getElementById("selection-area")
let jv = window["w-jsonview-tree"]
jv(objects, el, { expanded: false })
})
// Handle double click events
viewer.on("object-doubleclicked", obj => {
console.info("Object double click event.")
console.log(obj ? obj : "nothing was doubleckicked.")
})
async function reload() {
document.getElementById("reloadButton").classList.add("is-loading")
streamId = document.getElementById("stream-input").value // Get the value of the stream input
token = document.getElementById("token-input").value // Get the value of the token input
await fetchStreamData() // Fetch the stream data
if (!isDropdownLoaded) {
populateDropdown("alternative-selector", beams)
populateDropdown("alternative-selector-2", columns) // If it's the first time, populate the dropdown too.
}
await reloadViewer() // Reload the viewer once the stream data has been fetched
document.getElementById("reloadButton").classList.remove("is-loading")
}
// This will add an option for each branch in the alternatives list, and bind the referenced object id as the value
function populateDropdown(id, data) {
let select = document.getElementById(id)
data.forEach(alt => {
if (alt.commits.items.length == 0) return
var opt = document.createElement("option")
opt.appendChild(document.createTextNode(alt.name))
opt.value = alt.commits.items[0].referencedObject
select.appendChild(opt)
})
isDropdownLoaded = true
}
// Get the stream data and process it
//
async function fetchStreamData() {
await getStreamCommits(streamId, 1, null, token).then(str => {
stream = str.data.stream
// Split the branches into "main" and everything else
mainBranch = stream.branches.items.find(b => b.name == "main")
beams = stream.branches.items.filter(b => b.name.startsWith("beam"))
columns = stream.branches.items.filter(b => b.name.startsWith("column"))
console.log("main branch", mainBranch)
console.log("beam options", beams)
console.log("column options", columns)
})
}
// Reload of the viewer data, remove all objects, reload everything and zoom.
async function reloadViewer() {
viewer.sceneManager.removeAllObjects()
await viewer.loadObject(
objUrl(streamId, mainBranch.commits.items[0].referencedObject)
)
console.log(`Loaded latest commit from branch "${mainBranch.name}"`)
// Load beam if selected
if (selectedBeam) {
console.log("alternative is selected, should load", selectedBeam)
await viewer.loadObject(objUrl(streamId, selectedBeam))
console.log("loaded alternative")
}
// Load column if selected
if (selectedColumn) {
console.log("alternative is selected, should load", selectedColumn)
await viewer.loadObject(objUrl(streamId, selectedColumn))
console.log("loaded alternative")
}
viewer.interactions.zoomExtents(0.95, true)
}
// Reload viewer every time an alternative is selected in the dropdown.
async function onColumnAlternativeSelected(event) {
const selection = event.target.value.substring(
event.target.selectionStart,
event.target.selectionEnd
)
selectedColumn = selection
console.log("selected", selectedColumn)
document.getElementById("reloadButton").classList.add("is-loading")
await reloadViewer()
document.getElementById("reloadButton").classList.remove("is-loading")
}
async function onBeamAlternativeSelected(event) {
const selection = event.target.value.substring(
event.target.selectionStart,
event.target.selectionEnd
)
selectedBeam = selection
console.log("selected", selectedBeam)
document.getElementById("reloadButton").classList.add("is-loading")
await reloadViewer()
document.getElementById("reloadButton").classList.remove("is-loading")
}
// Hack to prevent scene from loosing current zoom.
viewer.sceneManager._postLoadFunction = () => {
viewer.reflectionsNeedUpdate = true
}
document.getElementById("take-screenshot").addEventListener("click", () => {
console.log("screenshot clickd")
let data = viewer.interactions.screenshot() // transparent png.
let pop = window.open()
pop.document.title = "SpeckleStreamScreenshot"
pop.document.body.style.backgroundColor = "grey"
let img = new Image()
img.src = data
pop.document.body.appendChild(img)
})
+67 -4
View File
@@ -7,14 +7,77 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Speckle Web Starter</title>
<script src="https://unpkg.com/@speckle/viewer"></script>
<script src="https://cdn.jsdelivr.net/npm/w-jsonview-tree@1.0.24/dist/w-jsonview-tree.umd.js"></script>
<script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="viewerParent">
<div id="viewer"></div>
</div>
<script src="app.js"></script>
<div id="viewerParent" class="hero is-fullheight">
<div id="viewer" class=""></div>
<div class="box" id="menu">
<div class="content">
<h3 class="title has-text-info">Speckle - AEC Tech Demo</h3>
<p class="subtitle is-size-7">Compare different design options on a stream</p>
<div class="field has-addons">
<div class="control">
<input id="stream-input" class="input" type="text" placeholder="Your stream ID">
</div>
<div class="control">
<input id="token-input" class="input" type="text" placeholder="Your auth token">
</div>
<div class="control">
<button class="button is-info" id="reloadButton">Load</button>
</div>
</div>
<div class="field has-addons">
<div class="control">
<button class="button is-info" disabled>Beam options</button>
</div>
<div class="control is-expanded">
<div class="select is-fullwidth">
<select id="alternative-selector" class="is-loading">
<option selected>Select a beam option</option>
</select>
</div>
</div>
</div>
<div class="field has-addons">
<div class="control">
<button class="button is-info" disabled>Column options</button>
</div>
<div class="control is-expanded">
<span class="select is-fullwidth">
<select id="alternative-selector-2" class="is-loading">
<option selected>Select a column option</option>
</select>
</span>
</div>
</div>
<button id="take-screenshot" class="button is-fullwidth is-info is-small">Take screenshot</button>
</div>
</div>
<div class="box" id="selected-panel">
<div class="content" id="selection-area-parent">
<h3 class="title has-text-info">Selected objects
</h3>
<p class="subtitle is-size-7">Data from selected objects</p>
<p id="selection-area"></p>
</div>
</div>
<div class="bottom-left">
<a class="button is-info is-small" href="http://speckle.systems">
<span>Powered by Speckle</span>
</a>
</div>
<div class="bottom-right">
<a class="button is-small is-info is-rounded" href="http://speckle.guide">
<span class="icon">
<i class="fas fa-question"></i>
</span></a>
</div>
<script type="module" src="app.js"></script>
</body>
</html>
+38
View File
@@ -0,0 +1,38 @@
export const userInfoQuery = () => `query {
user {
name
},
serverInfo {
name
company
}
}`
export const streamCommitsQuery = (streamId, itemsPerPage, cursor) => `query {
stream(id: "${streamId}"){
branches {
totalCount
cursor
items {
name
commits(limit: 1){
items {
referencedObject
}
}
}
}
}
}`
export const streamSearchQuery = search => `query {
streams(query: "${search}") {
totalCount
cursor
items {
id
name
updatedAt
}
}
}`
+39
View File
@@ -0,0 +1,39 @@
import {
streamCommitsQuery,
streamSearchQuery,
userInfoQuery
} from "./speckleQueries.js"
export let SERVER_URL = "https://speckle.xyz"
// Calls the GraphQL endpoint of the Speckle server with a specific query.
export async function speckleFetch(query, token) {
console.log("fetching with token ", token)
if (token)
try {
var res = await fetch(`${SERVER_URL}/graphql`, {
method: "POST",
headers: {
Authorization: "Bearer " + token,
"Content-Type": "application/json"
},
body: JSON.stringify({
query: query
})
})
return await res.json()
} catch (err) {
console.error("API call failed", err)
}
else return Promise.reject("You are not logged in (token does not exist)")
}
// Fetch the current user data using the userInfoQuery
export const getUserData = token => speckleFetch(userInfoQuery(), token)
// Fetch for streams matching the specified text using the streamSearchQuery
export const searchStreams = (e, token) => speckleFetch(streamSearchQuery(e))
// Get commits related to a specific stream, allows for pagination by passing a cursor
export const getStreamCommits = (streamId, itemsPerPage, cursor, token) =>
speckleFetch(streamCommitsQuery(streamId, itemsPerPage, cursor), token)
+36 -8
View File
@@ -1,15 +1,43 @@
@import "https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css";
body {
margin: 0;
padding: 0;
}
#viewerParent {
min-width: 100vw;
min-height: 100vh;
background-color: whitesmoke !important;
}
#viewer {
min-width: 100vw;
min-height: 80vh;
border: 1px solid black;
width: 100vw;
height: 100vh;
}
#menu {
position: fixed;
display: flex;
flex-grow: 1;
flex-direction: column;
margin: 1em;
}
#selected-panel {
position: absolute;
top: 0em;
right: 0em;
width: 450px !important;
margin: 1em;
max-height: 50% !important;
overflow-y: auto;
}
.bottom-left {
position: fixed;
bottom: 0;
margin: 1em;
}
.bottom-right {
position: fixed;
bottom: 0;
right: 0;
margin: 1em;
}