Migrating from Micrio 3.x to 4.x Client 4.x
This page is about the Micrio client version 4. Use the links below to navigate to alternative versions.
This guide only applies to upgrading existing custom JS and CSS implementations in your own website using Micrio 3.x and older to version 4.x.
If you don't know what that is, or if you are simply using Micrio out of the box without any customizations, this article is not for you.
If you do have a Micrio implementation inside your own website which makes use of the Micrio API, and/or has custom CSS, please read on.
Should I upgrade?
Each Micrio JavaScript major version has a stable working release:
- Version 1.x (2015-2019): Micrio 1.9
- Version 2.x (2019-2020): Micrio 2.9
- Version 3.x (2020-2021): Micrio 3.3
- Version 4.x (2022): Micrio 4.1
This means that Micrio projects using those versions will always keep working as they are. Since Micrio only uses standard browser functions, older versions will not suddenly stop working at some point in time.
If you have a current running Micrio implementation in your own site, and it works well, there is no need to upgrade to Micrio 4.
We also still offer limited support on the previous major release, in this case Micrio 3.3. If you find any bugs, please contact us.
When should I upgrade?
There are a few reasons where upgrading makes sense:
- You want to use newly added features, like petapixel viewing support or built-in swipeable galleries
- You are using Micrio on many places inside your website (ie. a collection viewer), and you want to be sure you are running the latest and greatest Micrio version for performance or code cleanliness reasons
If either of these questions can be answered with "Yes", this article is for you.
What's changed?
Micrio 4.0 comes with quite some changes under the hood compared to Micrio 3.x, resulting in changed HTML/CSS, and a new JavaScript API.
1. HTML & CSS
Micrio 4.0 has a slightly different HTML DOM model compared to Micrio 3.x.
All changes to primary elements are below in this table. If an element is not listed here, it hasn't changed.
NOTE: &
refers to the main Micrio element
HTML element | 3.x CSS selector | 4.0 CSS selector |
---|---|---|
All Micrio icon buttons | button.micrio-icon | button.micrio-action |
Main Micrio element | .micrio-container | micr-io |
Image marker | & > micrio-markers > micrio-marker | & > .micrio-markers > .marker |
Custom marker classnames from the editor (ie red ) | & micrio-marker.class-red | & .marker.red |
Marker popup | & > micrio-interface > micrio-marker-popup | & > .marker-popup |
Minimap | & > micrio-interface > canvas.minimap | & > canvas.minimap |
Image info panel | & > micrio-interface > header.micrio-image-info | & > details |
Control buttons | & > micrio-interface > aside.controls | & > aside.controls |
Video tour controls | & > micrio-interface > micrio-media | & > div.tour |
Marker tour controls | & > micrio-interface > micrio-marker-tour | & > div.tour |
Full-window popover | & > micrio-popover > figure.micrio-popover | & > div.popover > section |
As you can see, it's not all that different. If you are only using custom CSS for your Micrio implementations, upgrading can be done quickly by updating your CSS selectors.
Do mind to double check your changes: it's possible some underlying HTML of the main selected element has also changed, for instance the marker popup HTML.
2. JavaScript (& TypeScript)
Micrio 4.0 has been rewritten from scratch, for the following reasons:
Upgrading from pure JavaScript to pure TypeScript
This allows for full typing and more optimized releases, making it much harder to introduce "stupid" bugs from our end.
It might also be one step closer to making the Micrio client Open Source in the (definitely not near) future.
Incorporating the Svelte Store logic into Micrio
This is something a lot of front-end UI frameworks like React, Vue, and Svelte use: Based on arbitrary JSON data, the interface is set to represent the data, instead of the developer reading the data, and then programatically saying "Ok, the user clicked a marker, now show the marker popup!".
This makes Micrio reactive state oriented instead of imperative. These are complicated words to describe the API approach, which will be demonstrated below.
2.1. No more new Micrio()
Since Micrio makes full use of the CustomElements browser API, it actually became a HTML Element, instead of added functionality to a standard element.
This means that the Micrio
JavaScript constructor is now no longer directly callable.
If you want to create a Micrio instance in pure JS, this is however still possible. Let's say you already have the image ID, and original image width and height.
In 3.x, you would use this (putting it into the HTML <body>
):
const micrio = new Micrio({
id: 'abcde',
width: 1000,
height: 1000,
container: document.body
});
This would auto-load everything, and place the newly created <micr-io>
element in the document.
In 4.x, you would use this:
// This already fully instances a new Micrio useable container
const micrio = document.createElement('micr-io');
// The .open() call accepts a simple ID, or a full JSON Micrio info model
micrio.open({
id: 'abcde',
width: 1000,
height: 1000
});
// Put the element inside the main <body>
document.body.appendChild(micrio);
Not that different!
2.1.1 Querying the Micrio instance
To access an already instantiated Micrio instance, for 3.x, this was a .micrio
property on the main <micr-io>
tag:
const micrio = document.querySelector('micr-io').micrio;
Following the above, for 4.0 this is the main <micr-io>
tag itself:
const micrio = document.querySelector('micr-io');
2.1.2. Using the Typescript Declarations include
If your project uses TypeScript, be sure to include the Micrio declaration file into your project, so it will be seamlessly integrated in your IDE. Use it as such:
import type { HTMLMicrioElement } from 'Micrio';
// This gives you full type checking and any editor autocompletion
const micrio = document.querySelector('micr-io') as HTMLMicrioElement;
The following sections use the above Micrio JS reference as base micrio
.
2.2. The virtual camera
Good news here: this is mostly unchanged 😃
The only change is that camera.setCoo()
now takes 3 arguments (x
, y
and scale
), instead of a single array [x,y,scale]
.
The rest of the camera API is still the same. See the API documentation pages for more information on how to use it.
Flying to a certain viewport is still done like so:
// This returns a promise which is resolved when the animation is done
// Or throws an error when an animation is interrupted
await micrio.camera.flyToView([.25,.25,.75,.75]);
console.log('ok, done!');
2.3. Marker and tour APIs
This is the largest change, API-wise.
If you are unfamiliar with stores, basically they are a subscribable variable, which you can get and set, but also hook to any changes to this variable.
For more technical documentation, please see the 4.0 API docs here:
- The Micrio State management API doc
- The SvelteStore API doc, including a full list of available store variables in Micrio 4.1
In this document, we will focus on the practicalities of upgrading.
2.3.1. Markers
Where in a previous Micrio version you would open a marker like this:
// Markers are propagated to JS instances on image load
const marker = micrio.modules.markers.items[0];
// Let's open the marker
marker.open();
// And close it again after 5 seconds
setTimeout(() => { marker.close() }, 5000);
This works well, and is very simple. On load, the Micrio JSON data containing the image markers is propagated to JavaScript classes, giving each marker its own JavaScript instance, having methods as .open()
and .close()
.
However, this load operation is done only once. If you want to dynamically add or remove markers, things get dirty very quickly since the API to add or remove markers should also be made (and documented).
In 4.0, the entire interface is based on pure JSON data, and there are no such things as wrapped JS instances.
To do the above example in 4.0:
// The first marker of the current active shown MicrioImage
const marker = micrio.$current.$data.markers[0];
// Open the marker simply by setting its original JSON data as `state.marker`
micrio.state.marker.set(marker);
// Close it after 5 seconds
setTimeout(() => { micrio.state.marker.set(undefined) }, 5000);
2.3.2. Marker Tours & Video Tours
For tours, use the micrio.state.tour
store variable. Since you can only have 1 main active tour at the time (disregarding video tours embedded inside a marker), it makes sense to have a single store for both types.
Starting a tour in 3.x:
// A marker tour
micrio.modules.markerTours[0].start();
// The current marker tour:
const currentTour = micrio.modules.markers.currentTour;
// A video tour
micrio.modules.tours[0].start();
// The current video tour:
const currentVideoTour = micrio.modules.currentTour;
In 4.x:
// The current image JSON data
const data = micrio.$current.$data;
// Starting the first marker tour
micrio.state.tour.set(data.markerTours[0]);
// Starting the first video touir
micrio.state.tour.set(data.tours[0]);
// The current tour (JSON):
const currentTour = micrio.state.$tour;
As you can maybe already tell, this allows for a much cleaner setup, since only one tour can be active, and switching between different tours automatically gets correctly picked up by the UI.
2.3.3. Tour APIs
Another thing that has changed, is how to control the tours using the API.
Marker tours
Marker tours are now only known a JSON object: micrio.state.$tour
.
However, this object has a special getter/setter .currentStep
, which is the current step the user is on, and can be set to a value of your own:
// The current marker tour step
micrio.state.$tour.currentStep;
// Go to the next step
micrio.state.$tour.currentStep++;
// Go to the 4th step
micrio.state.$tour.currentStep = 4;
Video tours
Video tours are a special case. Since they behave very much like <audio>
and <video>
, they also are implemented as such, sharing the most important methods and properties of HTMLMediaElement
:
property | type | description |
---|---|---|
.pause() | function | Pauses a currently running tour |
.play() | async function | Plays a video tour |
.duration | number | The total tour duration in seconds |
.currentTime | number | The current playback time in seconds |
.paused | boolean | The current tour is paused |
The currentTime
property may also be set to a desired timestamp in seconds, which will set the video tour to that point in time.
An example:
// Let's start a video tour
micrio.state.tour.set(micrio.$current.$data.tours[0]);
// Get the media controller object
const tourMedia = micrio.state.media;
// Pause the tour
tourMedia.pause();
// Skip the tour to 4 seconds
tourMedia.currentTime = 4;
// Continue the tour
tourMedia.play();
2.4. Image navigating
Not a lot has changed here. If you want to manually navigate to a new Micrio image, here's how to do it:
3.x:
micrio.modules.navigator.goto('your-ID');
4.0:
micrio.open('your-ID');
The result is the same: a crossfade will take place to the requested image, once the required data has been loaded.
2.5. Events
2.5.1. Behavioral events (markers, tours, camera)
With Micrio 3.x, if you want to know when a user has opened a marker, or started a tour, or moved the camera, you would set an EventListener
for this.
Micrio 4.0 still fully supports this, so you can still use this method to do any custom event handling. Please see the Micrio JS Events API article for more details about this.
The only change is that all different kinds of tour events are now bundled:
3.x | 4.0 |
---|---|
markerTours-(start|stop|step) | tour-(start|stop|step) |
tours-(start|event|stop) | tour-(start|event|stop) |
And the event.detail
argument will be the JSON objects of the corresponding tour.
2.5.2. Lifecycle events: Using store readers to get updates
With the added state possibilities, it is also possible to get updates through them. This is a little more robust than listening to arbitrary events.
Micrio 3.x has a pretty detailed event lifecycle.
Since all of these events fire on the main <micr-io>
element, this quickly becomes complicated when you're working with multiple images (ie. a multi-image tour): the load
event would fire for each image loaded, so as a developer you have to keep check on which image this is.
These lifecycle events have been reduced in Micrio 4.0 to be only load
and show
:
load
only fires once, when data of the first image in the Micrio controller has been downloadedshow
also fires once, when the first image frame has been succesfully drawn in the browser
For more fine grained data loading/updating control, see the next section.
2.5.3. Subscribing to image switching, data loading and changes
If you want to watch for image switches inside Micrio, you can watch micrio.current
:
micrio.current.subscribe(image => {
console.log('Opening image', image);
});
If you want to know when an individual image data has been loaded, you can use the .info
and .data
store variables of the individual MicrioImage
.
An example, on opening an image and watching for load events:
// This returns a new MicrioImage, and also sets this as micrio.$current
const image = micrio.open('abcde');
// Subscribe to .info property: the image data (width, height, etc)
// This change will trigger once the needed JSON has been downloaded
image.info.subscribe(info => {
// When setting the subscriber, it will immediately fire the current value
// So it can also be undefined
if(!info) return;
// Log what we got
console.log('Got image info!', info.width, info.height);
});
// Subscribe to .data: the CultureData (markers, tours, audio)
// This also triggers once the JSON has been downloaded
image.data.subscribe(data => {
console.log('Got image data!', data);
});
The image.info
property is a Readable
, meaning that it's read-only.
However, the image.data
is Writable
, meaning that you can update the data yourself.
2.5.4. Changing or updating marker data yourself
To set your own custom data overwriting anything currently loaded, set
the image.data
store:
micrio.$current.data.set({
"markers": [
{
"title": "This is a test marker!",
"x": .5,
"y": .5
}
]
})
Or adding a marker to an existing loaded data object, use the update
function:
micrio.$current.data.update(data => {
data.markers.push({
"title": "This is a newly added marker",
"x": .5,
"y": .5
});
return data;
})
This will immediately be visible!
Concluding
In this guide, we have glossed over all major changes in the Micrio 3.x vs 4.0 APIs. Upgrading existing projects should be doable using this guide and all other available documentation.
However, if you have any more specific questions about this, contact us!