Genie Discord forum
![Author Avatar](https://cdn.discordapp.com/avatars/690223941708415031/c7a97db56b94a6b760cd6b0375580431.png?size=512)
I'm building an application centered around a Cesium viewer. The Cesium viewer runs on the frontend, along with all of my TypeScript code that adds camera transforms, entities and graphics, etc.
In a previous iteration of this application, I started with a SolidJS template, which made it very easy to add Cesium as a dependency and start building the frontend.
- What's the best way to incorporate JavaScript libraries such as Cesium into a Genie app? Essentially, how do I do the equivalent of
pnpm add cesium
such that I can call its API fromapp.jl
? - I know I can add javascript files to the
public
folder which will be automatically imported, but how do I actually call them? Does this work with TypeScript files?
I suspect that I'll end up just using the Genie
backend as an API and figure out how to fit it into my SolidJS template, but I wanted to know if there was a way that I could make use of the Stipple.jl
frontend instead.
![Author Avatar](https://cdn.discordapp.com/avatars/743412727464067154/bc30abeb49653e9978c0f7c90f4486a8.png?size=512)
You might want to use a layout so that you can edit the page headers and include anything you need. You can use the Stipple.ReactiveTools.DEFAULT_LAYOUT as a base, like I did here
https://github.com/BuiltWithGenie/ComponentGallery/blob/main/layout.html
then you include it with @page("/", "ui.jl", layout = "layout.html")
There's probably other ways, perhaps @hhaensel can provide some
![Author Avatar](https://cdn.discordapp.com/avatars/960642755799941150/8454099b3f43462890d75bc9c4cd572d.png?size=512)
Using Cesium is possible. Following the installation instruction from https://cesium.com/learn/cesiumjs-learn/cesiumjs-quickstart/ I composed this little app:
using GenieFramework
@genietools
cesium_token = "your token"
cesium_module() = [
script(type = "module", "
Cesium.Ion.defaultAccessToken = '$cesium_token';
// Initialize the Cesium Viewer in the HTML element with the `cesiumContainer` ID.
const viewer = new Cesium.Viewer('cesiumContainer', {
terrain: Cesium.Terrain.fromWorldTerrain(),
});
// Fly the camera to San Francisco at the given longitude, latitude, and height.
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(-122.4175, 37.655, 400),
orientation: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-15.0),
}
});
// Add Cesium OSM Buildings, a global 3D buildings layer.
const buildingTileset = await Cesium.createOsmBuildingsAsync();
viewer.scene.primitives.add(buildingTileset);
")
]
cesium_head = [
script(src = "https://cesium.com/downloads/cesiumjs/releases/1.113/Build/Cesium/Cesium.js", ),
link(href = "https://cesium.com/downloads/cesiumjs/releases/1.113/Build/Cesium/Widgets/widgets.css", rel = "stylesheet", )
]
@app begin
@in mybutton = false
@onbutton mybutton begin
println("button clicked")
end
end
@deps cesium_module
const UI = Ref(ParsedHTMLString[])
UI[] = [
row(cell(class = "st-module",
h1("My first Cesium App")
))
row(cell(class = "st-module", [
h3("Demo")
htmldiv(id="cesiumContainer")
]))
]
ui() = UI[]
route("/") do
page(@init, ui, head_content = join(cesium_head))
end
up(open_browser = true)
# verify page content at the command line
page(@init, ui, head_content = join(cesium_head)) |> println
![](https://cdn.discordapp.com/attachments/1195485588795699341/1196962357914648657/image.png?ex=65b98910&is=65a71410&hm=ca322caa2219bfe247c7a813b8bb64f003927a5d77f4c116ed5a2101b1bb0dd4&)
![Author Avatar](https://cdn.discordapp.com/avatars/960642755799941150/8454099b3f43462890d75bc9c4cd572d.png?size=512)
Note that here I used the explicit page()
function rather than the @page
macro, because the latter supports the head_content kwarg other than the macro.
![Author Avatar](https://cdn.discordapp.com/avatars/960642755799941150/8454099b3f43462890d75bc9c4cd572d.png?size=512)
You could also design your own layout as @Pere mentioned above, but this version was faster for me.
![Author Avatar](https://cdn.discordapp.com/avatars/743412727464067154/bc30abeb49653e9978c0f7c90f4486a8.png?size=512)
Thanks for the great example @hhaensel , I've added a doc page on this
https://learn.genieframework.com/docs/reference/reactive-ui/adding-js-libraries
![Author Avatar](https://cdn.discordapp.com/avatars/960642755799941150/8454099b3f43462890d75bc9c4cd572d.png?size=512)
I found a way of using a modified DEFAULT_LAYOUT together with the page macro. The point is that v-if:'isready' hides the element when the init code runs and hence the initialisation of cesium fails. A workaround is to delay script execution to when the app is ready. So the new way of defining cesium_module()
would be:
cesium_module_text = """
// Your access token can be found at: https://ion.cesium.com/tokens.
// Replace `your_access_token` with your Cesium ion access token.
Cesium.Ion.defaultAccessToken = '$cesium_token';
// Initialize the Cesium Viewer in the HTML element with the `cesiumContainer` ID.
const viewer = new Cesium.Viewer('cesiumContainer', {
terrain: Cesium.Terrain.fromWorldTerrain(),
});
// Fly the camera to San Francisco at the given longitude, latitude, and height.
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(-122.4175, 37.655, 400),
orientation: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-15.0),
}
});
// Add Cesium OSM Buildings, a global 3D buildings layer.
const buildingTileset = await Cesium.createOsmBuildingsAsync();
viewer.scene.primitives.add(buildingTileset);
"""
cesium_module() = [script(Stipple.js_initscript("""
newscript = document.createElement('script')
newscript.text = $(json(cesium_module_text))
newscript.type = 'module'
document.head.appendChild(newscript)
"""))]
![Author Avatar](https://cdn.discordapp.com/avatars/960642755799941150/8454099b3f43462890d75bc9c4cd572d.png?size=512)
@Pere let's wait for the PR to be accepted and then modify your docs accordingly
![Author Avatar](https://cdn.discordapp.com/avatars/690223941708415031/c7a97db56b94a6b760cd6b0375580431.png?size=512)
Holy moly! This is so much more helpful than I could have anticipated. Thank you both so much!
![Author Avatar](https://cdn.discordapp.com/avatars/690223941708415031/c7a97db56b94a6b760cd6b0375580431.png?size=512)
Changed the channel name: SOLVED Using TypeScript and managing dependencies
![Author Avatar](https://cdn.discordapp.com/avatars/743412727464067154/bc30abeb49653e9978c0f7c90f4486a8.png?size=512)
@hhaensel there's some caveats, like if you want to call the JS code from a Vue component you need to add it with @methods as I had to do with this tailwind example https://discord.com/channels/774897545717219328/1197340350075916328 . I'll need to do some thorough documentation about all this...
![Author Avatar](https://cdn.discordapp.com/avatars/960642755799941150/8454099b3f43462890d75bc9c4cd572d.png?size=512)
Agree, but as a starting point for people who are familiar with js it's probably already helpful ...
![Author Avatar](https://cdn.discordapp.com/avatars/690223941708415031/c7a97db56b94a6b760cd6b0375580431.png?size=512)
As a stopgap, you could probably just have a FAQ or "how do I..." page that contains the various examples we've come up with here along with the current Genie version number (so people know when/if it's outdated). I would hate for you to spend time on thorough documentation for this especially if you change how it works in future releases (e.g. if you provided a macro that toggled TailwindCSS instead of having the user copy-paste all that stuff).
![Author Avatar](https://cdn.discordapp.com/avatars/743412727464067154/bc30abeb49653e9978c0f7c90f4486a8.png?size=512)
We use the code examples for that, I was planning to add the Tailwind example there ๐. The versioning is a good idea though, although right now we just try to make sure they work on the latest versions https://learn.genieframework.com/docs/examples/reactive-ui/mapbox