'use strict';
'use strict';
(function (scope) {
/**
* InkPaper
*
* @class InkPaper
* @param {Element} element
* @param {Object} [options]
* @param {Function} [callback] callback function
* @param {Object} callback.data The recognition result
* @param {Object} callback.err The err to the callback
* @constructor
*/
function InkPaper(element, options, callback) {
this._element = element;
this._instanceId = undefined;
this._timerId = undefined;
this._initialized = false;
this._lastSentComponentIndex = 0;
this._components = [];
this._redoComponents = [];
this.isStarted = false;
this.resultCallback = callback;
this.changeCallback = undefined;
// Capture
var tempCanvas = _createCanvas(element, 'ms-temp-canvas');
this.canvasRatio = _getCanvasRatio(tempCanvas);
element.removeChild(tempCanvas);
//this.canvasRatio = 1;
this._captureCanvas = _createCanvas(element, 'ms-capture-canvas');
this._inkGrabber = new scope.InkGrabber(this._captureCanvas.getContext('2d'));
// Rendering
this._renderingCanvas = _createCanvas(element, 'ms-rendering-canvas');
this._textRenderer = new scope.TextRenderer(this._renderingCanvas.getContext('2d'));
this._mathRenderer = new scope.MathRenderer(this._renderingCanvas.getContext('2d'));
this._shapeRenderer = new scope.ShapeRenderer(this._renderingCanvas.getContext('2d'));
this._musicRenderer = new scope.MusicRenderer(this._renderingCanvas.getContext('2d'));
this._analyzerRenderer = new scope.AnalyzerRenderer(this._renderingCanvas.getContext('2d'));
// Recognition
this._textRecognizer = new scope.TextRecognizer();
this._mathRecognizer = new scope.MathRecognizer();
this._shapeRecognizer = new scope.ShapeRecognizer();
this._musicRecognizer = new scope.MusicRecognizer();
this._analyzerRecognizer = new scope.AnalyzerRecognizer();
this._textWSRecognizer = new scope.TextWSRecognizer(this._handleMessage.bind(this));
this._mathWSRecognizer = new scope.MathWSRecognizer(this._handleMessage.bind(this));
this._attachListeners(element);
this.options = { // Default options
type: scope.RecognitionType.TEXT,
protocol: scope.Protocol.REST,
ssl: true,
width: 400,
height: 300,
timeout: 2000,
typeset: false,
components: [],
textParameters: new scope.TextParameter(),
mathParameters: new scope.MathParameter(),
shapeParameters: new scope.ShapeParameter(),
musicParameters: new scope.MusicParameter(),
analyzerParameters: new scope.AnalyzerParameter()
};
if (options) {
for (var idx in options) {
if (options[idx] !== undefined) {
this.options[idx] = options[idx]; // Override current options
}
}
}
// Recognition type
this.setType(this.options.type);
this.setHost(this.options.host);
this.setSSL(this.options.ssl);
this.setTextParameters(this.options.textParameters); // jshint ignore:line
this.setMathParameters(this.options.mathParameters); // jshint ignore:line
this.setShapeParameters(this.options.shapeParameters); // jshint ignore:line
this.setMusicParameters(this.options.musicParameters); // jshint ignore:line
this.setAnalyzerParameters(this.options.analyzerParameters); // jshint ignore:line
this.setProtocol(this.options.protocol);
this.setTimeout(this.options.timeout);
this.setApplicationKey(this.options.applicationKey);
this.setHmacKey(this.options.hmacKey);
this.setPenParameters(this.options.penParameters);
this.setPrecision(this.options.precision);
this.setTypeset(this.options.typeset);
this.setComponents(this.options.components);
this.setWidth(this.options.width);
this.setHeight(this.options.height);
}
/**
* Set the width
*
* @method setWidth
* @param {Number} width
*/
InkPaper.prototype.setWidth = function (width) {
if (width > 0) {
this._captureCanvas.width = width * this.canvasRatio;
this._captureCanvas.style.width = width + 'px';
this._captureCanvas.getContext('2d').scale(this.canvasRatio, this.canvasRatio);
this._renderingCanvas.width = width * this.canvasRatio;
this._renderingCanvas.style.width = width + 'px';
this._renderingCanvas.getContext('2d').scale(this.canvasRatio, this.canvasRatio);
}
this._initRenderingCanvas();
};
/**
* Set the height
*
* @method setHeight
* @param {Number} height
*/
InkPaper.prototype.setHeight = function (height) {
if (height > 0) {
this._captureCanvas.height = height * this.canvasRatio;
this._captureCanvas.style.height = height + 'px';
this._captureCanvas.getContext('2d').scale(this.canvasRatio, this.canvasRatio);
this._renderingCanvas.height = height * this.canvasRatio;
this._renderingCanvas.style.height = height + 'px';
this._renderingCanvas.getContext('2d').scale(this.canvasRatio, this.canvasRatio);
}
this._initRenderingCanvas();
};
/**
* Set the network protocol (REST or WebSocket)
*
* @param {'REST'|'WebSocket'} protocol
*/
InkPaper.prototype.setProtocol = function (protocol) {
switch (protocol) {
case scope.Protocol.REST:
this._selectedRecognizer = this._selectedRESTRecognizer;
break;
case scope.Protocol.WS:
this.setTimeout(-1); // FIXME hack to avoid border issues
this._selectedRecognizer = this._selectedWSRecognizer;
break;
default:
throw new Error('Unknown protocol: ' + protocol);
}
this._instanceId = undefined;
this._initialized = false;
this._lastSentComponentIndex = 0;
};
/**
* Get the network protocol (REST or WebSocket)
*
* @returns {'REST'|'WebSocket'}
*/
InkPaper.prototype.getProtocol = function () {
if (this._selectedRecognizer instanceof scope.AbstractWSRecognizer) {
return scope.Protocol.WS;
} else {
return scope.Protocol.REST;
}
};
/**
* Set recognition type
*
* @method setType
* @param {'TEXT'|'MATH'|'SHAPE'|'MUSIC'|'ANALYZER'} type
*/
InkPaper.prototype.setType = function (type) {
switch (type) {
case scope.RecognitionType.TEXT:
this._selectedRenderer = this._textRenderer;
this._selectedRESTRecognizer = this._textRecognizer;
this._selectedWSRecognizer = this._textWSRecognizer;
break;
case scope.RecognitionType.MATH:
this._selectedRenderer = this._mathRenderer;
this._selectedRESTRecognizer = this._mathRecognizer;
this._selectedWSRecognizer = this._mathWSRecognizer;
break;
case scope.RecognitionType.SHAPE:
this._selectedRenderer = this._shapeRenderer;
this._selectedRESTRecognizer = this._shapeRecognizer;
break;
case scope.RecognitionType.MUSIC:
this._selectedRenderer = this._musicRenderer;
this._selectedRESTRecognizer = this._musicRecognizer;
break;
case scope.RecognitionType.ANALYZER:
this._selectedRenderer = this._analyzerRenderer;
this._selectedRESTRecognizer = this._analyzerRecognizer;
break;
default:
throw new Error('Unknown type: ' + type);
}
this._instanceId = undefined;
this._initialized = false;
this._lastSentComponentIndex = 0;
};
/**
* Get recognition type
*
* @method getType
* @returns {'TEXT'|'MATH'|'SHAPE'|'MUSIC'|'ANALYZER'} type
*/
InkPaper.prototype.getType = function () {
if (this._selectedRenderer instanceof scope.TextRenderer) {
return scope.RecognitionType.TEXT;
}
if (this._selectedRenderer instanceof scope.MathRenderer) {
return scope.RecognitionType.MATH;
}
if (this._selectedRenderer instanceof scope.ShapeRenderer) {
return scope.RecognitionType.SHAPE;
}
if (this._selectedRenderer instanceof scope.MusicRenderer) {
return scope.RecognitionType.MUSIC;
}
if (this._selectedRenderer instanceof scope.AnalyzerRenderer) {
return scope.RecognitionType.ANALYZER;
}
throw new Error('Unknown type');
};
/**
* Get the recognition timeout
*
* @method getTimeout
* @returns {Number}
*/
InkPaper.prototype.getTimeout = function () {
return this.timeout;
};
/**
* Set the recognition timeout
*
* @method setTimeout
* @param {Number} timeout
*/
InkPaper.prototype.setTimeout = function (timeout) {
this.timeout = timeout;
};
/**
* Set the recognition precision
*
* @method setPrecision
* @param {Number} precision
*/
InkPaper.prototype.setPrecision = function (precision) {
this._textRecognizer.setPrecision(precision);
this._textWSRecognizer.setPrecision(precision);
this._mathRecognizer.setPrecision(precision);
this._mathWSRecognizer.setPrecision(precision);
this._shapeRecognizer.setPrecision(precision);
this._musicRecognizer.setPrecision(precision);
this._analyzerRecognizer.setPrecision(precision);
};
/**
* Get the default components
*
* @method getComponents
* @return {Array} components
*/
InkPaper.prototype.getComponents = function () {
return this.options.components;
};
/**
* Set the default components
*
* @method setComponents
* @param {Array} components
*/
InkPaper.prototype.setComponents = function (components) {
this.options.components = components;
this._initRenderingCanvas();
};
/**
* Get the application key
*
* @method getApplicationKey
* @returns {String}
*/
InkPaper.prototype.getApplicationKey = function () {
return this.applicationKey;
};
/**
* Set the application key
*
* @method setApplicationKey
* @param {String} applicationKey
*/
InkPaper.prototype.setApplicationKey = function (applicationKey) {
this.applicationKey = applicationKey;
};
/**
* Get the HMAC key
*
* @method getHmacKey
* @returns {String}
*/
InkPaper.prototype.getHmacKey = function () {
return this.hmacKey;
};
/**
* Set the HMAC key
*
* @method setHmacKey
* @param {String} hmacKey
*/
InkPaper.prototype.setHmacKey = function (hmacKey) {
this.hmacKey = hmacKey;
};
/**
* Set text recognition parameters
*
* @method setTextParameters
* @param {TextParameter} textParameters
*/
InkPaper.prototype.setTextParameters = function (textParameters) {
if (textParameters) {
if (this._selectedRecognizer instanceof scope.AbstractWSRecognizer) {
this.isStarted = false;
this._selectedRecognizer.resetWSRecognition();
}
for (var i in textParameters) {
if (textParameters[i] !== undefined) {
this._textRecognizer.getParameters()[i] = textParameters[i]; // Override options
this._textWSRecognizer.getParameters()[i] = textParameters[i]; // Override options
this._analyzerRecognizer.getParameters().getTextParameters()[i] = textParameters[i]; // Override options
}
}
}
};
/**
* Get text recognition parameters
*
* @method getTextParameters
* @returns {TextParameter} textParameters
*/
InkPaper.prototype.getTextParameters = function () {
return this._textRecognizer.getParameters();
};
/**
* Set math recognition parameters
*
* @method setMathParameters
* @param {MathParameter} mathParameters
*/
InkPaper.prototype.setMathParameters = function (mathParameters) {
if (mathParameters) {
if (this._selectedRecognizer instanceof scope.AbstractWSRecognizer) {
this.isStarted = false;
this._selectedRecognizer.resetWSRecognition();
}
for (var i in mathParameters) {
if (mathParameters[i] !== undefined) {
this._mathRecognizer.getParameters()[i] = mathParameters[i]; // Override options
this._mathWSRecognizer.getParameters()[i] = mathParameters[i]; // Override options
}
}
}
};
/**
* Get math recognition parameters
*
* @method getMathParameters
* @returns {MathParameter} mathParameters
*/
InkPaper.prototype.getMathParameters = function () {
return this._mathRecognizer.getParameters();
};
/**
* Set shape recognition parameters
*
* @method setShapeParameters
* @param {ShapeParameter} shapeParameters
*/
InkPaper.prototype.setShapeParameters = function (shapeParameters) {
if (shapeParameters) {
if (this._selectedRecognizer instanceof scope.AbstractWSRecognizer) {
this.isStarted = false;
this._selectedRecognizer.resetWSRecognition();
}
for (var i in shapeParameters) {
if (shapeParameters[i] !== undefined) {
this._shapeRecognizer.getParameters()[i] = shapeParameters[i]; // Override options
}
}
}
};
/**
* Get shape recognition parameters
*
* @method getShapeParameters
* @returns {ShapeParameter} shapeParameters
*/
InkPaper.prototype.getShapeParameters = function () {
return this._shapeRecognizer.getParameters();
};
/**
* Set music recognition parameters
*
* @method setMusicParameters
* @param {MusicParameter} musicParameters
*/
InkPaper.prototype.setMusicParameters = function (musicParameters) {
if (musicParameters) {
if (this._selectedRecognizer instanceof scope.AbstractWSRecognizer) {
this.isStarted = false;
this._selectedRecognizer.resetWSRecognition();
}
for (var i in musicParameters) {
if (musicParameters[i] !== undefined) {
this._musicRecognizer.getParameters()[i] = musicParameters[i]; // Override options
}
}
this._initRenderingCanvas();
}
};
/**
* Get music recognition parameters
*
* @method getMusicParameters
* @returns {MusicParameter} musicParameters
*/
InkPaper.prototype.getMusicParameters = function () {
return this._musicRecognizer.getParameters();
};
/**
* Set analyzer recognition parameters
*
* @method setAnalyzerParameters
* @param {AnalyzerParameter} analyzerParameters
*/
InkPaper.prototype.setAnalyzerParameters = function (analyzerParameters) {
if (analyzerParameters) {
if (this._selectedRecognizer instanceof scope.AbstractWSRecognizer) {
this.isStarted = false;
this._selectedRecognizer.resetWSRecognition();
}
for (var i in analyzerParameters) {
if (analyzerParameters[i] !== undefined) {
this._analyzerRecognizer.getParameters()[i] = analyzerParameters[i]; // Override options
}
}
}
};
/**
* Get analyzer recognition parameters
*
* @method getAnalyzerParameters
* @returns {AnalyzerParameter} analyzerParameters
*/
InkPaper.prototype.getAnalyzerParameters = function () {
return this._analyzerRecognizer.getParameters();
};
/**
* Set pen parameters
*
* @method setPenParameters
* @param {PenParameters} penParameters
*/
InkPaper.prototype.setPenParameters = function (penParameters) {
if (penParameters) {
for (var i in penParameters) {
if (penParameters[i] !== undefined) {
this._selectedRenderer.getParameters()[i] = penParameters[i]; // Override options
}
}
var params = this._selectedRenderer.getParameters();
this._inkGrabber.setParameters(params); // Override options
this._textRenderer.setParameters(params); // Override options
this._mathRenderer.setParameters(params); // Override options
this._shapeRenderer.setParameters(params); // Override options
this._musicRenderer.setParameters(params); // Override options
this._analyzerRenderer.setParameters(params); // Override options
}
};
/**
* Get pen parameters
*
* @method getPenParameters
* @returns {PenParameters} penParameters
*/
InkPaper.prototype.getPenParameters = function () {
return this._selectedRenderer.getParameters();
};
/**
* Enable / disable typeset
*
* @method setTypeset
* @param {Boolean} typeset
*/
InkPaper.prototype.setTypeset = function (typeset) {
this._textRenderer.setTypeset(typeset);
this._mathRenderer.setTypeset(typeset);
this._shapeRenderer.setTypeset(typeset);
this._musicRenderer.setTypeset(typeset);
this._analyzerRenderer.setTypeset(typeset);
};
/**
* Get available languages
*
* @method getAvailableLanguages
* @param {String} [inputMode] input mode
*/
InkPaper.prototype.getAvailableLanguages = function (inputMode) {
this._selectedRESTRecognizer.getAvailableLanguageList(
this.getApplicationKey(),
inputMode ? inputMode : this._textRecognizer.getParameters().getInputMode()
).then(
function (data) {
this._onResult(data);
}.bind(this),
function (error) {
this._onResult(undefined, error);
}.bind(this)
);
};
/**
* Get the renderer
*
* @method getRenderer
* @returns {AbstractRenderer}
*/
InkPaper.prototype.getRenderer = function () {
return this._selectedRenderer;
};
/**
* Get the ink capturer
*
* @method getInkGrabber
* @returns {InkGrabber}
*/
InkPaper.prototype.getInkGrabber = function () {
return this._inkGrabber;
};
/**
* Get the recognizer
*
* @method getRecognizer
* @returns {AbstractRecognizer}
*/
InkPaper.prototype.getRecognizer = function () {
return this._selectedRecognizer;
};
/**
* Set the change callback
*
* @method setChangeCallback
* @param {Function} callback callback function
* @param {Object} callback.data The inkPaper state
*/
InkPaper.prototype.setChangeCallback = function (changeCallback) {
this.changeCallback = changeCallback;
};
/**
* Set the recognition result callback
*
* @method setResultCallback
* @param {Function} callback callback function
* @param {Object} callback.data The recognition result
*/
InkPaper.prototype.setResultCallback = function (callback) {
this.resultCallback = callback;
};
/**
* Recognize
*
* @method recognize
* @returns {Promise}
*/
InkPaper.prototype.recognize = function () {
var input = this.getComponents().concat(this._components);
if (this._selectedRecognizer instanceof scope.AbstractWSRecognizer) {
if (this._initialized) {
var lastInput = input.slice(this._lastSentComponentIndex);
if (lastInput.length > 0) {
this._lastSentComponentIndex = input.length;
if (!this.isStarted) {
this.isStarted = true;
this._selectedRecognizer.startWSRecognition(lastInput);
} else {
this._selectedRecognizer.continueWSRecognition(lastInput, this._instanceId);
}
} else {
this._renderResult();
}
}
} else {
if (this._selectedRecognizer instanceof scope.ShapeRecognizer) {
this._instanceId = undefined;
}
if (input.length > 0) {
if (!this.isStarted) {
this._startRESTRecognition(input);
} else {
this._continueRESTRecognition(input, this._instanceId);
}
} else {
this._renderResult();
}
}
};
InkPaper.prototype._startRESTRecognition = function (components) {
this._instanceId = undefined;
this._selectedRecognizer.doSimpleRecognition(
this.getApplicationKey(),
this._instanceId,
components,
this.getHmacKey()
).then(
function (data) {
if (!this.isStarted) {
this.isStarted = true;
this._lastSentComponentIndex = components.length;
this._instanceId = data.getInstanceId();
this._renderResult(data);
}
}.bind(this),
function (error) {
this._onResult(undefined, error);
}.bind(this)
);
};
InkPaper.prototype._continueRESTRecognition = function (components, instanceId) {
this._selectedRecognizer.doSimpleRecognition(
this.getApplicationKey(),
instanceId,
components,
this.getHmacKey()
).then(
function (data) {
this._lastSentComponentIndex = this._lastSentComponentIndex + components.length;
this._renderResult(data);
}.bind(this),
function (error) {
this._onResult(undefined, error);
}.bind(this)
);
};
InkPaper.prototype._clearRESTRecognition = function (instanceId) {
if (this._selectedRecognizer instanceof scope.ShapeRecognizer) {
this.isStarted = false;
this._lastSentComponentIndex = 0;
this._selectedRecognizer.clearShapeRecognitionSession(
this.getApplicationKey(),
instanceId
).then(
function (data) {
this._instanceId = undefined;
this._onResult(data);
}.bind(this),
function (error) {
this._onResult(undefined, error);
}.bind(this)
);
} else {
this._onResult();
}
};
/**
* Return true if you can undo
*
* @method canUndo
* @returns {Boolean}
*/
InkPaper.prototype.canUndo = function () {
return this._components.length > 0;
};
/**
* Undo
*
* @method undo
*/
InkPaper.prototype.undo = function () {
if (this.canUndo()) {
//Remove the scratched state for Math strokes
this._components.forEach(function(stroke){
stroke.scratchedStroke = false;
});
//Remove the latsModel used for Shape
this.updatedModel = undefined;
this._redoComponents.push(this._components.pop());
this._clearRESTRecognition(this._instanceId);
this._initRenderingCanvas();
this._onChange();
this.isStarted = false;
if (this._selectedRecognizer instanceof scope.AbstractWSRecognizer) {
this._selectedRecognizer.resetWSRecognition();
} else {
clearTimeout(this._timerId);
if (this.getTimeout() > -1) {
this._timerId = setTimeout(this.recognize.bind(this), this.getTimeout());
} else {
this._onResult();
}
}
}
};
/**
* Return true if you can redo
*
* @method canRedo
* @returns {Boolean}
*/
InkPaper.prototype.canRedo = function () {
return this._redoComponents.length > 0;
};
/**
* Redo
*
* @method redo
*/
InkPaper.prototype.redo = function () {
if (this.canRedo()) {
this._components.push(this._redoComponents.pop());
this._clearRESTRecognition(this._instanceId);
this._initRenderingCanvas();
this._onChange();
if (this._selectedRecognizer instanceof scope.AbstractWSRecognizer) {
this.recognize();
} else {
clearTimeout(this._timerId);
this.isStarted = false;
if (this.getTimeout() > -1) {
this._timerId = setTimeout(this.recognize.bind(this), this.getTimeout());
} else {
this._onResult();
}
}
}
};
/**
* Clear the ink paper
*
* @method clear
*/
InkPaper.prototype.clear = function () {
this._components = [];
this._redoComponents = [];
this._clearRESTRecognition(this._instanceId);
this._initRenderingCanvas();
this._onChange();
if (this._selectedRecognizer instanceof scope.AbstractWSRecognizer) {
this.isStarted = false;
this._selectedRecognizer.resetWSRecognition();
} else if (this._selectedRecognizer instanceof scope.MusicRecognizer) {
clearTimeout(this._timerId);
this._onResult();
} else {
clearTimeout(this._timerId);
if (this.getTimeout() > -1) {
this._timerId = setTimeout(this.recognize.bind(this), this.getTimeout());
} else {
this._onResult();
}
}
};
InkPaper.event = {
'addDomListener': function (element, useCapture, myfunction) {
element.addEventListener(useCapture, myfunction);
}
};
/**
*
* @private
* @method _down
* @param {Number} x X coordinate
* @param {Number} y Y coordinate
* @param {Date} [t] timeStamp
*/
InkPaper.prototype._down = function (x, y, t) {
clearTimeout(this._timerId);
var sizeChanged = false;
if (this._captureCanvas.clientHeight * this.canvasRatio !== this._captureCanvas.height) {
this._captureCanvas.height = this._captureCanvas.clientHeight * this.canvasRatio;
this._renderingCanvas.height = this._renderingCanvas.clientHeight * this.canvasRatio;
sizeChanged = true;
}
if (this._captureCanvas.clientWidth * this.canvasRatio !== this._captureCanvas.width) {
this._captureCanvas.width = this._captureCanvas.clientWidth * this.canvasRatio;
this._renderingCanvas.width = this._renderingCanvas.clientWidth * this.canvasRatio;
sizeChanged = true;
}
//Safari trash the canvas content when heigth or width are modified.
if (sizeChanged) {
this._captureCanvas.getContext('2d').scale(this.canvasRatio, this.canvasRatio);
this._renderingCanvas.getContext('2d').scale(this.canvasRatio, this.canvasRatio);
this._initRenderingCanvas();
}
if (this.canRedo()) {
this._redoComponents = [];
this._onChange();
}
this._inkGrabber.startCapture(x, y, t);
};
/**
*
* @private
* @method _move
* @param {Number} x X coordinate
* @param {Number} y Y coordinate
* @param {Date} [t] timeStamp
*/
InkPaper.prototype._move = function (x, y, t) {
this._inkGrabber.continueCapture(x, y, t);
};
/**
*
* @private
* @method _move
* @param {Number} x X coordinate
* @param {Number} y Y coordinate
* @param {Date} [t] timeStamp
*/
InkPaper.prototype._up = function (x, y, t) {
this._inkGrabber.endCapture(x, y, t);
var stroke = this._inkGrabber.getStroke();
this._inkGrabber.clear();
this._selectedRenderer.drawComponent(stroke);
this._components.push(stroke);
this._onChange();
if (this._selectedRecognizer instanceof scope.AbstractWSRecognizer) {
if (!this._selectedRecognizer.isOpen() && !this._selectedRecognizer.isConnecting()) {
this._selectedRecognizer.open();
} else {
this.recognize();
}
} else {
clearTimeout(this._timerId);
if (this.getTimeout() > -1) {
this._timerId = setTimeout(this.recognize.bind(this), this.getTimeout());
}
}
};
InkPaper.prototype._onResult = function (data, err) {
if (this.resultCallback) {
this.resultCallback(data, err);
}
if (err) {
this._element.dispatchEvent(new CustomEvent('error', {detail: err}));
} else {
this._element.dispatchEvent(new CustomEvent('success', {detail: data}));
}
};
InkPaper.prototype._onChange = function () {
var data = {
canUndo: this.canUndo(),
undoLength: this._components.length,
canRedo: this.canRedo(),
redoLength: this._redoComponents.length
};
if (this.changeCallback) {
this.changeCallback(data)
}
this._element.dispatchEvent(new CustomEvent('changed', {detail: data}));
};
InkPaper.prototype._renderResult = function (data) {
this.updatedModel = this._selectedRenderer.drawRecognitionResult(this.getComponents().concat(this._components), data? data.getDocument(): undefined);
if (this._selectedRecognizer instanceof scope.MusicRecognizer) {
if (this._selectedRecognizer.getParameters().getStaff() instanceof scope.MusicStaff) {
this._selectedRenderer.drawStaff(this._selectedRecognizer.getParameters().getStaff());
}
}
this._onResult(data);
return data;
};
/**
* Set recognition service url
*
* @param {String} host
*/
InkPaper.prototype.setHost = function (host) {
this._textRecognizer.setHost(host);
this._textWSRecognizer.setHost(host);
this._mathRecognizer.setHost(host);
this._mathWSRecognizer.setHost(host);
this._shapeRecognizer.setHost(host);
this._musicRecognizer.setHost(host);
this._analyzerRecognizer.setHost(host);
};
/**
* @private
*/
InkPaper.prototype.setSSL = function (ssl) {
this._textRecognizer.setSSL(ssl);
this._textWSRecognizer.setSSL(ssl);
this._mathRecognizer.setSSL(ssl);
this._mathWSRecognizer.setSSL(ssl);
this._shapeRecognizer.setSSL(ssl);
this._musicRecognizer.setSSL(ssl);
this._analyzerRecognizer.setSSL(ssl);
};
/**
* Tool to attach touch events
*
* @private
* @param {Element} element
*/
InkPaper.prototype._attachListeners = function (element) {
var self = this;
var pointerId;
//Desactivation of contextmenu to prevent safari to fire pointerdown only once
element.addEventListener("contextmenu", function (e) {
e.preventDefault();
e.stopPropagation();
return false;
}
);
element.addEventListener('pointerdown', function (e) {
if (!pointerId) {
pointerId = e.pointerId;
e.preventDefault();pointerId
var coord = _getCoordinates(e, element);
self._down(coord.x, coord.y, coord.t);
}
}, false);
element.addEventListener('pointermove', function (e) {
if (pointerId === e.pointerId) {
e.preventDefault();
var coord = _getCoordinates(e, element);
self._move(coord.x, coord.y, coord.t);
}
}, false);
element.addEventListener('pointerup', function (e) {
if (pointerId === e.pointerId) {
e.preventDefault();
var coord = _getCoordinates(e, element);
self._up(coord.x, coord.y, coord.t);
pointerId = undefined;
}
}, false);
element.addEventListener('pointerleave', function (e) {
if (pointerId === e.pointerId) {
e.preventDefault();
var point = self._inkGrabber.getStroke().getPointByIndex(self._inkGrabber.getStroke().getLastIndexPoint());
self._up(point.x, point.y, point.t);
pointerId = undefined;
}
}, false);
element.addEventListener('pointerout', function (e) {
if (pointerId === e.pointerId) {
e.preventDefault();
var point = self._inkGrabber.getStroke().getPointByIndex(self._inkGrabber.getStroke().getLastIndexPoint());
self._up(point.x, point.y, point.t);
pointerId = undefined;
}
}, false);
};
InkPaper.prototype._initRenderingCanvas = function () {
this._selectedRenderer.clear();
if (this._selectedRecognizer instanceof scope.MusicRecognizer) {
if (this._selectedRecognizer.getParameters().getStaff() instanceof scope.MusicStaff) {
this._selectedRenderer.drawStaff(this._selectedRecognizer.getParameters().getStaff());
}
}
if(this._selectedRecognizer instanceof scope.ShapeRecognizer && this.updatedModel){
this._selectedRenderer.drawRecognitionResult(this.updatedModel.components, this.updatedModel.document);
} elseĀ {
this._selectedRenderer.drawComponents(this.getComponents().concat(this._components));
}
};
/**
*
* @param message
* @param error
* @returns {boolean} false no immediate replay needed, true when the call need to be replay ASAP
* @private
*/
InkPaper.prototype._handleMessage = function (message, error) {
var replayNeeded = false;
if (error) {
replayNeeded = true;
this._instanceId = undefined;
this.isStarted = false;
this._lastSentComponentIndex = 0;
this._onResult(undefined, error);
}
if (message) {
switch (message.type) {
case 'open':
this._selectedWSRecognizer.initWSRecognition(this.getApplicationKey());
break;
case 'hmacChallenge':
this._selectedWSRecognizer.takeUpHmacChallenge(this.getApplicationKey(), message.getChallenge(), this.getHmacKey());
break;
case 'init':
this.isStarted = false;
this._initialized = true;
this._instanceId = undefined;
this._lastSentComponentIndex = 0;
this.recognize();
break;
case 'reset':
this.isStarted = false;
this._instanceId = undefined;
this._lastSentComponentIndex = 0;
this.recognize();
break;
case 'close':
this._initialized = false;
this._instanceId = undefined;
this._lastSentComponentIndex = 0;
break;
default:
this.isStarted = true;
if (!this._instanceId) {
this._instanceId = message.getInstanceId();
}
this._renderResult(message);
break;
}
}
return replayNeeded;
};
/**
* Return the stats allowing to monitor what ink size is send to the server.
* @returns Stats objects format {strokesCount : 0, pointsCount : 0, byteSize : 0, humanSize : 0, humanUnit : 'BYTE'} humanUnit could have the values BYTE, BYTES, KiB, MiB
*/
InkPaper.prototype.getStats = function () {
var stats = {strokesCount: 0, pointsCount: 0, byteSize: 0, humanSize: 0, humanUnit: 'BYTE'};
if (this._components) {
stats.strokesCount = this._components.length;
var pointsCount = 0;
for (var strokeNb = 0; strokeNb < this._components.length; strokeNb++) {
pointsCount = pointsCount + this._components[strokeNb].x.length;
}
stats.strokesCount = this._components.length;
stats.pointsCount = pointsCount;
//We start with 270 as it is the size in bytes. Make a real computation implies to recode a doRecogntion
var byteSize = 270;
byteSize = JSON.stringify(this._components).length;
stats.byteSize = byteSize;
if (byteSize < 270) {
stats.humanUnit = 'BYTE';
stats.byteSize = 0;
stats.humanSize = 0;
} else if (byteSize < 2048) {
stats.humanUnit = 'BYTES';
stats.humanSize = byteSize;
} else if (byteSize < 1024 * 1024) {
stats.humanUnit = 'KiB';
stats.humanSize = (byteSize / 1024).toFixed(2);
} else {
stats.humanUnit = 'MiB';
stats.humanSize = (byteSize / 1024 / 1024).toFixed(2);
}
}
return stats;
};
/**
*
* @param marginX the horizontal margin to apply (by default 10)
* @param marginY the vertical margin to apply (by default 10)
* @returns {ImageData} Build an ImageData object with content shrink to border of strokes.
* @private
*/
InkPaper.prototype.getInkAsImageData = function (marginX, marginY) {
//Remove the scratched strokes
var componentCopy = [];
this._components.forEach(function(stroke) {
if (stroke.scratchedStroke !== true) {
componentCopy.push(stroke);
}
}
);
if (!marginX) {
marginX = 10;
}
if (!marginY) {
marginY = 10;
}
if (componentCopy && componentCopy.length > 0) {
var updatedStrokes;
var strokesCount = componentCopy.length;
//Initializing min and max
var minX = componentCopy[0].x[0];
var maxX = componentCopy[0].x[0];
var minY = componentCopy[0].y[0];
var maxY = componentCopy[0].y[0];
// Computing the min and max for x and y
for (var strokeNb = 0; strokeNb < componentCopy.length; strokeNb++) {
var pointCount = componentCopy[strokeNb].x.length;
for (var pointNb = 0; pointNb < pointCount; pointNb++) {
var currentX = componentCopy[strokeNb].x[pointNb];
var currentY = componentCopy[strokeNb].y[pointNb];
if (currentX < minX) {
minX = currentX;
}
if (currentX > maxX) {
maxX = currentX;
}
if (currentY < minY) {
minY = currentY;
}
if (currentY > maxY) {
maxY = currentY;
}
}
}
var nonDisplayCanvas = document.createElement('canvas');
nonDisplayCanvas.width = (maxX ) + (2 * marginX);
nonDisplayCanvas.height = (maxY ) + (2 * marginY)
var ctx = nonDisplayCanvas.getContext("2d");
var imageRendered = new scope.ImageRenderer(ctx);
imageRendered.drawComponents(componentCopy, ctx);
// https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getImageData
return ctx.getImageData(minX - marginX, minY - marginY, (maxX - minX ) + (2 * marginX), (maxY - minY ) + (2 * marginY));
}
};
/**
*
* @param marginX the horizontal margin to apply (by default 10)
* @param marginY the vertical margin to apply (by default 10)
* @returns {String} Build an String containg dataUrl with content shrink to border of strokes.
* @private
*/
InkPaper.prototype.getInkAsPng = function (marginX, marginY) {
var imageRenderingCanvas = document.createElement('canvas');
imageRenderingCanvas.style.display = 'none';
var imageDataToRender = this.getInkAsImageData();
imageRenderingCanvas.width = imageDataToRender.width;
imageRenderingCanvas.style.width = imageDataToRender.width + 'px';
imageRenderingCanvas.height = imageDataToRender.height;
imageRenderingCanvas.style.height = imageDataToRender.height + 'px';
var ctx = imageRenderingCanvas.getContext('2d');
ctx.putImageData(imageDataToRender, 0, 0);
return imageRenderingCanvas.toDataURL("image/png");
};
/**
* Tool to create canvas
*
* @private
* @param {Element} parent
* @param {String} id
* @returns {Element}
*/
function _createCanvas(parent, id) {
var count = document.querySelectorAll('canvas[id^=' + id + ']').length;
var canvas = document.createElement('canvas');
canvas.id = id + '-' + count;
parent.appendChild(canvas);
return canvas;
}
/**
* Tool to get canvas ratio (retina display)
*
* @private
* @param {Element} canvas
* @returns {Number}
*/
function _getCanvasRatio(canvas) {
if (canvas) {
var context = canvas.getContext('2d'),
devicePixelRatio = window.devicePixelRatio || 1,
backingStoreRatio = context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio || 1;
return devicePixelRatio / backingStoreRatio;
}
return 1;
}
/**
* Tool to get proper coordinates
*
* @private
* @param {Event} e
* @param {Element} element
* @returns {Object}
*/
function _getCoordinates(e, container) {
if (e.changedTouches) e = e.changedTouches[0];
var rect = container.getBoundingClientRect();
return {
x: e.clientX - rect.left - container.clientLeft,
y: e.clientY - rect.top - container.clientTop,
t: e.timeStamp
};
}
// Export
scope.InkPaper = InkPaper;
})(MyScript);