Messages
WebSockets API is a connected API between a client (generally a browser) and MyScript Cloud or MyScript Server.
Opening the WebSocket
Open a websocket on this URL wss://cloud.myscript.com/api/v4.0/iink/document
Creating a new iink document,
The client sends a createNewContentPackage
message with an applicationKey
.
Initialization with HMAC HandShake
If the application hmac security option is set (default mode), a HMAC Challenge must be answered before making any operation in the iink document.
{
type: "newContentPackage",
applicationKey: "XXXX-XXXXXX-XXXXX-XXXX",
xDpi: 90,
yDpi: 90,
viewSizeHeight: 800,
viewSizeWidth: 1023
}
The server sends an ack message containing a hmacChallenge
:
The inkSessionId
is used to reconnect to the doc in case of connection failure.
{
type: 'ack',
hmacChallenge: 'XXXX-XXXXXX-XXXXX-XXXX',
iinkSessionId: 'YYYYYYYYYYYYYYYYYYYYY'
}
The browser computes the hmac with this challenge and the private key.
{
type: "hmac",
hmac: "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
}
Please find here a javascript example on how to compute the HMAC code.
Simple initialization (No HMAC HandShake)
Sequence if the application hmac security option is not set (refer to Administration interface),
{
type: "newContentPackage",
applicationKey: "XXXX-XXXXXX-XXXXX-XXXX",
xDpi: "90",
yDpi: "90",
viewSizeHeight: "800",
viewSizeWidth: "1023"
}
The server will send a simple ack message:
{
type: "ack"
}
Configuration
This message is optional. Depending on the content part type, you can configure the recognition language, the margins or the solver behavior.
{
type: 'configuration',
lang:'en_US',
math: {
solver: {
enable: true,
fractionalPartDigits: 3,
decimalSeparator: '.',
roundingMode: 'half up',
angleUnit: 'deg',
},
margin: {
top: 0,
left: 0,
right: 0
},
customGrammarId: 'MyGrammar'
},
text: {
margin:{
top: 0,
left: 0,
right: 0
},
guide: {
enable: true
},
configuration:{
customResources: ['MyResource1', 'MyResource2'],
customLexicon: ['MyWord1', 'MyWord2'],
addLKText: true
}
},
export: {
imageResolution: 300,
jiix: {
boundingBox: false,
text: {
chars: false,
words: true
}
strokes: true
}
}
}
Set Theme
The theme is the default style of the content. The theme property is a CSS given as a String
.
{
type: 'setTheme',
theme: 'ink {color: #00FF00; -myscript-pen-width: 1; -myscript-pen-fill-style: none;-myscript-pen-fill-color: #FFFFFF00;} .math {font-family: STIXGeneral;} .math-solved {font-family: STIXGeneral; color: #2E7D32;} .text { font-family: Open Sans; font-size: 10;}'
}
Set Pen Style
Set the pen style
{
type: 'setPenStyle',
style: '↵'
}
Set Pen Style Classes
Set the pen style classes
{
type: 'setPenStyleClasses',
styleClasses: ''
}
Creating a new part
The client must declare a new part. It can declare mimeTypes
which will be attached to the exported message.
If mimeTypes
are specified, the server will send exported message after each contentChanged
message.
{
"type":"newContentPart",
"contentType":"MATH",
"mimeTypes":["application/x-latex","application/mathml+xml"]
}
Sending Strokes
Sending a stroke
pointerType
can be “MOUSE”, “PEN” or “TOUCH”.
Timestamps are expressed in milliseconds.
p
(optional) is the pressure.
{
type: "addStrokes",
strokes: [
{
"id": 'pending-1',
"pointerType" : 'PEN',
"x": [273, 278, 281],
"y": [121, 128, 133],
"t": [3185.7900000000004, 3213.8150000000005, 3222.5350000000003],
"p": [1.3, 1.3, 1.3]
}
]
}
Pending stroke management
At this point, the stroke is injected in the engine and its states is ‘pending’. The engine will decide if the stroke is a gesture or not. It will then send an SVG Patch. If you draw the pending stroke, you will be able to remove it, during a next SVG Patch containing a REMOVE_ELEMENT action with the stroke id for the CAPTURE layer.
{
"type": "svgPatch",
"layer": "MODEL",
"updates":[
{ "type": "REMOVE_ELEMENT", "id": "pendingStroke-1" }
]
}
SVG Patch
Server sends SVG Patch to update the browser view.
A patch is composed of updates which can be:
- APPEND_CHILD
- REMOVE_ELEMENT
- REPLACE_ALL
- REPLACE_ELEMENT
- REMOVE_CHILD
- APPEND_CHILD
- INSERT_BEFORE
- REMOVE_ATTRIBUTE
- SET_ATTRIBUTE
As the display block is build by putting a MODEL
layer on top of a BACKGROUND
one, the layer
attribute in patch indicates the one to apply the patch.
Example:
{
"type":"svgPatch",
"layer":"MODEL",
"updates":[
{
"type": "APPEND_CHILD",
"parentId": "G7fb3e8086be0",
"svg": "<path id=\"i10000010035ff\" d=\"M198.76,56.45l-0.3-0.1l2.11-1.38l1.5-0.82l0.68-0.09l0.61"></path>\n"
},
{
"type": "REMOVE_ELEMENT",
"id": "G7fb3a2434abc"
},
{
"type": "REPLACE_ALL",
"svg": "..."
},
{
"type": "REPLACE_ELEMENT",
"id": "G7fb3e8086be1",
"svg": "..."
},
{
"type": "REMOVE_CHILD",
"parentId": "G7fb3e8086be1",
"index": 2
},
{
"type": "APPEND_CHILD",
"parentId": "G7fb3e8086be1",
"svg": "..."
},
{
"type": "INSERT_BEFORE",
"refId": "G7fb3e8086be1",
"svg": "..."
},
{
"type": "REMOVE_ATTRIBUTE",
"id": "G7fb3e8086be1",
"name": "..."
},
{
"type": "SET_ATTRIBUTE",
"id": "G7fb3e8086be1",
"name": "attributName"
"value": "A Value"
}
]
}
Content Changed
Server sends a contentChanged
message to the browser every time the content is modified.
{
"type":"contentChanged",
"partId": 'qsonzdfd',
"canUndo":true,
"canRedo":false,
"empty": false,
"undoStackIndex": 3,
"possibleUndoCount": 2
}
Exported
Server sends exported message to the browser.
{
"type":"exported",
"partId": 'qsonzdfd',
"exports":
{
"application/x-latex":"\\sqrt ",
"application/mathml+xml":"<math xmlns='http://www.w3.org/1998/Math/MathML'>\n <mo> √ <!-- square root --> </mo>\n</math>\n"
}
}
image/jpeg
or image/png
), the value will be base64 encoded.
Client commands
pointerEvents
This message import external ink
{
type: 'pointerEvents',
processGestures: false,
events: [{
pointerType: 'PEN',
pointerId: 1,
id: 'AZDFDFD'
"x": [273, 278, 281],
"y": [121, 128, 133],
"t": [3185.7900000000004, 3213.8150000000005, 3222.5350000000003],
"p": [1.3, 1.3, 1.3]
},{
gesture: false,
pointerType: 'PEN',
pointerId: 1,
id: 'AAAZZA',
"x": [173, 178, 181],
"y": [221, 228, 233],
"t": [6185.7900000000004, 6213.8150000000005,6222.5350000000003],
"p": [1.3, 1.3, 1.3]
}]
}
Change View Size
To ensure an accurate gesture detection, it is critical that the displayed content client-side and server-side are exactly the same. The ink will then be reflowed. Strokes or glyph elements will be replaced to fit at best on your screen; e.g. when you turn your tablet from landscape to portrait.
{
"type":"changeViewSize",
"width":1024,
"height":768
}
Convert
To convert recognized strokes to glyphs
{
"type":"convert",
"partId": 'XXXXX',
"conversionState": 'DIGITAL_EDIT'
}
Undo
Undo the last user action.
{
"type":"undo"
}
Redo
Redo the last user action.
{
"type":"redo"
}
Restore an iink session
Server stores document periodically. If your session is disconnected, you can restore it in a few minutes.
{
type:"restoreIInkSession",
applicationKey: 'XXXX-XXXXXX-XXXXX-XXXX',
iinkSessionId: 'YYYYYYYYYYYYYYYYYYYYY',
xDpi: 90,
yDpi: 90,
viewSizeHeight: 800,
viewSizeWidth: 1023
}
Import File
File import process has 2 steps: initialization and chunk sends. Splitting a file in chunks can be useful.
You can import JIIX or text (with a text part). Note that currently Math parts does not support import.
You must begin the import with an importFile
message once you have created a content part.
Set and keep importFileId
which must be used in the next fileChunk
messages.
Supported mime types are application/vnd.myscript.jiix
and text/plain
{
type: 'importFile',
importFileId: 'XXXXXX'
mimeType: 'text/plain',
x: 0,
y: 0
}
You can then send fileChunk
messages.
{
type: 'fileChunk',
importFileId: 'XXXXXX'
data: 'plain text or base64 if binary',
lastChunk: true
}
The server sends you an ack when a chunck is received.
{
type: 'fileChunkAck',
importFileId: 'XXXXXX'
chunkIdx: 1
}
After the last chunk, the server will incorporate the file and send SVG patches.
Export
This message allows to force an export client-side.
{
"type":"export",
"partId": "XXXXX",
"mimeTypes": []
}
Possible values for mimeTypes
are: application/mathofficeXML
, text/plain
, application/x-latex
, application/vnd.myscript.jiix
, application/vnd.myscript.iink
, image/jpeg
and image/png
.
The server will answer asynchronously with an “exported” message.
Ping-pong
The ping pong mechanism prevents the websocket from being disconnected with a timeout (client, server or network equipment in the middle).
{
"type":"ping"
}
If server is alive, it will respond as soon as the ping message arrives with a pong message
{
"type":"pong"
}
Common behaviour
On error, the server will send an error message and close the WebSocket.
{
type: 'error',
message: 'details about the error'
}