Jean-Yves Didier

cleanup; clearer video component; example with qrcode detection

/***
* @deprecated
* @see UIMapper
*
*/
arcs_module(
function(ARCS) {
var PositionWidget;
PositionWidget = ARCS.Component.create(
function(fields) {
var lonField = document.getElementById(fields[0]);
var latField = document.getElementById(fields[1]);
var accField = document.getElementById(fields[2]);
this.updatePosition = function(position) {
if (lonField)
lonField.innerHTML = position.coords.longitude;
if (latField)
latField.innerHTML = position.coords.latitude;
if (accField)
accField.innerHTML = position.coords.accuracy;
};
},
["updatePosition"],
[]
);
return { PositionWidget : PositionWidget};
}
);
......@@ -18,6 +18,7 @@ QRCodeDetector = ARCS.Componenent.create(
worker.postMessage(imageData);
}
if (dataCache !== null) {
console.log("qrdata", dataCache);
this.emit('onQRCode', dataCache);
}
};
......
......@@ -7,19 +7,26 @@ UIMapper = ARCS.Component.create(
let self = this;
// returns a map function
const mapFunction = function(param, field) {
const mapFunction = function(param, field, format) {
let fields = field.split('.');
let params = param.split('.');
let eltField = document.getElementById(fields[0]);
for(let i=1; i < fields.length-1; i++) {
eltField = eltField[fields[i]];
}
let func = null;
if (format !== undefined) {
func = new Function(`return ${format}`)();
}
return function() {
let eltField = document.getElementById(fields[0]);
for(let i=1; i < fields.length-1; i++) {
eltField = eltField[fields[i]];
}
let value = arguments[params[0]];
for (let i=1; i < params.length; i++) {
value = value[params[i]];
}
eltField[fields[fields.length-1]] = value;
}
eltField[fields[fields.length-1]] = (func)?((typeof func === 'function')?func(value):func):value;
}
};
......@@ -29,7 +36,7 @@ UIMapper = ARCS.Component.create(
let slotFunction = function(pobj) {
return function() {
pobj.map( elt => {
mapFunction(elt.param, elt.field).apply(null, arguments);
mapFunction(elt.param, elt.field,elt.format).apply(null, arguments);
});
};
}
......
import ARCS from '../build/arcs.js';
/* LiveSource browser compatibility :
* - Chrome: 53+
* - Edge: 12+
* - Firefox: 42+
* - Safari: 11+
*/
var LiveSource, VideoSource;
LiveSource = ARCS.Component.create(
function () {
function (config) {
var context, canvas, video, imageData;
var defaultWidth = 320;
var defaultHeight = 240;
var defaultWidth = config || config.width || 320;
var defaultHeight = config || config.height || 240;
var self = this;
var handleMediaStream = function(stream) {
console.log(video,stream);
if (window.webkitURL) {
video.src = window.webkitURL.createObjectURL(stream);
} else if (video.mozSrcObject !== undefined) {
video.mozSrcObject = stream;
} else if (video.srcObject !== undefined) {
video.srcObject = stream;
} else {
video.src = stream;
}
video.srcObject = stream;
video.onloadedmetadata = e => video.play();
/*video.videoWidth=defaultWidth;
video.videoHeight=defaultHeight;*/
self.emit("onReady");
......@@ -29,21 +30,14 @@ LiveSource = ARCS.Component.create(
};
var setUserMedia = function() {
if (navigator.mediaDevices !== undefined) {
navigator.mediaDevices.getUserMedia({video: {facingMode: "environment", width: defaultWidth, height: defaultHeight}})
.then(handleMediaStream)
.catch(errorMediaStream);
} else {
var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
if (getUserMedia !== undefined) {
getUserMedia({video:true}).then(handleMediaStream);
}
}
navigator.mediaDevices.getUserMedia({video: {facingMode: "environment", width: defaultWidth, height: defaultHeight}})
.then(handleMediaStream)
.catch(errorMediaStream);
};
this.grabFrame = function () {
if ( context === undefined || canvas === undefined || video === undefined)
return;
createWidgets();
if (video.readyState === video.HAVE_ENOUGH_DATA) {
context.drawImage(video, 0, 0, canvas.width, canvas.height);
imageData = context.getImageData(0, 0, canvas.width, canvas.height);
......@@ -55,6 +49,23 @@ LiveSource = ARCS.Component.create(
};
var createWidgets = function() {
video = video || document.createElement("video");
canvas = canvas || document.createElement("canvas");
canvas.width = video.width = defaultWidth;
canvas.height = video.height = defaultHeight;
canvas.style.width = canvas.width + "px";
canvas.style.height = canvas.height + "px";
// in order to hide our new elements
video.style.display = "none";
canvas.style.display = "none";
let shadow = document.body;//.attachShadow({mode: 'open'});
shadow.appendChild(video);
shadow.appendChild(canvas);
context = canvas.getContext("2d");
};
this.setWidgets = function (videoId, canvasId) {
video = document.getElementById(videoId);
canvas = document.getElementById(canvasId);
......@@ -105,9 +116,27 @@ VideoSource = ARCS.Component.create(
};
var createWidgets = function() {
video = document.createElement("video");
canvas = document.createElement("canvas");
canvas.width = video.width = defaultWidth;
canvas.height = video.height = defaultHeight;
canvas.style.width = canvas.width + "px";
canvas.style.height = canvas.height + "px";
// in order to hide our new elements
video.style.display = "none";
canvas.style.display = "none";
let shadow = document.body;//.attachShadow({mode: 'open'});
shadow.appendChild(video);
shadow.appendChild(canvas);
context = canvas.getContext("2d");
};
this.grabFrame = function () {
if ( context === undefined || canvas === undefined || video === undefined)
return;
createWidgets();
if (video.paused || video.ended) {
return;
}
......
......@@ -5,9 +5,9 @@
"geolocator": {"type":"GeoLocator"},
"positionWidget": { "type": "UIMapper", "value": {
"updatePosition" : [
{ "param" : "0.coords.longitude", "field" : "lon.innerHTML" },
{ "param" : "0.coords.latitude", "field" : "lat.innerHTML" },
{ "param" : "0.coords.accuracy", "field" : "acc.innerHTML" }
{ "param" : "0.coords.longitude", "field" : "lon.innerHTML", "format": "e=>e.toFixed(6)" },
{ "param" : "0.coords.latitude", "field" : "lat.innerHTML", "format": "e=>e.toFixed(6)" },
{ "param" : "0.coords.accuracy", "field" : "acc.innerHTML", "format": "e=>e.toFixed(2)" }
]
}},
"statemachine" : {
......
@viewport {
width: device-width;
zoom: 1;
}
#logo {
position: absolute;
margin:0px;
padding:0px;
right: 0px;
bottom:0px;
}
{
"context" : {
"libraries" : [ "../components/video.js","../components/animator.js", "../components/qrcodedetector.js"],
"components" : {
"animator" : { "type": "Animator"},
"video" : { "type": "LiveSource"},
"detector" : { "type": "QRCodeDetector"},
"statemachine" : {
"type": "StateMachine",
"value" : {
"initial": "init",
"final": "end",
"transitions" : {
"init" : { "next": "start"},
"start" : { "next" : "end"}
}
}
}
}
},
"controller" : "statemachine",
"sheets": {
"init" : {
"preconnections": [
{ "destination": "video", "slot": "setWidgets", "value": ["video"] },
],
"connections": [
{ "source": "video", "signal": "onReady", "destination": "statemachine", "slot" : "next"}
],
"postconnections": [],
"cleanups": []
},
"start" : {
"preconnections": [],
"connections": [
{"source": "animator", "signal": "onAnimationFrame", "destination": "video", "slot": "grabFrame"},
{"source": "video", "signal": "onImage", "destination": "detector", "slot": "detect"}
],
"postconnections": [
{ "destination": "animator", "slot": "start", "value":[]}
],
"cleanups": []
},
"end" : {
"preconnections": [],
"connections": [],
"postconnections": [],
"cleanups": []
}
}
}
body {
font-family: sans-serif;
}
table {
border: 1px solid black;
}
th {
text-align: left;
}
<!DOCTYPE html>
<html>
<head>
<title>QRCode detector</title>
<meta charset="utf-8">
<script data-base-url="../.."
data-arcsapp="arcsapp.json"
type="module"
src="../../build/arcs_browser.js">
</script>
<link rel="stylesheet" href="qrcode.css">
<link rel="stylesheet" href="arcs.css">
</head>
<body>
<video id="video" width=640 height=480 autoplay="true"></video>
<div id="contents">
<a id="logo" href="http://arcs.ibisc.univ-evry.fr"><img src="../../docs/arcs_logo.png" alt="ARCS"/></a>
</div>
</body>
</html>