Socket
Socket
Sign inDemoInstall

opentok-annotation

Package Overview
Dependencies
Maintainers
1
Versions
101
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

opentok-annotation - npm Package Compare versions

Comparing version 1.0.29 to 1.0.30

2

dist/opentok-annotation.min.js

@@ -1,1 +0,1 @@

var _otkanalytics,_session,_logEventData={clientVersion:"js-vsol-1.0.0",componentId:"annotationsAccPack",name:"guidAnnotationsKit",actionStartDrawing:"Start Drawing",actionEndDrawing:"End Drawing",variationSuccess:"Success"},_logAnalytics=function(){var t=window.location.href,e={clientVersion:_logEventData.clientVersion,source:t,componentId:_logEventData.componentId,name:_logEventData.name};_otkanalytics=new OTKAnalytics(e);var n={sessionId:_session.id,connectionId:_session.connection.connectionId,partnerId:_session.apiKey};_otkanalytics.addSessionInfo(n)},_log=function(t,e){var n={action:t,variation:e};_otkanalytics.logEvent(n)};window.OTSolution=window.OTSolution||{},OTSolution.Annotations=function(t){function e(t,e,n){for(var o=e.split(" "),i=0,a=o.length;i<a;i++)t.addEventListener(o[i],n,!0)}function n(t,e){0===a.width&&(a.width=i.parent.getBoundingClientRect().width),0===a.height&&(a.height=i.parent.getBoundingClientRect().height);var n,o=e?t.canvas.width:i.parent.clientWidth,s=e?t.canvas.height:i.parent.clientHeight,r=e?t.canvas.offsetLeft:a.offsetLeft,l=e?t.canvas.offsetTop:a.offsetTop,d=a.width/o,h=a.height/s,u=t.offsetX||t.pageX-r||t.changedTouches&&t.changedTouches[0].pageX-r,g=t.offsetY||t.pageY-l||t.changedTouches&&t.changedTouches[0].pageY-l,m=u*d,v=g*h,y=e?t.selectedItem:i.selectedItem;if(y)if("OT_pen"===y.id)switch(t.type){case"mousedown":case"touchstart":f.dragging=!0,f.lastX=m,f.lastY=v,i.isStartPoint=!0,!e&&_log(_logEventData.actionStartDrawing,_logEventData.variationSuccess);break;case"mousemove":case"touchmove":f.dragging&&(n={id:i.videoFeed.stream.connection.connectionId,fromId:i.session.connection.connectionId,fromX:f.lastX,fromY:f.lastY,toX:m,toY:v,color:e?t.userColor:i.userColor,lineWidth:i.lineWidth,videoWidth:i.videoFeed.videoElement().clientWidth,videoHeight:i.videoFeed.videoElement().clientHeight,canvasWidth:a.width,canvasHeight:a.height,mirrored:c,startPoint:i.isStartPoint,endPoint:!1,selectedItem:y},W(n,!0),f.lastX=m,f.lastY=v,!e&&X(n),i.isStartPoint=!1);break;case"mouseup":case"touchend":f.dragging=!1,n={id:i.videoFeed.stream.connection.connectionId,fromId:i.session.connection.connectionId,fromX:f.lastX,fromY:f.lastY,toX:m,toY:v,color:e?t.userColor:i.userColor,lineWidth:i.lineWidth,videoWidth:i.videoFeed.videoElement().clientWidth,videoHeight:i.videoFeed.videoElement().clientHeight,canvasWidth:a.width,canvasHeight:a.height,mirrored:c,startPoint:i.isStartPoint,endPoint:!0,selectedItem:y},W(n,!0),f.lastX=m,f.lastY=v,!e&&X(n),i.isStartPoint=!1,!e&&_log(_logEventData.actionEndDrawing,_logEventData.variationSuccess);break;case"mouseout":f.dragging=!1}else if("OT_text"===y.id)n={id:i.videoFeed.stream.connection.connectionId,fromId:i.session.connection.connectionId,fromX:m,fromY:v+t.inputHeight,color:t.userColor,font:t.font,text:t.text,videoWidth:i.videoFeed.videoElement().clientWidth,videoHeight:i.videoFeed.videoElement().clientHeight,canvasWidth:a.width,canvasHeight:a.height,mirrored:c,selectedItem:y},W(n),!e&&X(n);else if(y&&y.points)switch(f.mX=m,f.mY=v,t.type){case"mousedown":case"touchstart":f.isDrawing=!0,f.dragging=!0,f.startX=m,f.startY=v;break;case"mousemove":case"touchmove":f.dragging&&(n={color:e?t.userColor:i.userColor,lineWidth:e?t.lineWidth:i.lineWidth,selectedItem:y},W(n,!0));break;case"mouseup":case"touchend":f.isDrawing=!1;var b=y.points;if(2===b.length)n={id:i.videoFeed.stream.connection.connectionId,fromId:i.session.connection.connectionId,fromX:f.startX,fromY:f.startY,toX:f.mX,toY:f.mY,color:e?t.userColor:i.userColor,lineWidth:e?t.lineWidth:i.lineWidth,videoWidth:i.videoFeed.videoElement().clientWidth,videoHeight:i.videoFeed.videoElement().clientHeight,canvasWidth:a.width,canvasHeight:a.height,mirrored:c,smoothed:!1,startPoint:!0,endPoint:!0,selectedItem:y},p.push(n),!e&&X(n);else{for(var w=P(b),I=0;I<b.length;I++){var x=!1,T=!1,_=f.startX+w.x*b[I][0],k=f.startY+w.y*b[I][1];0===I?(f.lastX=_,f.lastY=k,x=!0):I===b.length-1&&(T=!0),n={id:i.videoFeed.stream.connection.connectionId,fromId:i.session.connection.connectionId,fromX:f.lastX,fromY:f.lastY,toX:_,toY:k,color:e?t.userColor:i.userColor,lineWidth:e?t.lineWidth:i.lineWidth,videoWidth:i.videoFeed.videoElement().clientWidth,videoHeight:i.videoFeed.videoElement().clientHeight,canvasWidth:a.width,canvasHeight:a.height,mirrored:c,smoothed:y.enableSmoothing,startPoint:x,endPoint:T},p.push(n),!e&&X(n),f.lastX=_,f.lastY=k}W(null)}f.dragging=!1}}t=t||{},this.widgetVersion="js-1.0.0-beta",this.parent=t.container,this.videoFeed=t.feed;var o=t.externalWindow?t.externalWindow.document:window.document,i=this;if(this.parent){var a=document.createElement("canvas");a.setAttribute("id","opentok_canvas"),a.style.position="absolute",this.parent.appendChild(a),a.setAttribute("width",this.parent.clientWidth+"px"),a.style.width=window.getComputedStyle(this.parent).width,a.setAttribute("height",this.parent.clientHeight+"px"),a.style.height=window.getComputedStyle(this.parent).height}var s,r,c,l,d,i=this,h=[],u=[],p=[],g=[],m=[],f={dragging:!1};r=(" "+i.videoFeed.element.className+" ").indexOf(" OT_publisher ")>-1,c=!!r&&(" "+i.videoFeed.element.className+" ").indexOf(" OT_mirrored ")>-1,l=(" "+i.videoFeed.element.className+" ").indexOf(" OT_fit-mode-cover ")>-1,this.canvas=function(){return a},this.link=function(t){this.session=t},this.changeColor=function(t){i.userColor=t,i.lineWidth||(i.lineWidth=2)},this.changeLineWidth=function(t){this.lineWidth=t},this.selectItem=function(t){i.overlay&&(i.overlay.style.display="none",i.overlay=null),"OT_capture"===t.id?(i.selectedItem=t,i.overlay?i.overlay.style="inline":(i.overlay=document.createElement("div"),i.overlay.style.position="absolute",i.overlay.style.width=i.parent.clientWidth+"px",i.overlay.style.height=i.parent.clientHeight+"px",i.overlay.style.background='rgba(0,0,0,0.4) url("../images/annotation/camera.png") no-repeat center',i.overlay.style.backgroundSize="50px 50px",i.overlay.style.cursor="pointer",i.overlay.style.opacity=0,i.parent.appendChild(i.overlay),i.parent.onmouseover=function(){i.overlay.style.opacity=1},i.parent.onmouseout=function(){i.overlay.style.opacity=0},i.overlay.onclick=function(){i.captureScreenshot()})):t.id.indexOf("OT_line_width")!==-1?t.size&&i.changeLineWidth(t.size):i.selectedItem=t},this.colors=function(t){this.colors=t,this.changeColor(t[0])},this.clear=function(){E(!1,i.session.connection.connectionId),i.session&&i.session.signal({type:"otAnnotation_clear"})},this.captureScreenshot=function(){var t=document.createElement("canvas");t.width=a.width,t.height=a.height;var e=i.videoFeed.videoWidth(),n=i.videoFeed.videoHeight(),o=1,s=0,r=0;l?(e<n?(o=a.width/e,e=a.width,n*=o):(o=a.height/n,n=a.height,e*=o),s=(e-a.width)/2,r=(n-a.height)/2):e>n?(o=a.width/e,e=a.width,n*=o):(o=a.height/n,n=a.height,e*=o);var d=new Image;d.onload=function(){var o=t.getContext("2d");c&&(o.translate(e,0),o.scale(-1,1)),o.drawImage(d,s,r,e,n),c&&(o.translate(e,0),o.scale(-1,1)),o.drawImage(a,0,0),h.forEach(function(e){e.call(i,t.toDataURL())}),t=null},d.src="data:image/png;base64,"+i.videoFeed.getImgData()},this.onScreenCapture=function(t){h.push(t)},this.onResize=function(){p=[],M(g,!0),m.forEach(function(t){n(t,!0)})},e(a,"mousedown mousemove mouseup mouseout touchstart touchmove touchend",function(t){var e=i.selectedItem&&"OT_text"===i.selectedItem.id,o="mousemove"===t.type&&!f.dragging;e||o||(t.preventDefault(),t.selectedItem=i.selectedItem,t.selectedItem&&(t.canvas={width:a.width,height:a.height,offsetLeft:a.offsetLeft,offsetTop:a.offsetTop},t.userColor=i.userColor,t.lineWidth=i.lineWidth,m.push(t)),n(t))});var v,y="textAnnotation",b=!1,w=function(t){t.preventDefault(),i.selectedItem&&"OT_text"===i.selectedItem.id&&!b&&(b=!0,t.selectedItem=i.selectedItem,k(t))},I=function(t){13===t.which&&_(),27===t.which&&(o.getElementById(y).remove(),v=null),b=!1},x=function(){o.addEventListener("keydown",I)},T=function(){o.removeEventListener("keydown",I)},_=function(){var t=o.getElementById(y);t.clientHeight;return t.value?(t.remove(),T(),v.text=t.value,v.font="16px Arial",v.userColor=i.userColor,v.canvas={width:a.width,height:a.height,offsetLeft:a.offsetLeft,offsetTop:a.offsetTop},m.push(v),void n(v)):void(v=null)},k=function(t){var e=o.createElement("input");e.setAttribute("type","text"),e.style.position="absolute",e.style.top=t.clientY+"px",e.style.left=t.clientX+"px",e.style.background="rgba(255,255,255, .5)",e.style.width="100px",e.style.maxWidth="200px",e.style.border="1px dashed red",e.style.fontSize="16px",e.style.color=i.userColor,e.style.fontFamily="Arial",e.style.zIndex="1001",e.setAttribute("data-canvas-origin",JSON.stringify({x:t.offsetX,y:t.offsetY})),e.id=y,o.body.appendChild(e),e.focus(),v=t,v.inputHeight=e.clientHeight,x()};e(a,"click",w);var W=function(t,e){s||(s=a.getContext("2d"),s.lineCap="round",s.lineJoin="round",s.fillStyle="solid"),s.clearRect(0,0,a.width,a.height),p.forEach(function(t){s.strokeStyle=t.color,s.lineWidth=t.lineWidth,t.smoothed=!!t.smoothed,t.startPoint=!!t.startPoint;var e=!1,n=!!t.selectedItem&&"Text"===t.selectedItem.title&&t.text;n?(s.font=t.font,s.fillStyle=t.color,s.fillText(t.text,t.fromX,t.fromY)):t.smoothed?(t.startPoint?i.isStartPoint=!0:i.isStartPoint&&(e=!0,i.isStartPoint=!1),t.startPoint?(s.closePath(),s.beginPath()):e?s.moveTo((t.fromX+t.toX)/2,(t.fromY+t.toY)/2):(s.quadraticCurveTo(t.fromX,t.fromY,(t.fromX+t.toX)/2,(t.fromY+t.toY)/2),s.stroke())):(s.beginPath(),s.moveTo(t.fromX,t.fromY),s.lineTo(t.toX,t.toY),s.stroke(),s.closePath())});var n=e?t.selectedItem:i.selectedItem;!n||"Pen"!==n.title&&"Text"!==n.title?f.isDrawing&&(t&&(s.strokeStyle=t.color,s.lineWidth=t.lineWidth),n&&n.points&&O(s,i.selectedItem.points)):t&&("Pen"===n.title&&(s.strokeStyle=t.color,s.lineWidth=t.lineWidth,s.beginPath(),s.moveTo(t.fromX,t.fromY),s.lineTo(t.toX,t.toY),s.stroke(),s.closePath()),"Text"===n.title&&(s.font=t.font,s.fillStyle=t.color,s.fillText(t.text,t.fromX,t.fromY)),p.push(t))},O=function(t,e){var n=P(e);if(t.beginPath(),2===e.length)t.moveTo(f.startX,f.startY),t.lineTo(f.mX,f.mY);else for(var o=0;o<e.length;o++){var a=f.startX+n.x*e[o][0],s=f.startY+n.y*e[o][1];i.selectedItem.enableSmoothing?0===o||(1===o?(t.moveTo((a+f.lastX)/2,(s+f.lastY)/2),f.lastX=(a+f.lastX)/2,f.lastX=(s+f.lastY)/2):(t.quadraticCurveTo(f.lastX,f.lastY,(a+f.lastX)/2,(s+f.lastY)/2),f.lastX=(a+f.lastX)/2,f.lastY=(s+f.lastY)/2)):0===o?t.moveTo(a,s):t.lineTo(a,s),f.lastX=a,f.lastY=s}t.stroke(),t.closePath()},P=function(t){for(var e=Number.MAX_VALUE,n=Number.MAX_VALUE,o=0,i=0,a=0;a<t.length;a++)t[a][0]<e?e=t[a][0]:t[a][0]>o&&(o=t[a][0]),t[a][1]<n?n=t[a][1]:t[a][1]>i&&(i=t[a][1]);var s=Math.abs(o-e),r=Math.abs(i-n),c=(f.mX-f.startX)/s,l=(f.mY-f.startY)/r;return{x:c,y:l}},C=function(t,e,n){var o={width:t.canvasWidth,height:t.canvasHeight},s={width:t.videoWidth,height:t.videoHeight},r={width:i.videoFeed.videoElement().clientWidth,height:i.videoFeed.videoElement().clientHeight},l=1,d=a.width/a.height;r.width/r.height,o.width/o.height,s.width/s.height;l=d<0?a.width/o.width:a.height/o.height;var h=a.width/2,u=a.height/2,m=o.width/2,f=o.height/2;t.fromX=h-l*(m-t.fromX),t.fromY=u-l*(f-t.fromY),t.toX=h-l*(m-t.toX),t.toY=u-l*(f-t.toY),t.mirrored=!!t.mirrored,t.mirrored&&(t.fromX=a.width-t.fromX,t.toX=a.width-t.toX),c&&(t.fromX=a.width-t.fromX,t.toX=a.width-t.toX);var v=JSON.parse(JSON.stringify(t));v.canvasWidth=a.width,v.canvasHeight=a.height,v.videoWidth=r.width,v.videoHeight=r.height,e?g[n]=v:g.push(v),p.push(t),W(null)},M=function(t,e){t.forEach(function(t,n){i.videoFeed.stream&&t.id===i.videoFeed.stream.connection.connectionId&&C(t,e,n)})},E=function(t,e){p=p.filter(function(t){return console.log(t.fromId),t.fromId!==e}),t?g=[]:(i.session&&i.session.signal({type:"otAnnotation_clear"}),m=[]),W()};i.videoFeed.session&&i.videoFeed.session.on({"signal:otAnnotation_pen":function(t){t.from.connectionId!==i.session.connection.connectionId&&M(JSON.parse(t.data))},"signal:otAnnotation_text":function(t){t.from.connectionId!==i.session.connection.connectionId&&M(JSON.parse(t.data))},"signal:otAnnotation_history":function(t){d&&d!==t.from.connectionId||(d=t.from.connectionId,M(JSON.parse(t.data)))},"signal:otAnnotation_clear":function(t){t.from.connectionId!==i.session.connection.connectionId&&E(!0,t.from.connectionId)},connectionCreated:function(t){p.length>0&&t.connection.connectionId!==i.session.connection.connectionId&&A("otWhiteboard_history",p,t.connection)}});var S,A=function(t,e){for(var n=t.slice(),o=function(t){t&&TB.error(t)},a="otAnnotation_pen",s=function(t){if(t&&t[0]&&t[0].selectedItem&&t[0].selectedItem.id){var e=t[0].selectedItem.id;a="OT_text"===e?"otAnnotation_text":"otAnnotation_pen"}};n.length;){var r=n.splice(0,Math.min(n.length,32));s(r);var c={type:a,data:JSON.stringify(r)};e&&(c.to=e),i.session.signal(c,o)}},X=function(t){i.session&&(u.push(t),S||(S=setTimeout(function(){A(u),u=[],S=null},100)))}},OTSolution.Annotations.Toolbar=function(t){var e=this,n=this;if(t||(t={}),!t.session)throw new Error("OpenTok Annotation Widget requires an OpenTok session");_session=t.session,_otkanalytics||_logAnalytics(),this.session=t.session,this.parent=t.container,this.externalWindow=t.externalWindow,this.backgroundColor=t.backgroundColor||"rgba(0, 0, 0, 0.7)",this.buttonWidth=t.buttonWidth||"40px",this.buttonHeight=t.buttonHeight||"40px",this.iconWidth=t.iconWidth||"30px",this.iconHeight=t.iconHeight||"30px",this.items=t.items||[{id:"OT_pen",title:"Pen",icon:"../images/annotation/freehand.png",selectedIcon:"../images/annotation/freehand_selected.png"},{id:"OT_line",title:"Line",icon:"../images/annotation/line.png",selectedIcon:"../images/annotation/line_selected.png",points:[[0,0],[0,1]]},{id:"OT_shapes",title:"Shapes",icon:"../images/annotation/shapes.png",items:[{id:"OT_arrow",title:"Arrow",icon:"../images/annotation/arrow.png",points:[[0,1],[3,1],[3,0],[5,2],[3,4],[3,3],[0,3],[0,1]]},{id:"OT_rect",title:"Rectangle",icon:"../images/annotation/rectangle.png",points:[[0,0],[1,0],[1,1],[0,1],[0,0]]},{id:"OT_oval",title:"Oval",icon:"../images/annotation/oval.png",enableSmoothing:!0,points:[[0,.5],[.5+.5*Math.cos(5*Math.PI/4),.5+.5*Math.sin(5*Math.PI/4)],[.5,0],[.5+.5*Math.cos(7*Math.PI/4),.5+.5*Math.sin(7*Math.PI/4)],[1,.5],[.5+.5*Math.cos(Math.PI/4),.5+.5*Math.sin(Math.PI/4)],[.5,1],[.5+.5*Math.cos(3*Math.PI/4),.5+.5*Math.sin(3*Math.PI/4)],[0,.5],[.5+.5*Math.cos(5*Math.PI/4),.5+.5*Math.sin(5*Math.PI/4)]]}]},{id:"OT_text",title:"Text",icon:"../images/annotation/text.png",selectedIcon:"../images/annotation/text.png"},{id:"OT_colors",title:"Colors",icon:"",items:{}},{id:"OT_line_width",title:"Line Width",icon:"../images/annotation/line_width.png",items:{}},{id:"OT_clear",title:"Clear",icon:"../images/annotation/clear.png"},{id:"OT_capture",title:"Capture",icon:"../images/annotation/camera.png",selectedIcon:"../images/annotation/camera_selected.png"}],this.colors=t.colors||["#1abc9c","#2ecc71","#3498db","#9b59b6","#34495e","#16a085","#27ae60","#2980b9","#8e44ad","#2c3e50","#f1c40f","#e67e22","#e74c3c","#ecf0f1","#95a5a6","#f39c12","#d35400","#c0392b","#bdc3c7","#7f8c8d"],this.cbs=[];var o,i=[],a=function(t,e,o){var i=this,a=n.externalWindow?n.externalWindow.document:document;this.getElm=function(t){return"string"==typeof t?a.querySelector(t):t},this.render=function(){var t=this,e="";t.colors.forEach(function(n){e+=t.options.template.replace(/\{color\}/g,n)}),t.elm.innerHTML=e},this.close=function(){this.elm.style.display="none"},this.open=function(){this.elm.style.display=this.options.style.display},this.colorChosen=function(t){this.cbs.push(t)},this.set=function(t,e){var n=this;n.color=t,e!==!1&&n.cbs.forEach(function(e){e.call(n,t)})},o=o||{},o.openEvent=o.openEvent||"click",o.style=Object(o.style),o.style.display=o.style.display||"block",o.template=o.template||'<div class="color-choice" data-col="{color}" style="background-color: {color}"></div>',i.elm=i.getElm(t),i.cbs=[],i.colors=e,i.options=o,i.render(),i.elm.addEventListener("click",function(t){var e=t.target.getAttribute("data-col");e&&(i.set(e),i.close())}),o.autoclose!==!1&&i.close()};this.createPanel=function(t){if(n.parent){var r=t?t.document:document;o=r.createElement("div"),o.setAttribute("id","OT_toolbar"),o.setAttribute("class","OT_panel"),o.style.width="100%",o.style.height="100%",o.style.backgroundColor=this.backgroundColor,this.parent.appendChild(o),this.parent.style.position="relative",this.parent.zIndex=1e3;for(var c=[],l=r.createElement("div"),d=0,h=this.items.length;d<h;d++){var u=this.items[d],p=r.createElement("input");if(p.setAttribute("type","button"),p.setAttribute("id",u.id),p.style.position="relative",p.style.top="50%",p.style.transform="translateY(-50%)","OT_colors"===u.id){p.style.webkitTransform="translateY(-85%)";var g=r.createElement("div");g.setAttribute("class","color-picker"),g.style.backgroundColor=this.backgroundColor,this.parent.appendChild(g);var m=new a(".color-picker",this.colors,{externalWindow:n.externalWindow});m.colorChosen(function(t){var e=r.getElementById("OT_colors");e.style.backgroundColor=t,i.forEach(function(e){e.changeColor(t)})});for(var f=r.querySelectorAll(".color-choice"),v=0;v<f.length;v++)f[v].style.display="inline-block",f[v].style.width="30px",f[v].style.height="30px",f[v].style.margin="5px",f[v].style.cursor="pointer",f[v].style.borderRadius="100%",f[v].style.opacity=.7,f[v].onmouseover=function(){this.style.opacity=1},f[v].onmouseout=function(){this.style.opacity=.7};p.setAttribute("class","OT_color"),p.style.marginLeft="10px",p.style.marginRight="10px",p.style.borderRadius="50%",p.style.backgroundColor=this.colors[0],p.style.width=this.iconWidth,p.style.height=this.iconHeight,p.style.paddingTop=this.buttonHeight.replace("px","")-this.iconHeight.replace("px","")+"px"}else p.style.background='url("'+u.icon+'") no-repeat',p.style.backgroundSize=this.iconWidth+" "+this.iconHeight,p.style.backgroundPosition="center",p.style.width=this.buttonWidth,p.style.height=this.buttonHeight;"Line Width"!==u.title||Array.isArray(u.items)||(u.items=[{id:"OT_line_width_2",title:"Line Width 2",size:2},{id:"OT_line_width_4",title:"Line Width 4",size:4},{id:"OT_line_width_6",title:"Line Width 6",size:6},{id:"OT_line_width_8",title:"Line Width 8",size:8},{id:"OT_line_width_10",title:"Line Width 10",size:10},{id:"OT_line_width_12",title:"Line Width 12",size:12},{id:"OT_line_width_14",title:"Line Width 14",size:14}]),u.items&&p.setAttribute("data-type","group"),p.setAttribute("data-col",u.title),p.style.border="none",p.style.cursor="pointer",c.push(p.outerHTML)}o.innerHTML=c.join(""),o.onclick=function(t){var n="group"===t.target.getAttribute("data-type"),o=t.target.getAttribute("data-col"),a=t.target.getAttribute("id");n?e.items.forEach(function(t){if(t.title===o){if(e.selectedGroup=t,t.items&&(l.setAttribute("class","OT_subpanel"),l.style.backgroundColor=e.backgroundColor,l.style.width="100%",l.style.height="100%",l.style.paddingLeft="15px",l.style.display="none",e.parent.appendChild(l),Array.isArray(t.items))){var n=[];"OT_line_width"===t.id?t.items.forEach(function(t){var o=r.createElement("div");o.setAttribute("data-col",t.title),o.setAttribute("id",t.id),o.style.position="relative",o.style.top="50%",o.style.transform="translateY(-50%)",o.style["float"]="left",o.style.width=e.buttonWidth,o.style.height=e.buttonHeight,o.style.border="none",o.style.cursor="pointer";var i=r.createElement("div");i.style.backgroundColor="#FFFFFF",i.style.width="80%",i.style.height=t.size+"px",i.style.position="relative",i.style.left="50%",i.style.top="50%",i.style.transform="translateX(-50%) translateY(-50%)",i.style.pointerEvents="none",o.appendChild(i),n.push(o.outerHTML)}):t.items.forEach(function(t){var o=r.createElement("input");o.setAttribute("type","button"),o.setAttribute("data-col",t.title),o.setAttribute("id",t.id),o.style.background='url("'+t.icon+'") no-repeat',o.style.position="relative",o.style.top="50%",o.style.transform="translateY(-50%)",o.style.backgroundSize=e.iconWidth+" "+e.iconHeight,o.style.backgroundPosition="center",o.style.width=e.buttonWidth,o.style.height=e.buttonHeight,o.style.border="none",o.style.cursor="pointer",n.push(o.outerHTML)}),l.innerHTML=n.join("")}"OT_shapes"===a||"OT_line_width"===a?(l&&(l.style.display="block"),m.close()):"OT_colors"===a&&(l&&(l.style.display="none"),m.open())}}):(e.items.forEach(function(t){if("Clear"!==t.title&&t.title===o){if(e.selectedItem){var n=r.getElementById(e.selectedItem.id);n&&(n.style.background='url("'+e.selectedItem.icon+'") no-repeat',n.style.backgroundSize=e.iconWidth+" "+e.iconHeight,n.style.backgroundPosition="center")}if(t.selectedIcon){var a=r.getElementById(t.id);a&&(a.style.background='url("'+t.selectedIcon+'") no-repeat',a.style.backgroundSize=e.iconWidth+" "+e.iconHeight,a.style.backgroundPosition="center")}return e.selectedItem=t,s(t),i.forEach(function(t){t.selectItem(e.selectedItem)}),!1}}),l.style.display="none"),e.cbs.forEach(function(t){t.call(e,a)})},l.onclick=function(t){var n="group"===t.target.getAttribute("data-type"),o=(t.target.getAttribute("data-col"),t.target.getAttribute("id"));l.style.display="none",n||e.selectedGroup.items.forEach(function(t){if("OT_clear"!==t.id&&t.id===o){if(e.selectedItem){var n=document.getElementById(e.selectedItem.id);n&&(n.style.background='url("'+e.selectedItem.icon+'") no-repeat',n.style.backgroundSize=e.iconWidth+" "+e.iconHeight,n.style.backgroundPosition="center")}if(t.selectedIcon){var a=document.getElementById(t.id);n&&(a.style.background='url("'+t.selectedIcon+'") no-repeat',a.style.backgroundSize=e.iconWidth+" "+e.iconHeight,a.style.backgroundPosition="center")}return e.selectedItem=t,s(t),i.forEach(function(t){t.selectItem(e.selectedItem)}),!1}}),e.cbs.forEach(function(t){t.call(e,o)})},r.getElementById("OT_clear").onclick=function(){i.forEach(function(t){t.clear()})}}},!this.externalWindow&&this.createPanel();var s=function(t){t.points||("OT_line"===t.id?e.selectedItem.points=[[0,0],[0,1]]:"OT_arrow"===t.id?e.selectedItem.points=[[0,1],[3,1],[3,0],[5,2],[3,4],[3,3],[0,3],[0,1]]:"OT_rect"===t.id?e.selectedItem.points=[[0,0],[1,0],[1,1],[0,1],[0,0]]:"OT_oval"===t.id&&(e.selectedItem.enableSmoothing=!0,e.selectedItem.points=[[0,.5],[.5+.5*Math.cos(5*Math.PI/4),.5+.5*Math.sin(5*Math.PI/4)],[.5,0],[.5+.5*Math.cos(7*Math.PI/4),.5+.5*Math.sin(7*Math.PI/4)],[1,.5],[.5+.5*Math.cos(Math.PI/4),.5+.5*Math.sin(Math.PI/4)],[.5,1],[.5+.5*Math.cos(3*Math.PI/4),.5+.5*Math.sin(3*Math.PI/4)],[0,.5],[.5+.5*Math.cos(5*Math.PI/4),.5+.5*Math.sin(5*Math.PI/4)]]))};this.itemClicked=function(t){this.cbs.push(t)},this.addCanvas=function(t){var e=this;t.link(e.session),t.colors(e.colors),i.push(t)},this.removeCanvas=function(t){i.forEach(function(e){var n=e.canvas();e.videoFeed.stream.connection.connectionId===t&&n.parentNode&&n.parentNode.removeChild(n)}),i=i.filter(function(e){return e.videoFeed.stream.connection.connectionId!==t})},this.remove=function(){try{o.parentNode.removeChild(o)}catch(t){console.log(t)}i.forEach(function(t){var e=t.canvas();e.parentNode&&e.parentNode.removeChild(e)}),i=[]}},function(){var t,e,n;"object"==typeof module&&"object"==typeof module.exports?(t=require("underscore"),e=require("jquery"),n=require("opentok-solutions-logging")):(t=this._,e=this.$,n=this.OTKAnalytics);var o,i,a,s,r,c={},l={clientVersion:"js-vsol-1.0.0",componentId:"annotationsAccPack",name:"guidAnnotationsKit",actionInitialize:"Init",actionStart:"Start",actionEnd:"End",actionFreeHand:"Free Hand",actionPickerColor:"Picker Color",actionText:"Text",actionScreenCapture:"Screen Capture",actionErase:"Erase",actionUseToolbar:"Use Toolbar",variationAttempt:"Attempt",variationError:"Failure",variationSuccess:"Success"},d=function(){var t=window.location.href,e={clientVersion:l.clientVersion,source:t,componentId:l.componentId,name:l.name};r=new n(e);var o={sessionId:a.id,connectionId:a.connection.connectionId,partnerId:a.apiKey};r.addSessionInfo(o)},h=function(t,e){var n={action:t,variation:e};r.logEvent(n)},u=function(t,e){i&&i.triggerEvent(t,e)},p=function(){var t=["startAnnotation","linkAnnotation","resizeCanvas","annotationWindowClosed","endAnnotation"];i.registerEvents(t)},g=function(){var t=['<div id="annotationToolbarContainer" class="annotation-toolbar-container">','<div id="toolbar"></div>',"</div>"].join("\n");e("body").append(t),h(l.actionUseToolbar,l.variationSuccess)},m=[{id:"OT_pen",title:"Pen",icon:"../images/annotation/freehand.png",selectedIcon:"../images/annotation/freehand_selected.png"},{id:"OT_line",title:"Line",icon:"../images/annotation/line.png",selectedIcon:"../images/annotation/line_selected.png"},{id:"OT_text",title:"Text",icon:"../images/annotation/text.png",selectedIcon:"../images/annotation/text.png"},{id:"OT_shapes",title:"Shapes",icon:"../images/annotation/shapes.png",items:[{id:"OT_arrow",title:"Arrow",icon:"../images/annotation/arrow.png"},{id:"OT_rect",title:"Rectangle",icon:"../images/annotation/rectangle.png"},{id:"OT_oval",title:"Oval",icon:"../images/annotation/oval.png"},{id:"OT_star",title:"Star",icon:"../images/annotation/star.png",points:[[.5+.5*Math.cos(90*(Math.PI/180)),.5+.5*Math.sin(90*(Math.PI/180))],[.5+.25*Math.cos(126*(Math.PI/180)),.5+.25*Math.sin(126*(Math.PI/180))],[.5+.5*Math.cos(162*(Math.PI/180)),.5+.5*Math.sin(162*(Math.PI/180))],[.5+.25*Math.cos(198*(Math.PI/180)),.5+.25*Math.sin(198*(Math.PI/180))],[.5+.5*Math.cos(234*(Math.PI/180)),.5+.5*Math.sin(234*(Math.PI/180))],[.5+.25*Math.cos(270*(Math.PI/180)),.5+.25*Math.sin(270*(Math.PI/180))],[.5+.5*Math.cos(306*(Math.PI/180)),.5+.5*Math.sin(306*(Math.PI/180))],[.5+.25*Math.cos(342*(Math.PI/180)),.5+.25*Math.sin(342*(Math.PI/180))],[.5+.5*Math.cos(18*(Math.PI/180)),.5+.5*Math.sin(18*(Math.PI/180))],[.5+.25*Math.cos(54*(Math.PI/180)),.5+.25*Math.sin(54*(Math.PI/180))],[.5+.5*Math.cos(90*(Math.PI/180)),.5+.5*Math.sin(90*(Math.PI/180))]]}]},{id:"OT_colors",title:"Colors",icon:"",items:{}},{id:"OT_line_width",title:"Line Width",icon:"../images/annotation/line_width.png",items:{}},{id:"OT_clear",title:"Clear",icon:"../images/annotation/clear.png"}],f=["#1abc9c","#2ecc71","#3498db","#9b59b6","#8e44ad","#f1c40f","#e67e22","#e74c3c","#ded5d5"],v=10/6,y=t.throttle(function(){s.onResize()},1e3),b=function(){var t,n;if(c.externalWindow){var o={width:c.externalWindow.innerWidth,height:c.externalWindow.innerHeight},i=o.width/v;i<=o.height?(t=o.width,n=i):(n=o.height,t=n*v)}else{var a=c.absoluteParent||c.canvasContainer;t=e(a).width(),n=e(a).height()}e(c.canvasContainer).css({width:t,height:n}),e(c.canvasContainer).find("canvas").css({width:t,height:n}),e(c.canvasContainer).find("canvas").attr({width:t,height:n}),y(),u("resizeCanvas")},w=function(){e(c.resizeSubject).on("resize",t.throttle(function(){b()},500))},I=function(e,n,o){var i=t.property("toolbarId")(n)||"toolbar",a=t.property("toolbarItems")(n)||m,s=t.property("colors")(n)||f,r=function(){var t=o?o:window;return t.document.getElementById(i)};toolbar=new OTSolution.Annotations.Toolbar({session:e,container:r(),colors:s,items:a,externalWindow:o||null}),toolbar.itemClicked(function(t){var e={OT_pen:l.actionFreeHand,OT_colors:l.actionPickerColor,OT_text:l.actionText,OT_clear:l.actionErase},n=e[t];n&&h(n,l.variationSuccess)})},x=function(){var t=e.Deferred(),n=.8*screen.width|0,o=n/v,i='<!DOCTYPE html><html lang="en"><head><meta http-equiv="Content-type" content="text/html; charset=utf-8"><title>OpenTok Screen Sharing Solution Annotation</title><script type="text/javascript" charset="utf-8">var opener,canvas;toolbar?(opener=window.opener,window.onbeforeunload=window.triggerCloseEvent):alert("Something went wrong: You must pass an OpenTok annotation toolbar object into the window.");var createContainerElements=function(){var e=document.getElementById("annotationContainer"),n=document.createElement("div");return n.setAttribute("id","screenshare_publisher"),n.classList.add("publisher-wrap"),e.appendChild(n),{annotation:e,publisher:n}};if(-1!==navigator.userAgent.indexOf("Firefox")){var ghost=window.open("about:blank");ghost.focus(),ghost.close()}</script><style type="text/css" media="screen"> body{margin:0;background-color:rgba(0,153,203,.7);box-sizing:border-box;height:100vh}canvas{top:0;z-index:1000}.main-wrap{width:100%;height:100%;-ms-box-orient:horizontal;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-moz-flex;display:-webkit-flex;display:flex;-webkit-justify-content:center;justify-content:center;-webkit-align-items:center;align-items:center}.inner-wrap{position:relative;border-radius:8px;overflow:hidden}.fixed-container{position:fixed;top:275px;right:0;width:40px;z-index:1001}.fixed-container .toolbar-wrap{position:absolute;top:0;left:0}.fixed-container .toolbar-wrap input{display:block;top:0!important;transform:none!important}.fixed-container .toolbar-wrap .OT_color{width:30px;margin-right:5px!important;margin-left:5px!important;padding:0}.fixed-container .toolbar-wrap .OT_subpanel,.fixed-container .toolbar-wrap .color-picker{position:absolute;top:0;right:40px;padding-left:0!important;overflow:hidden}.fixed-container .toolbar-wrap .OT_subpanel>div{top:0!important;transform:none!important}.fixed-container .toolbar-wrap .color-picker{left:-30px}.fixed-container .toolbar-wrap .color-picker .color-choice{display:block!important;height:20px!important;width:20px!important}.publisherContainer{display:block;background-color:#000;position:absolute}.OT_video-element,.publisher-wrap{height:100%;width:100%}.OT_edge-bar-item{display:none}</style></head><body> <div class="main-wrap"> <div id="annotationContainer" class="inner-wrap"></div> </div> <div id="toolbarContainer" class="fixed-container"> <div id="toolbar" class="toolbar-wrap"></div> </div></body></html>',a=["toolbar=no","location=no","directories=no","status=no","menubar=no","scrollbars=no","resizable=no","copyhistory=no",["width=",n].join(""),["height=",o].join(""),["left=",screen.width/2-n/2].join(""),["top=",screen.height/2-o/2].join("")].join(","),s=window.open("about:blank","",a);s.document.write(i),window.onbeforeunload=function(){s.close()},s.toolbar=toolbar,s.OT=OT,s.$=e,s.triggerCloseEvent=function(){u("annotationWindowClosed")};var r=function(){s.createContainerElements?e(s.document).ready(function(){t.resolve(s)}):setTimeout(r,100)};return r(),t.promise()},T=function(){e(c.resizeSubject).off("resize",b),toolbar.remove(),c.externalWindow||e("#annotationToolbarContainer").remove()},_=function(n,o){var i=e.Deferred();return t.property("screensharing")(o)?x().then(function(t){I(n,o,t),toolbar.createPanel(t),u("startAnnotation",t),h(l.actionStart,l.variationSuccess),i.resolve(t)}):(I(n,o),u("startAnnotation"),h(l.actionStart,l.variationSuccess),i.resolve()),i.promise()},k=function(n,o,i){c.resizeSubject=t.property("externalWindow")(i)||window,c.externalWindow=t.property("externalWindow")(i)||null,c.absoluteParent=t.property("absoluteParent")(i)||null,c.canvasContainer=o,s=new OTSolution.Annotations({feed:n,container:o,externalWindow:c.externalWindow}),toolbar.addCanvas(s),s.onScreenCapture(function(t){var e=window.open(t,"_blank");e.focus()});var a=c.externalWindow?c.externalWindow:window;c.canvas=e(t.first(a.document.getElementsByTagName("canvas"))),w(),b(),u("linkAnnotation")},W=function(){b()},O=function(t){T(),c.canvas=null,t&&(c.externalWindow&&(c.externalWindow.close(),c.externalWindow=null,c.resizeSubject=null),u("endAnnotation")),h(l.actionEnd,l.variationSuccess)},P=function(e){if(o=this,o.options=t.omit(e,"accPack","session"),i=t.property("accPack")(e),a=t.property("session")(e),!a)throw new Error("OpenTok Annotation Accelerator Pack requires an OpenTok session");p(),d(),h(l.actionInitialize,l.variationSuccess),g()};P.prototype={constructor:P,start:_,linkCanvas:k,resizeCanvas:W,end:O},"object"==typeof exports?module.exports=P:"function"==typeof define&&define.amd?define(function(){return P}):this.AnnotationAccPack=P}.call(this);
(function(){var t,e,n,o={clientVersion:"js-vsol-1.0.0",componentId:"annotationsAccPack",name:"guidAnnotationsKit",actionStartDrawing:"Start Drawing",actionEndDrawing:"End Drawing",variationSuccess:"Success"},i=function(){var i=window.location.href,a={clientVersion:o.clientVersion,source:i,componentId:o.componentId,name:o.name};e=new t(a);var s={sessionId:n.id,connectionId:n.connection.connectionId,partnerId:n.apiKey};e.addSessionInfo(s)},a=function(t,n){var o={action:t,variation:n};e.logEvent(o)};OTSolution=this.OTSolution||{},console.log("ello"),OTSolution.Annotations=function(n){function s(t,e,n){for(var o=e.split(" "),i=0,a=o.length;i<a;i++)t.addEventListener(o[i],n,!0)}function r(t,e){0===d.width&&(d.width=l.parent.getBoundingClientRect().width),0===d.height&&(d.height=l.parent.getBoundingClientRect().height);var n,i=e?t.canvas.width:l.parent.clientWidth,s=e?t.canvas.height:l.parent.clientHeight,r=e?t.canvas.offsetLeft:d.offsetLeft,c=e?t.canvas.offsetTop:d.offsetTop,h=d.width/i,u=d.height/s,g=t.offsetX||t.pageX-r||t.changedTouches&&t.changedTouches[0].pageX-r,m=t.offsetY||t.pageY-c||t.changedTouches&&t.changedTouches[0].pageY-c,f=g*h,v=m*u,b=e?t.selectedItem:l.selectedItem;if(b)if("OT_pen"===b.id)switch(t.type){case"mousedown":case"touchstart":I.dragging=!0,I.lastX=f,I.lastY=v,l.isStartPoint=!0,!e&&a(o.actionStartDrawing,o.variationSuccess);break;case"mousemove":case"touchmove":I.dragging&&(n={id:l.videoFeed.stream.connection.connectionId,fromId:l.session.connection.connectionId,fromX:I.lastX,fromY:I.lastY,toX:f,toY:v,color:e?t.userColor:l.userColor,lineWidth:l.lineWidth,videoWidth:l.videoFeed.videoElement().clientWidth,videoHeight:l.videoFeed.videoElement().clientHeight,canvasWidth:d.width,canvasHeight:d.height,mirrored:p,startPoint:l.isStartPoint,endPoint:!1,selectedItem:b},E(n,!0),I.lastX=f,I.lastY=v,!e&&L(n),l.isStartPoint=!1);break;case"mouseup":case"touchend":I.dragging=!1,n={id:l.videoFeed.stream.connection.connectionId,fromId:l.session.connection.connectionId,fromX:I.lastX,fromY:I.lastY,toX:f,toY:v,color:e?t.userColor:l.userColor,lineWidth:l.lineWidth,videoWidth:l.videoFeed.videoElement().clientWidth,videoHeight:l.videoFeed.videoElement().clientHeight,canvasWidth:d.width,canvasHeight:d.height,mirrored:p,startPoint:l.isStartPoint,endPoint:!0,selectedItem:b},E(n,!0),I.lastX=f,I.lastY=v,!e&&L(n),l.isStartPoint=!1,!e&&a(o.actionEndDrawing,o.variationSuccess);break;case"mouseout":I.dragging=!1}else if("OT_text"===b.id)n={id:l.videoFeed.stream.connection.connectionId,fromId:l.session.connection.connectionId,fromX:f,fromY:v+t.inputHeight,color:t.userColor,font:t.font,text:t.text,videoWidth:l.videoFeed.videoElement().clientWidth,videoHeight:l.videoFeed.videoElement().clientHeight,canvasWidth:d.width,canvasHeight:d.height,mirrored:p,selectedItem:b},E(n),!e&&L(n);else if(b&&b.points)switch(I.mX=f,I.mY=v,t.type){case"mousedown":case"touchstart":I.isDrawing=!0,I.dragging=!0,I.startX=f,I.startY=v;break;case"mousemove":case"touchmove":I.dragging&&(n={color:e?t.userColor:l.userColor,lineWidth:e?t.lineWidth:l.lineWidth,selectedItem:b},E(n,!0));break;case"mouseup":case"touchend":I.isDrawing=!1;var w=b.points;if(2===w.length)n={id:l.videoFeed.stream.connection.connectionId,fromId:l.session.connection.connectionId,fromX:I.startX,fromY:I.startY,toX:I.mX,toY:I.mY,color:e?t.userColor:l.userColor,lineWidth:e?t.lineWidth:l.lineWidth,videoWidth:l.videoFeed.videoElement().clientWidth,videoHeight:l.videoFeed.videoElement().clientHeight,canvasWidth:d.width,canvasHeight:d.height,mirrored:p,smoothed:!1,startPoint:!0,endPoint:!0,selectedItem:b},y.push(n),!e&&L(n);else{for(var T=A(w),x=0;x<w.length;x++){var _=!1,W=!1,k=I.startX+T.x*w[x][0],O=I.startY+T.y*w[x][1];0===x?(I.lastX=k,I.lastY=O,_=!0):x===w.length-1&&(W=!0),n={id:l.videoFeed.stream.connection.connectionId,fromId:l.session.connection.connectionId,fromX:I.lastX,fromY:I.lastY,toX:k,toY:O,color:e?t.userColor:l.userColor,lineWidth:e?t.lineWidth:l.lineWidth,videoWidth:l.videoFeed.videoElement().clientWidth,videoHeight:l.videoFeed.videoElement().clientHeight,canvasWidth:d.width,canvasHeight:d.height,mirrored:p,smoothed:b.enableSmoothing,startPoint:_,endPoint:W},y.push(n),!e&&L(n),I.lastX=k,I.lastY=O}E(null)}I.dragging=!1}}n=n||{},this.widgetVersion="js-1.0.0-beta",this.parent=n.container,this.videoFeed=n.feed,t=t||n.OTKAnalytics,e||i();var c=n.externalWindow?n.externalWindow.document:window.document,l=this;if(this.parent){var d=document.createElement("canvas");d.setAttribute("id","opentok_canvas"),d.style.position="absolute",this.parent.appendChild(d),d.setAttribute("width",this.parent.clientWidth+"px"),d.style.width=window.getComputedStyle(this.parent).width,d.setAttribute("height",this.parent.clientHeight+"px"),d.style.height=window.getComputedStyle(this.parent).height}var h,u,p,g,m,l=this,f=[],v=[],y=[],b=[],w=[],I={dragging:!1};u=(" "+l.videoFeed.element.className+" ").indexOf(" OT_publisher ")>-1,p=!!u&&(" "+l.videoFeed.element.className+" ").indexOf(" OT_mirrored ")>-1,g=(" "+l.videoFeed.element.className+" ").indexOf(" OT_fit-mode-cover ")>-1,this.canvas=function(){return d},this.link=function(t){this.session=t},this.changeColor=function(t){l.userColor=t,l.lineWidth||(l.lineWidth=2)},this.changeLineWidth=function(t){this.lineWidth=t},this.selectItem=function(t){l.overlay&&(l.overlay.style.display="none",l.overlay=null),"OT_capture"===t.id?(l.selectedItem=t,l.overlay?l.overlay.style="inline":(l.overlay=document.createElement("div"),l.overlay.style.position="absolute",l.overlay.style.width=l.parent.clientWidth+"px",l.overlay.style.height=l.parent.clientHeight+"px",l.overlay.style.background='rgba(0,0,0,0.4) url("../images/annotation/camera.png") no-repeat center',l.overlay.style.backgroundSize="50px 50px",l.overlay.style.cursor="pointer",l.overlay.style.opacity=0,l.parent.appendChild(l.overlay),l.parent.onmouseover=function(){l.overlay.style.opacity=1},l.parent.onmouseout=function(){l.overlay.style.opacity=0},l.overlay.onclick=function(){l.captureScreenshot()})):t.id.indexOf("OT_line_width")!==-1?t.size&&l.changeLineWidth(t.size):l.selectedItem=t},this.colors=function(t){this.colors=t,this.changeColor(t[0])},this.clear=function(){H(!1,l.session.connection.connectionId),l.session&&l.session.signal({type:"otAnnotation_clear"})},this.captureScreenshot=function(){var t=document.createElement("canvas");t.width=d.width,t.height=d.height;var e=l.videoFeed.videoWidth(),n=l.videoFeed.videoHeight(),o=1,i=0,a=0;g?(e<n?(o=d.width/e,e=d.width,n*=o):(o=d.height/n,n=d.height,e*=o),i=(e-d.width)/2,a=(n-d.height)/2):e>n?(o=d.width/e,e=d.width,n*=o):(o=d.height/n,n=d.height,e*=o);var s=new Image;s.onload=function(){var o=t.getContext("2d");p&&(o.translate(e,0),o.scale(-1,1)),o.drawImage(s,i,a,e,n),p&&(o.translate(e,0),o.scale(-1,1)),o.drawImage(d,0,0),f.forEach(function(e){e.call(l,t.toDataURL())}),t=null},s.src="data:image/png;base64,"+l.videoFeed.getImgData()},this.onScreenCapture=function(t){f.push(t)},this.onResize=function(){y=[],Y(b,!0),w.forEach(function(t){r(t,!0)})},s(d,"mousedown mousemove mouseup mouseout touchstart touchmove touchend",function(t){var e=l.selectedItem&&"OT_text"===l.selectedItem.id,n="mousemove"===t.type&&!I.dragging;e||n||(t.preventDefault(),t.selectedItem=l.selectedItem,t.selectedItem&&(t.canvas={width:d.width,height:d.height,offsetLeft:d.offsetLeft,offsetTop:d.offsetTop},t.userColor=l.userColor,t.lineWidth=l.lineWidth,w.push(t)),r(t))});var T,x="textAnnotation",_=!1,W=function(t){t.preventDefault(),l.selectedItem&&"OT_text"===l.selectedItem.id&&!_&&(_=!0,t.selectedItem=l.selectedItem,M(t))},k=function(t){13===t.which&&C(),27===t.which&&(c.getElementById(x).remove(),T=null),_=!1},O=function(){c.addEventListener("keydown",k)},P=function(){c.removeEventListener("keydown",k)},C=function(){var t=c.getElementById(x);t.clientHeight;return t.value?(t.remove(),P(),T.text=t.value,T.font="16px Arial",T.userColor=l.userColor,T.canvas={width:d.width,height:d.height,offsetLeft:d.offsetLeft,offsetTop:d.offsetTop},w.push(T),void r(T)):void(T=null)},M=function(t){var e=c.createElement("input");e.setAttribute("type","text"),e.style.position="absolute",e.style.top=t.clientY+"px",e.style.left=t.clientX+"px",e.style.background="rgba(255,255,255, .5)",e.style.width="100px",e.style.maxWidth="200px",e.style.border="1px dashed red",e.style.fontSize="16px",e.style.color=l.userColor,e.style.fontFamily="Arial",e.style.zIndex="1001",e.setAttribute("data-canvas-origin",JSON.stringify({x:t.offsetX,y:t.offsetY})),e.id=x,c.body.appendChild(e),e.focus(),T=t,T.inputHeight=e.clientHeight,O()};s(d,"click",W);var E=function(t,e){h||(h=d.getContext("2d"),h.lineCap="round",h.lineJoin="round",h.fillStyle="solid"),h.clearRect(0,0,d.width,d.height),y.forEach(function(t){h.strokeStyle=t.color,h.lineWidth=t.lineWidth,t.smoothed=!!t.smoothed,t.startPoint=!!t.startPoint;var e=!1,n=!!t.selectedItem&&"Text"===t.selectedItem.title&&t.text;n?(h.font=t.font,h.fillStyle=t.color,h.fillText(t.text,t.fromX,t.fromY)):t.smoothed?(t.startPoint?l.isStartPoint=!0:l.isStartPoint&&(e=!0,l.isStartPoint=!1),t.startPoint?(h.closePath(),h.beginPath()):e?h.moveTo((t.fromX+t.toX)/2,(t.fromY+t.toY)/2):(h.quadraticCurveTo(t.fromX,t.fromY,(t.fromX+t.toX)/2,(t.fromY+t.toY)/2),h.stroke())):(h.beginPath(),h.moveTo(t.fromX,t.fromY),h.lineTo(t.toX,t.toY),h.stroke(),h.closePath())});var n=e?t.selectedItem:l.selectedItem;!n||"Pen"!==n.title&&"Text"!==n.title?I.isDrawing&&(t&&(h.strokeStyle=t.color,h.lineWidth=t.lineWidth),n&&n.points&&S(h,l.selectedItem.points)):t&&("Pen"===n.title&&(h.strokeStyle=t.color,h.lineWidth=t.lineWidth,h.beginPath(),h.moveTo(t.fromX,t.fromY),h.lineTo(t.toX,t.toY),h.stroke(),h.closePath()),"Text"===n.title&&(h.font=t.font,h.fillStyle=t.color,h.fillText(t.text,t.fromX,t.fromY)),y.push(t))},S=function(t,e){var n=A(e);if(t.beginPath(),2===e.length)t.moveTo(I.startX,I.startY),t.lineTo(I.mX,I.mY);else for(var o=0;o<e.length;o++){var i=I.startX+n.x*e[o][0],a=I.startY+n.y*e[o][1];l.selectedItem.enableSmoothing?0===o||(1===o?(t.moveTo((i+I.lastX)/2,(a+I.lastY)/2),I.lastX=(i+I.lastX)/2,I.lastX=(a+I.lastY)/2):(t.quadraticCurveTo(I.lastX,I.lastY,(i+I.lastX)/2,(a+I.lastY)/2),I.lastX=(i+I.lastX)/2,I.lastY=(a+I.lastY)/2)):0===o?t.moveTo(i,a):t.lineTo(i,a),I.lastX=i,I.lastY=a}t.stroke(),t.closePath()},A=function(t){for(var e=Number.MAX_VALUE,n=Number.MAX_VALUE,o=0,i=0,a=0;a<t.length;a++)t[a][0]<e?e=t[a][0]:t[a][0]>o&&(o=t[a][0]),t[a][1]<n?n=t[a][1]:t[a][1]>i&&(i=t[a][1]);var s=Math.abs(o-e),r=Math.abs(i-n),c=(I.mX-I.startX)/s,l=(I.mY-I.startY)/r;return{x:c,y:l}},X=function(t,e,n){var o={width:t.canvasWidth,height:t.canvasHeight},i={width:t.videoWidth,height:t.videoHeight},a={width:l.videoFeed.videoElement().clientWidth,height:l.videoFeed.videoElement().clientHeight},s=1,r=d.width/d.height;a.width/a.height,o.width/o.height,i.width/i.height;s=r<0?d.width/o.width:d.height/o.height;var c=d.width/2,h=d.height/2,u=o.width/2,g=o.height/2;t.fromX=c-s*(u-t.fromX),t.fromY=h-s*(g-t.fromY),t.toX=c-s*(u-t.toX),t.toY=h-s*(g-t.toY),t.mirrored=!!t.mirrored,t.mirrored&&(t.fromX=d.width-t.fromX,t.toX=d.width-t.toX),p&&(t.fromX=d.width-t.fromX,t.toX=d.width-t.toX);var m=JSON.parse(JSON.stringify(t));m.canvasWidth=d.width,m.canvasHeight=d.height,m.videoWidth=a.width,m.videoHeight=a.height,e?b[n]=m:b.push(m),y.push(t),E(null)},Y=function(t,e){t.forEach(function(t,n){l.videoFeed.stream&&t.id===l.videoFeed.stream.connection.connectionId&&X(t,e,n)})},H=function(t,e){y=y.filter(function(t){return console.log(t.fromId),t.fromId!==e}),t?b=[]:(l.session&&l.session.signal({type:"otAnnotation_clear"}),w=[]),E()};l.videoFeed.session&&l.videoFeed.session.on({"signal:otAnnotation_pen":function(t){t.from.connectionId!==l.session.connection.connectionId&&Y(JSON.parse(t.data))},"signal:otAnnotation_text":function(t){t.from.connectionId!==l.session.connection.connectionId&&Y(JSON.parse(t.data))},"signal:otAnnotation_history":function(t){m&&m!==t.from.connectionId||(m=t.from.connectionId,Y(JSON.parse(t.data)))},"signal:otAnnotation_clear":function(t){t.from.connectionId!==l.session.connection.connectionId&&H(!0,t.from.connectionId)},connectionCreated:function(t){y.length>0&&t.connection.connectionId!==l.session.connection.connectionId&&z("otWhiteboard_history",y,t.connection)}});var F,z=function(t,e){for(var n=t.slice(),o=function(t){t&&TB.error(t)},i="otAnnotation_pen",a=function(t){if(t&&t[0]&&t[0].selectedItem&&t[0].selectedItem.id){var e=t[0].selectedItem.id;i="OT_text"===e?"otAnnotation_text":"otAnnotation_pen"}};n.length;){var s=n.splice(0,Math.min(n.length,32));a(s);var r={type:i,data:JSON.stringify(s)};e&&(r.to=e),l.session.signal(r,o)}},L=function(t){l.session&&(v.push(t),F||(F=setTimeout(function(){z(v),v=[],F=null},100)))}},OTSolution.Annotations.Toolbar=function(o){var a=this,s=this;if(o||(o={}),!o.session)throw new Error("OpenTok Annotation Widget requires an OpenTok session");if(n=o.session,!t&&!o.OTKAnalytics)throw new Error("OpenTok Annotation Widget requires an OpenTok Solution");t=t||o.OTKAnalytics,e||i(),this.session=o.session,this.parent=o.container,this.externalWindow=o.externalWindow,this.backgroundColor=o.backgroundColor||"rgba(0, 0, 0, 0.7)",this.buttonWidth=o.buttonWidth||"40px",this.buttonHeight=o.buttonHeight||"40px",this.iconWidth=o.iconWidth||"30px",this.iconHeight=o.iconHeight||"30px",this.items=o.items||[{id:"OT_pen",title:"Pen",icon:"../images/annotation/freehand.png",selectedIcon:"../images/annotation/freehand_selected.png"},{id:"OT_line",title:"Line",icon:"../images/annotation/line.png",selectedIcon:"../images/annotation/line_selected.png",points:[[0,0],[0,1]]},{id:"OT_shapes",title:"Shapes",icon:"../images/annotation/shapes.png",items:[{id:"OT_arrow",title:"Arrow",icon:"../images/annotation/arrow.png",points:[[0,1],[3,1],[3,0],[5,2],[3,4],[3,3],[0,3],[0,1]]},{id:"OT_rect",title:"Rectangle",icon:"../images/annotation/rectangle.png",points:[[0,0],[1,0],[1,1],[0,1],[0,0]]},{id:"OT_oval",title:"Oval",icon:"../images/annotation/oval.png",enableSmoothing:!0,points:[[0,.5],[.5+.5*Math.cos(5*Math.PI/4),.5+.5*Math.sin(5*Math.PI/4)],[.5,0],[.5+.5*Math.cos(7*Math.PI/4),.5+.5*Math.sin(7*Math.PI/4)],[1,.5],[.5+.5*Math.cos(Math.PI/4),.5+.5*Math.sin(Math.PI/4)],[.5,1],[.5+.5*Math.cos(3*Math.PI/4),.5+.5*Math.sin(3*Math.PI/4)],[0,.5],[.5+.5*Math.cos(5*Math.PI/4),.5+.5*Math.sin(5*Math.PI/4)]]}]},{id:"OT_text",title:"Text",icon:"../images/annotation/text.png",selectedIcon:"../images/annotation/text.png"},{id:"OT_colors",title:"Colors",icon:"",items:{}},{id:"OT_line_width",title:"Line Width",icon:"../images/annotation/line_width.png",items:{}},{id:"OT_clear",title:"Clear",icon:"../images/annotation/clear.png"},{id:"OT_capture",title:"Capture",icon:"../images/annotation/camera.png",selectedIcon:"../images/annotation/camera_selected.png"}],this.colors=o.colors||["#1abc9c","#2ecc71","#3498db","#9b59b6","#34495e","#16a085","#27ae60","#2980b9","#8e44ad","#2c3e50","#f1c40f","#e67e22","#e74c3c","#ecf0f1","#95a5a6","#f39c12","#d35400","#c0392b","#bdc3c7","#7f8c8d"],this.cbs=[];var r,c=[],l=function(t,e,n){var o=this,i=s.externalWindow?s.externalWindow.document:document;this.getElm=function(t){return"string"==typeof t?i.querySelector(t):t},this.render=function(){var t=this,e="";t.colors.forEach(function(n){e+=t.options.template.replace(/\{color\}/g,n)}),t.elm.innerHTML=e},this.close=function(){this.elm.style.display="none"},this.open=function(){this.elm.style.display=this.options.style.display},this.colorChosen=function(t){this.cbs.push(t)},this.set=function(t,e){var n=this;n.color=t,e!==!1&&n.cbs.forEach(function(e){e.call(n,t)})},n=n||{},n.openEvent=n.openEvent||"click",n.style=Object(n.style),n.style.display=n.style.display||"block",n.template=n.template||'<div class="color-choice" data-col="{color}" style="background-color: {color}"></div>',o.elm=o.getElm(t),o.cbs=[],o.colors=e,o.options=n,o.render(),o.elm.addEventListener("click",function(t){var e=t.target.getAttribute("data-col");e&&(o.set(e),o.close())}),n.autoclose!==!1&&o.close()};this.createPanel=function(t){if(s.parent){var e=t?t.document:document;r=e.createElement("div"),r.setAttribute("id","OT_toolbar"),r.setAttribute("class","OT_panel"),r.style.width="100%",r.style.height="100%",r.style.backgroundColor=this.backgroundColor,this.parent.appendChild(r),this.parent.style.position="relative",this.parent.zIndex=1e3;for(var n=[],o=e.createElement("div"),i=0,h=this.items.length;i<h;i++){var u=this.items[i],p=e.createElement("input");if(p.setAttribute("type","button"),p.setAttribute("id",u.id),p.style.position="relative",p.style.top="50%",p.style.transform="translateY(-50%)","OT_colors"===u.id){p.style.webkitTransform="translateY(-85%)";var g=e.createElement("div");g.setAttribute("class","color-picker"),g.style.backgroundColor=this.backgroundColor,this.parent.appendChild(g);var m=new l(".color-picker",this.colors,{externalWindow:s.externalWindow});m.colorChosen(function(t){var n=e.getElementById("OT_colors");n.style.backgroundColor=t,c.forEach(function(e){e.changeColor(t)})});for(var f=e.querySelectorAll(".color-choice"),v=0;v<f.length;v++)f[v].style.display="inline-block",f[v].style.width="30px",f[v].style.height="30px",f[v].style.margin="5px",f[v].style.cursor="pointer",f[v].style.borderRadius="100%",f[v].style.opacity=.7,f[v].onmouseover=function(){this.style.opacity=1},f[v].onmouseout=function(){this.style.opacity=.7};p.setAttribute("class","OT_color"),p.style.marginLeft="10px",p.style.marginRight="10px",p.style.borderRadius="50%",p.style.backgroundColor=this.colors[0],p.style.width=this.iconWidth,p.style.height=this.iconHeight,p.style.paddingTop=this.buttonHeight.replace("px","")-this.iconHeight.replace("px","")+"px"}else p.style.background='url("'+u.icon+'") no-repeat',p.style.backgroundSize=this.iconWidth+" "+this.iconHeight,p.style.backgroundPosition="center",p.style.width=this.buttonWidth,p.style.height=this.buttonHeight;"Line Width"!==u.title||Array.isArray(u.items)||(u.items=[{id:"OT_line_width_2",title:"Line Width 2",size:2},{id:"OT_line_width_4",title:"Line Width 4",size:4},{id:"OT_line_width_6",title:"Line Width 6",size:6},{id:"OT_line_width_8",title:"Line Width 8",size:8},{id:"OT_line_width_10",title:"Line Width 10",size:10},{id:"OT_line_width_12",title:"Line Width 12",size:12},{id:"OT_line_width_14",title:"Line Width 14",size:14}]),u.items&&p.setAttribute("data-type","group"),p.setAttribute("data-col",u.title),p.style.border="none",p.style.cursor="pointer",n.push(p.outerHTML)}r.innerHTML=n.join(""),r.onclick=function(t){var n="group"===t.target.getAttribute("data-type"),i=t.target.getAttribute("data-col"),s=t.target.getAttribute("id");n?a.items.forEach(function(t){if(t.title===i){if(a.selectedGroup=t,t.items&&(o.setAttribute("class","OT_subpanel"),o.style.backgroundColor=a.backgroundColor,o.style.width="100%",o.style.height="100%",o.style.paddingLeft="15px",o.style.display="none",a.parent.appendChild(o),Array.isArray(t.items))){var n=[];"OT_line_width"===t.id?t.items.forEach(function(t){var o=e.createElement("div");o.setAttribute("data-col",t.title),o.setAttribute("id",t.id),o.style.position="relative",o.style.top="50%",o.style.transform="translateY(-50%)",o.style["float"]="left",o.style.width=a.buttonWidth,o.style.height=a.buttonHeight,o.style.border="none",o.style.cursor="pointer";var i=e.createElement("div");i.style.backgroundColor="#FFFFFF",i.style.width="80%",i.style.height=t.size+"px",i.style.position="relative",i.style.left="50%",i.style.top="50%",i.style.transform="translateX(-50%) translateY(-50%)",i.style.pointerEvents="none",o.appendChild(i),n.push(o.outerHTML)}):t.items.forEach(function(t){var o=e.createElement("input");o.setAttribute("type","button"),o.setAttribute("data-col",t.title),o.setAttribute("id",t.id),o.style.background='url("'+t.icon+'") no-repeat',o.style.position="relative",o.style.top="50%",o.style.transform="translateY(-50%)",o.style.backgroundSize=a.iconWidth+" "+a.iconHeight,o.style.backgroundPosition="center",o.style.width=a.buttonWidth,o.style.height=a.buttonHeight,o.style.border="none",o.style.cursor="pointer",n.push(o.outerHTML)}),o.innerHTML=n.join("")}"OT_shapes"===s||"OT_line_width"===s?(o&&(o.style.display="block"),m.close()):"OT_colors"===s&&(o&&(o.style.display="none"),m.open())}}):(a.items.forEach(function(t){if("Clear"!==t.title&&t.title===i){if(a.selectedItem){var n=e.getElementById(a.selectedItem.id);n&&(n.style.background='url("'+a.selectedItem.icon+'") no-repeat',n.style.backgroundSize=a.iconWidth+" "+a.iconHeight,n.style.backgroundPosition="center")}if(t.selectedIcon){var o=e.getElementById(t.id);o&&(o.style.background='url("'+t.selectedIcon+'") no-repeat',o.style.backgroundSize=a.iconWidth+" "+a.iconHeight,o.style.backgroundPosition="center")}return a.selectedItem=t,d(t),c.forEach(function(t){t.selectItem(a.selectedItem)}),!1}}),o.style.display="none"),a.cbs.forEach(function(t){t.call(a,s)})},o.onclick=function(t){var e="group"===t.target.getAttribute("data-type"),n=(t.target.getAttribute("data-col"),t.target.getAttribute("id"));o.style.display="none",e||a.selectedGroup.items.forEach(function(t){if("OT_clear"!==t.id&&t.id===n){if(a.selectedItem){var e=document.getElementById(a.selectedItem.id);e&&(e.style.background='url("'+a.selectedItem.icon+'") no-repeat',e.style.backgroundSize=a.iconWidth+" "+a.iconHeight,e.style.backgroundPosition="center")}if(t.selectedIcon){var o=document.getElementById(t.id);e&&(o.style.background='url("'+t.selectedIcon+'") no-repeat',o.style.backgroundSize=a.iconWidth+" "+a.iconHeight,o.style.backgroundPosition="center")}return a.selectedItem=t,d(t),c.forEach(function(t){t.selectItem(a.selectedItem)}),!1}}),a.cbs.forEach(function(t){t.call(a,n)})},e.getElementById("OT_clear").onclick=function(){c.forEach(function(t){t.clear()})}}},!this.externalWindow&&this.createPanel();var d=function(t){t.points||("OT_line"===t.id?a.selectedItem.points=[[0,0],[0,1]]:"OT_arrow"===t.id?a.selectedItem.points=[[0,1],[3,1],[3,0],[5,2],[3,4],[3,3],[0,3],[0,1]]:"OT_rect"===t.id?a.selectedItem.points=[[0,0],[1,0],[1,1],[0,1],[0,0]]:"OT_oval"===t.id&&(a.selectedItem.enableSmoothing=!0,a.selectedItem.points=[[0,.5],[.5+.5*Math.cos(5*Math.PI/4),.5+.5*Math.sin(5*Math.PI/4)],[.5,0],[.5+.5*Math.cos(7*Math.PI/4),.5+.5*Math.sin(7*Math.PI/4)],[1,.5],[.5+.5*Math.cos(Math.PI/4),.5+.5*Math.sin(Math.PI/4)],[.5,1],[.5+.5*Math.cos(3*Math.PI/4),.5+.5*Math.sin(3*Math.PI/4)],[0,.5],[.5+.5*Math.cos(5*Math.PI/4),.5+.5*Math.sin(5*Math.PI/4)]]))};this.itemClicked=function(t){this.cbs.push(t)},this.addCanvas=function(t){var e=this;t.link(e.session),t.colors(e.colors),c.push(t)},this.removeCanvas=function(t){c.forEach(function(e){var n=e.canvas();e.videoFeed.stream.connection.connectionId===t&&n.parentNode&&n.parentNode.removeChild(n)}),c=c.filter(function(e){return e.videoFeed.stream.connection.connectionId!==t})},this.remove=function(){try{r.parentNode.removeChild(r)}catch(t){console.log(t)}c.forEach(function(t){var e=t.canvas();e.parentNode&&e.parentNode.removeChild(e)}),c=[]}}}).call(this),function(){var t,e,n;"object"==typeof module&&"object"==typeof module.exports?(t=require("underscore"),e=require("jquery"),n=require("opentok-solutions-logging")):(t=this._,e=this.$,n=this.OTKAnalytics);var o,i,a,s,r,c={},l={clientVersion:"js-vsol-1.0.0",componentId:"annotationsAccPack",name:"guidAnnotationsKit",actionInitialize:"Init",actionStart:"Start",actionEnd:"End",actionFreeHand:"Free Hand",actionPickerColor:"Picker Color",actionText:"Text",actionScreenCapture:"Screen Capture",actionErase:"Erase",actionUseToolbar:"Use Toolbar",variationAttempt:"Attempt",variationError:"Failure",variationSuccess:"Success"},d=function(){var t=window.location.href,e={clientVersion:l.clientVersion,source:t,componentId:l.componentId,name:l.name};r=new n(e);var o={sessionId:a.id,connectionId:a.connection.connectionId,partnerId:a.apiKey};r.addSessionInfo(o)},h=function(t,e){var n={action:t,variation:e};r.logEvent(n)},u=function(t,e){i&&i.triggerEvent(t,e)},p=function(){var t=["startAnnotation","linkAnnotation","resizeCanvas","annotationWindowClosed","endAnnotation"];i.registerEvents(t)},g=function(){var t=['<div id="annotationToolbarContainer" class="annotation-toolbar-container">','<div id="toolbar"></div>',"</div>"].join("\n");e("body").append(t),h(l.actionUseToolbar,l.variationSuccess)},m=[{id:"OT_pen",title:"Pen",icon:"../images/annotation/freehand.png",selectedIcon:"../images/annotation/freehand_selected.png"},{id:"OT_line",title:"Line",icon:"../images/annotation/line.png",selectedIcon:"../images/annotation/line_selected.png"},{id:"OT_text",title:"Text",icon:"../images/annotation/text.png",selectedIcon:"../images/annotation/text.png"},{id:"OT_shapes",title:"Shapes",icon:"../images/annotation/shapes.png",items:[{id:"OT_arrow",title:"Arrow",icon:"../images/annotation/arrow.png"},{id:"OT_rect",title:"Rectangle",icon:"../images/annotation/rectangle.png"},{id:"OT_oval",title:"Oval",icon:"../images/annotation/oval.png"},{id:"OT_star",title:"Star",icon:"../images/annotation/star.png",points:[[.5+.5*Math.cos(90*(Math.PI/180)),.5+.5*Math.sin(90*(Math.PI/180))],[.5+.25*Math.cos(126*(Math.PI/180)),.5+.25*Math.sin(126*(Math.PI/180))],[.5+.5*Math.cos(162*(Math.PI/180)),.5+.5*Math.sin(162*(Math.PI/180))],[.5+.25*Math.cos(198*(Math.PI/180)),.5+.25*Math.sin(198*(Math.PI/180))],[.5+.5*Math.cos(234*(Math.PI/180)),.5+.5*Math.sin(234*(Math.PI/180))],[.5+.25*Math.cos(270*(Math.PI/180)),.5+.25*Math.sin(270*(Math.PI/180))],[.5+.5*Math.cos(306*(Math.PI/180)),.5+.5*Math.sin(306*(Math.PI/180))],[.5+.25*Math.cos(342*(Math.PI/180)),.5+.25*Math.sin(342*(Math.PI/180))],[.5+.5*Math.cos(18*(Math.PI/180)),.5+.5*Math.sin(18*(Math.PI/180))],[.5+.25*Math.cos(54*(Math.PI/180)),.5+.25*Math.sin(54*(Math.PI/180))],[.5+.5*Math.cos(90*(Math.PI/180)),.5+.5*Math.sin(90*(Math.PI/180))]]}]},{id:"OT_colors",title:"Colors",icon:"",items:{}},{id:"OT_line_width",title:"Line Width",icon:"../images/annotation/line_width.png",items:{}},{id:"OT_clear",title:"Clear",icon:"../images/annotation/clear.png"}],f=["#1abc9c","#2ecc71","#3498db","#9b59b6","#8e44ad","#f1c40f","#e67e22","#e74c3c","#ded5d5"],v=10/6,y=t.throttle(function(){s.onResize()},1e3),b=function(){var t,n;if(c.externalWindow){var o={width:c.externalWindow.innerWidth,height:c.externalWindow.innerHeight},i=o.width/v;i<=o.height?(t=o.width,n=i):(n=o.height,t=n*v)}else{var a=c.absoluteParent||c.canvasContainer;t=e(a).width(),n=e(a).height()}e(c.canvasContainer).css({width:t,height:n}),e(c.canvasContainer).find("canvas").css({width:t,height:n}),e(c.canvasContainer).find("canvas").attr({width:t,height:n}),y(),u("resizeCanvas")},w=function(){e(c.resizeSubject).on("resize",t.throttle(function(){b()},500))},I=function(e,o,i){var a=t.property("toolbarId")(o)||"toolbar",s=t.property("toolbarItems")(o)||m,r=t.property("colors")(o)||f,c=function(){var t=i?i:window;return t.document.getElementById(a)};toolbar=new OTSolution.Annotations.Toolbar({session:e,container:c(),colors:r,items:s,externalWindow:i||null,OTKAnalytics:n}),toolbar.itemClicked(function(t){var e={OT_pen:l.actionFreeHand,OT_colors:l.actionPickerColor,OT_text:l.actionText,OT_clear:l.actionErase},n=e[t];n&&h(n,l.variationSuccess)})},T=function(){var t=e.Deferred(),n=.8*screen.width|0,o=n/v,i='<!DOCTYPE html><html lang="en"><head><meta http-equiv="Content-type" content="text/html; charset=utf-8"><title>OpenTok Screen Sharing Solution Annotation</title><script type="text/javascript" charset="utf-8">var opener,canvas;toolbar?(opener=window.opener,window.onbeforeunload=window.triggerCloseEvent):alert("Something went wrong: You must pass an OpenTok annotation toolbar object into the window.");var createContainerElements=function(){var e=document.getElementById("annotationContainer"),n=document.createElement("div");return n.setAttribute("id","screenshare_publisher"),n.classList.add("publisher-wrap"),e.appendChild(n),{annotation:e,publisher:n}};if(-1!==navigator.userAgent.indexOf("Firefox")){var ghost=window.open("about:blank");ghost.focus(),ghost.close()}</script><style type="text/css" media="screen"> body{margin:0;background-color:rgba(0,153,203,.7);box-sizing:border-box;height:100vh}canvas{top:0;z-index:1000}.main-wrap{width:100%;height:100%;-ms-box-orient:horizontal;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-moz-flex;display:-webkit-flex;display:flex;-webkit-justify-content:center;justify-content:center;-webkit-align-items:center;align-items:center}.inner-wrap{position:relative;border-radius:8px;overflow:hidden}.fixed-container{position:fixed;top:275px;right:0;width:40px;z-index:1001}.fixed-container .toolbar-wrap{position:absolute;top:0;left:0}.fixed-container .toolbar-wrap input{display:block;top:0!important;transform:none!important}.fixed-container .toolbar-wrap .OT_color{width:30px;margin-right:5px!important;margin-left:5px!important;padding:0}.fixed-container .toolbar-wrap .OT_subpanel,.fixed-container .toolbar-wrap .color-picker{position:absolute;top:0;right:40px;padding-left:0!important;overflow:hidden}.fixed-container .toolbar-wrap .OT_subpanel>div{top:0!important;transform:none!important}.fixed-container .toolbar-wrap .color-picker{left:-30px}.fixed-container .toolbar-wrap .color-picker .color-choice{display:block!important;height:20px!important;width:20px!important}.publisherContainer{display:block;background-color:#000;position:absolute}.OT_video-element,.publisher-wrap{height:100%;width:100%}.OT_edge-bar-item{display:none}</style></head><body> <div class="main-wrap"> <div id="annotationContainer" class="inner-wrap"></div> </div> <div id="toolbarContainer" class="fixed-container"> <div id="toolbar" class="toolbar-wrap"></div> </div></body></html>',a=["toolbar=no","location=no","directories=no","status=no","menubar=no","scrollbars=no","resizable=no","copyhistory=no",["width=",n].join(""),["height=",o].join(""),["left=",screen.width/2-n/2].join(""),["top=",screen.height/2-o/2].join("")].join(","),s=window.open("about:blank","",a);s.document.write(i),window.onbeforeunload=function(){s.close()},s.toolbar=toolbar,s.OT=OT,s.$=e,s.triggerCloseEvent=function(){u("annotationWindowClosed")};var r=function(){s.createContainerElements?e(s.document).ready(function(){t.resolve(s)}):setTimeout(r,100)};return r(),t.promise()},x=function(){e(c.resizeSubject).off("resize",b),toolbar.remove(),c.externalWindow||e("#annotationToolbarContainer").remove()},_=function(n,o){var i=e.Deferred();return t.property("screensharing")(o)?T().then(function(t){I(n,o,t),toolbar.createPanel(t),u("startAnnotation",t),h(l.actionStart,l.variationSuccess),i.resolve(t)}):(I(n,o),u("startAnnotation"),h(l.actionStart,l.variationSuccess),i.resolve()),i.promise()},W=function(n,o,i){c.resizeSubject=t.property("externalWindow")(i)||window,c.externalWindow=t.property("externalWindow")(i)||null,c.absoluteParent=t.property("absoluteParent")(i)||null,c.canvasContainer=o,s=new OTSolution.Annotations({feed:n,container:o,externalWindow:c.externalWindow}),toolbar.addCanvas(s),s.onScreenCapture(function(t){var e=window.open(t,"_blank");e.focus()});var a=c.externalWindow?c.externalWindow:window;c.canvas=e(t.first(a.document.getElementsByTagName("canvas"))),w(),b(),u("linkAnnotation")},k=function(){b()},O=function(t){x(),c.canvas=null,t&&(c.externalWindow&&(c.externalWindow.close(),c.externalWindow=null,c.resizeSubject=null),u("endAnnotation")),h(l.actionEnd,l.variationSuccess)},P=function(e){if(o=this,o.options=t.omit(e,"accPack","session"),i=t.property("accPack")(e),a=t.property("session")(e),!a)throw new Error("OpenTok Annotation Accelerator Pack requires an OpenTok session");p(),d(),h(l.actionInitialize,l.variationSuccess),g()};P.prototype={constructor:P,start:_,linkCanvas:W,resizeCanvas:k,end:O},"object"==typeof exports?module.exports=P:"function"==typeof define&&define.amd?define(function(){return P}):this.AnnotationAccPack=P}.call(this);
{
"name": "opentok-annotation",
"version": "1.0.29",
"version": "1.0.30",
"description": "OpenTok annotation accelerator pack",

@@ -5,0 +5,0 @@ "main": "dist/opentok-annotation.js",

@@ -265,3 +265,4 @@ /* global OT OTSolution OTKAnalytics ScreenSharingAccPack define */

items: items,
externalWindow: externalWindow || null
externalWindow: externalWindow || null,
OTKAnalytics: OTKAnalytics
});

@@ -268,0 +269,0 @@

@@ -11,339 +11,381 @@ /*!

/** Analytics */
var _otkanalytics;
var _session;
(function () {
// vars for the analytics logs. Internal use
var _logEventData = {
clientVersion: 'js-vsol-1.0.0',
componentId: 'annotationsAccPack',
name: 'guidAnnotationsKit',
actionStartDrawing: 'Start Drawing',
actionEndDrawing: 'End Drawing',
variationSuccess: 'Success',
};
var _OTKAnalytics;
var _otkanalytics;
var _session;
var _logAnalytics = function () {
// init the analytics logs
var _source = window.location.href;
var otkanalyticsData = {
clientVersion: _logEventData.clientVersion,
source: _source,
componentId: _logEventData.componentId,
name: _logEventData.name
// vars for the analytics logs. Internal use
var _logEventData = {
clientVersion: 'js-vsol-1.0.0',
componentId: 'annotationsAccPack',
name: 'guidAnnotationsKit',
actionStartDrawing: 'Start Drawing',
actionEndDrawing: 'End Drawing',
variationSuccess: 'Success',
};
_otkanalytics = new OTKAnalytics(otkanalyticsData);
var _logAnalytics = function () {
// init the analytics logs
var _source = window.location.href;
var sessionInfo = {
sessionId: _session.id,
connectionId: _session.connection.connectionId,
partnerId: _session.apiKey
};
var otkanalyticsData = {
clientVersion: _logEventData.clientVersion,
source: _source,
componentId: _logEventData.componentId,
name: _logEventData.name
};
_otkanalytics.addSessionInfo(sessionInfo);
};
_otkanalytics = new _OTKAnalytics(otkanalyticsData);
var _log = function (action, variation) {
var data = {
action: action,
variation: variation
var sessionInfo = {
sessionId: _session.id,
connectionId: _session.connection.connectionId,
partnerId: _session.apiKey
};
_otkanalytics.addSessionInfo(sessionInfo);
};
_otkanalytics.logEvent(data);
};
/** End Analytics */
var _log = function (action, variation) {
var data = {
action: action,
variation: variation
};
_otkanalytics.logEvent(data);
};
/** End Analytics */
//--------------------------------------
// OPENTOK ANNOTATION CANVAS/VIEW
//--------------------------------------
window.OTSolution = window.OTSolution || {};
OTSolution.Annotations = function (options) {
//--------------------------------------
// OPENTOK ANNOTATION CANVAS/VIEW
//--------------------------------------
options = options || {};
this.widgetVersion = 'js-1.0.0-beta';
this.parent = options.container;
this.videoFeed = options.feed;
var context = options.externalWindow ? options.externalWindow.document : window.document;
var self = this;
OTSolution = this.OTSolution || {};
console.log('ello');
if (this.parent) {
var canvas = document.createElement('canvas');
canvas.setAttribute('id', 'opentok_canvas'); // session.connection.id?
canvas.style.position = 'absolute';
this.parent.appendChild(canvas);
canvas.setAttribute('width', this.parent.clientWidth + 'px');
canvas.style.width = window.getComputedStyle(this.parent).width;
canvas.setAttribute('height', this.parent.clientHeight + 'px');
canvas.style.height = window.getComputedStyle(this.parent).height;
}
OTSolution.Annotations = function (options) {
var self = this,
ctx,
cbs = [],
isPublisher,
mirrored,
scaledToFill,
batchUpdates = [],
drawHistory = [],
drawHistoryReceivedFrom,
updateHistory = [],
eventHistory = [],
isStartPoint = false,
client = {
dragging: false
};
options = options || {};
this.widgetVersion = 'js-1.0.0-beta';
this.parent = options.container;
this.videoFeed = options.feed;
_OTKAnalytics = _OTKAnalytics || options.OTKAnalytics;
if (!_otkanalytics) {
_logAnalytics()
}
// INFO Mirrored feeds contain the OT_mirrored class
isPublisher = (' ' + self.videoFeed.element.className + ' ').indexOf(' ' + 'OT_publisher' + ' ') > -1;
mirrored = isPublisher ? (' ' + self.videoFeed.element.className + ' ').indexOf(' ' + 'OT_mirrored' + ' ') > -1 : false;
scaledToFill = (' ' + self.videoFeed.element.className + ' ').indexOf(' ' + 'OT_fit-mode-cover' + ' ') > -1;
var context = options.externalWindow ? options.externalWindow.document : window.document;
this.canvas = function () {
return canvas;
};
var self = this;
/**
* Links an OpenTok session to the annotation canvas. Typically, this is automatically linked
* when using {@link Toolbar#addCanvas}.
* @param session The OpenTok session.
*/
this.link = function (session) {
this.session = session;
};
/**
* Changes the active annotation color for the canvas.
* @param color The hex string representation of the color (#rrggbb).
*/
this.changeColor = function (color) {
self.userColor = color;
if (!self.lineWidth) {
self.lineWidth = 2; // TODO Default to first option in list of line widths
if (this.parent) {
var canvas = document.createElement('canvas');
canvas.setAttribute('id', 'opentok_canvas'); // session.connection.id?
canvas.style.position = 'absolute';
this.parent.appendChild(canvas);
canvas.setAttribute('width', this.parent.clientWidth + 'px');
canvas.style.width = window.getComputedStyle(this.parent).width;
canvas.setAttribute('height', this.parent.clientHeight + 'px');
canvas.style.height = window.getComputedStyle(this.parent).height;
}
};
/**
* Changes the line/stroke width of the active annotation for the canvas.
* @param size The size in pixels.
*/
this.changeLineWidth = function (size) {
this.lineWidth = size;
};
var self = this,
ctx,
cbs = [],
isPublisher,
mirrored,
scaledToFill,
batchUpdates = [],
drawHistory = [],
drawHistoryReceivedFrom,
updateHistory = [],
eventHistory = [],
isStartPoint = false,
client = {
dragging: false
};
/**
* Sets the selected menu item from the toolbar. This is typically handled
* automatically by the toolbar, but can be used to programmatically select an item.
* @param item The menu item to set as selected.
*/
this.selectItem = function (item) {
if (self.overlay) {
self.overlay.style.display = 'none';
self.overlay = null;
}
if (item.id === 'OT_capture') {
self.selectedItem = item;
if (!self.overlay) {
self.overlay = document.createElement('div');
self.overlay.style.position = 'absolute';
self.overlay.style.width = self.parent.clientWidth + 'px';
self.overlay.style.height = self.parent.clientHeight + 'px';
self.overlay.style.background = 'rgba(0,0,0,0.4) url("../images/annotation/camera.png") no-repeat center';
self.overlay.style.backgroundSize = '50px 50px';
self.overlay.style.cursor = 'pointer';
self.overlay.style.opacity = 0;
// INFO Mirrored feeds contain the OT_mirrored class
isPublisher = (' ' + self.videoFeed.element.className + ' ').indexOf(' ' + 'OT_publisher' + ' ') > -1;
mirrored = isPublisher ? (' ' + self.videoFeed.element.className + ' ').indexOf(' ' + 'OT_mirrored' + ' ') > -1 : false;
scaledToFill = (' ' + self.videoFeed.element.className + ' ').indexOf(' ' + 'OT_fit-mode-cover' + ' ') > -1;
self.parent.appendChild(self.overlay);
this.canvas = function () {
return canvas;
};
self.parent.onmouseover = function () {
self.overlay.style.opacity = 1;
};
/**
* Links an OpenTok session to the annotation canvas. Typically, this is automatically linked
* when using {@link Toolbar#addCanvas}.
* @param session The OpenTok session.
*/
this.link = function (session) {
this.session = session;
};
self.parent.onmouseout = function () {
/**
* Changes the active annotation color for the canvas.
* @param color The hex string representation of the color (#rrggbb).
*/
this.changeColor = function (color) {
self.userColor = color;
if (!self.lineWidth) {
self.lineWidth = 2; // TODO Default to first option in list of line widths
}
};
/**
* Changes the line/stroke width of the active annotation for the canvas.
* @param size The size in pixels.
*/
this.changeLineWidth = function (size) {
this.lineWidth = size;
};
/**
* Sets the selected menu item from the toolbar. This is typically handled
* automatically by the toolbar, but can be used to programmatically select an item.
* @param item The menu item to set as selected.
*/
this.selectItem = function (item) {
if (self.overlay) {
self.overlay.style.display = 'none';
self.overlay = null;
}
if (item.id === 'OT_capture') {
self.selectedItem = item;
if (!self.overlay) {
self.overlay = document.createElement('div');
self.overlay.style.position = 'absolute';
self.overlay.style.width = self.parent.clientWidth + 'px';
self.overlay.style.height = self.parent.clientHeight + 'px';
self.overlay.style.background = 'rgba(0,0,0,0.4) url("../images/annotation/camera.png") no-repeat center';
self.overlay.style.backgroundSize = '50px 50px';
self.overlay.style.cursor = 'pointer';
self.overlay.style.opacity = 0;
};
self.overlay.onclick = function () {
self.captureScreenshot();
};
self.parent.appendChild(self.overlay);
self.parent.onmouseover = function () {
self.overlay.style.opacity = 1;
};
self.parent.onmouseout = function () {
self.overlay.style.opacity = 0;
};
self.overlay.onclick = function () {
self.captureScreenshot();
};
} else {
self.overlay.style = 'inline';
}
} else if (item.id.indexOf('OT_line_width') !== -1) {
if (item.size) {
self.changeLineWidth(item.size);
}
} else {
self.overlay.style = 'inline';
self.selectedItem = item;
}
} else if (item.id.indexOf('OT_line_width') !== -1) {
if (item.size) {
self.changeLineWidth(item.size);
}
} else {
self.selectedItem = item;
}
};
};
/**
* Sets the color palette for the color picker
* @param colors The array of hex color strings (#rrggbb).
*/
this.colors = function (colors) {
this.colors = colors;
this.changeColor(colors[0]);
};
/**
* Sets the color palette for the color picker
* @param colors The array of hex color strings (#rrggbb).
*/
this.colors = function (colors) {
this.colors = colors;
this.changeColor(colors[0]);
};
/**
* Clears the canvas for the active user. Only annotations added by the active OpenTok user will
* be removed, leaving the history of all other annotations.
*/
this.clear = function () {
clearCanvas(false, self.session.connection.connectionId);
if (self.session) {
self.session.signal({
type: 'otAnnotation_clear'
});
}
};
/**
* Clears the canvas for the active user. Only annotations added by the active OpenTok user will
* be removed, leaving the history of all other annotations.
*/
this.clear = function () {
clearCanvas(false, self.session.connection.connectionId);
if (self.session) {
self.session.signal({
type: 'otAnnotation_clear'
});
}
};
// TODO Allow the user to choose the image type? (jpg, png) Also allow size?
/**
* Captures a screenshot of the annotations displayed on top of the active video feed.
*/
this.captureScreenshot = function () {
// TODO Allow the user to choose the image type? (jpg, png) Also allow size?
/**
* Captures a screenshot of the annotations displayed on top of the active video feed.
*/
this.captureScreenshot = function () {
var canvasCopy = document.createElement('canvas');
canvasCopy.width = canvas.width;
canvasCopy.height = canvas.height;
var canvasCopy = document.createElement('canvas');
canvasCopy.width = canvas.width;
canvasCopy.height = canvas.height;
var width = self.videoFeed.videoWidth();
var height = self.videoFeed.videoHeight();
var width = self.videoFeed.videoWidth();
var height = self.videoFeed.videoHeight();
var scale = 1;
var scale = 1;
var offsetX = 0;
var offsetY = 0;
var offsetX = 0;
var offsetY = 0;
if (scaledToFill) {
if (width < height) {
scale = canvas.width / width;
width = canvas.width;
height = height * scale;
} else {
scale = canvas.height / height;
height = canvas.height;
width = width * scale;
}
if (scaledToFill) {
if (width < height) {
scale = canvas.width / width;
width = canvas.width;
height = height * scale;
} else {
scale = canvas.height / height;
height = canvas.height;
width = width * scale;
}
// If stretched to fill, we need an offset to center the image
offsetX = (width - canvas.width) / 2;
offsetY = (height - canvas.height) / 2;
} else {
if (width > height) {
scale = canvas.width / width;
width = canvas.width;
height = height * scale;
// If stretched to fill, we need an offset to center the image
offsetX = (width - canvas.width) / 2;
offsetY = (height - canvas.height) / 2;
} else {
scale = canvas.height / height;
height = canvas.height;
width = width * scale;
if (width > height) {
scale = canvas.width / width;
width = canvas.width;
height = height * scale;
} else {
scale = canvas.height / height;
height = canvas.height;
width = width * scale;
}
}
}
// Combine the video and annotation images
var image = new Image();
image.onload = function () {
var ctxCopy = canvasCopy.getContext('2d');
if (mirrored) {
ctxCopy.translate(width, 0);
ctxCopy.scale(-1, 1);
}
ctxCopy.drawImage(image, offsetX, offsetY, width, height);
// Combine the video and annotation images
var image = new Image();
image.onload = function () {
var ctxCopy = canvasCopy.getContext('2d');
if (mirrored) {
ctxCopy.translate(width, 0);
ctxCopy.scale(-1, 1);
}
ctxCopy.drawImage(image, offsetX, offsetY, width, height);
// We want to make sure we draw the annotations the same way, so we need to flip back
if (mirrored) {
ctxCopy.translate(width, 0);
ctxCopy.scale(-1, 1);
}
ctxCopy.drawImage(canvas, 0, 0);
// We want to make sure we draw the annotations the same way, so we need to flip back
if (mirrored) {
ctxCopy.translate(width, 0);
ctxCopy.scale(-1, 1);
}
ctxCopy.drawImage(canvas, 0, 0);
cbs.forEach(function (cb) {
cb.call(self, canvasCopy.toDataURL());
});
cbs.forEach(function (cb) {
cb.call(self, canvasCopy.toDataURL());
});
// Clear and destroy the canvas copy
canvasCopy = null;
// Clear and destroy the canvas copy
canvasCopy = null;
};
image.src = 'data:image/png;base64,' + self.videoFeed.getImgData();
};
image.src = 'data:image/png;base64,' + self.videoFeed.getImgData();
};
this.onScreenCapture = function (cb) {
cbs.push(cb);
};
this.onScreenCapture = function (cb) {
cbs.push(cb);
};
this.onResize = function () {
drawHistory = [];
this.onResize = function () {
drawHistory = [];
drawUpdates(updateHistory, true);
drawUpdates(updateHistory, true);
eventHistory.forEach(function (history) {
updateCanvas(history, true);
});
};
eventHistory.forEach(function (history) {
updateCanvas(history, true);
});
};
/** Canvas Handling **/
/** Canvas Handling **/
function addEventListeners(el, s, fn) {
var evts = s.split(' ');
for (var i = 0, iLen = evts.length; i < iLen; i++) {
el.addEventListener(evts[i], fn, true);
function addEventListeners(el, s, fn) {
var evts = s.split(' ');
for (var i = 0, iLen = evts.length; i < iLen; i++) {
el.addEventListener(evts[i], fn, true);
}
}
}
function updateCanvas(event, resizeEvent) {
function updateCanvas(event, resizeEvent) {
// Ensure that our canvas has been properly sized
if (canvas.width === 0) {
canvas.width = self.parent.getBoundingClientRect().width;
}
// Ensure that our canvas has been properly sized
if (canvas.width === 0) {
canvas.width = self.parent.getBoundingClientRect().width;
}
if (canvas.height === 0) {
canvas.height = self.parent.getBoundingClientRect().height;
}
if (canvas.height === 0) {
canvas.height = self.parent.getBoundingClientRect().height;
}
var baseWidth = !!resizeEvent ? event.canvas.width : self.parent.clientWidth;
var baseHeight = !!resizeEvent ? event.canvas.height : self.parent.clientHeight;
var offsetLeft = !!resizeEvent ? event.canvas.offsetLeft : canvas.offsetLeft;
var offsetTop = !!resizeEvent ? event.canvas.offsetTop : canvas.offsetTop;
var baseWidth = !!resizeEvent ? event.canvas.width : self.parent.clientWidth;
var baseHeight = !!resizeEvent ? event.canvas.height : self.parent.clientHeight;
var offsetLeft = !!resizeEvent ? event.canvas.offsetLeft : canvas.offsetLeft;
var offsetTop = !!resizeEvent ? event.canvas.offsetTop : canvas.offsetTop;
var scaleX = canvas.width / baseWidth;
var scaleY = canvas.height / baseHeight;
var scaleX = canvas.width / baseWidth;
var scaleY = canvas.height / baseHeight;
var offsetX = event.offsetX || event.pageX - offsetLeft ||
(event.changedTouches && event.changedTouches[0].pageX - offsetLeft);
var offsetY = event.offsetY || event.pageY - offsetTop ||
(event.changedTouches && event.changedTouches[0].pageY - offsetTop);
var x = offsetX * scaleX;
var y = offsetY * scaleY;
var offsetX = event.offsetX || event.pageX - offsetLeft ||
(event.changedTouches && event.changedTouches[0].pageX - offsetLeft);
var offsetY = event.offsetY || event.pageY - offsetTop ||
(event.changedTouches && event.changedTouches[0].pageY - offsetTop);
var x = offsetX * scaleX;
var y = offsetY * scaleY;
var update;
var selectedItem = resizeEvent ? event.selectedItem : self.selectedItem;
var update;
var selectedItem = resizeEvent ? event.selectedItem : self.selectedItem;
if (selectedItem) {
if (selectedItem.id === 'OT_pen') {
if (selectedItem) {
if (selectedItem.id === 'OT_pen') {
switch (event.type) {
case 'mousedown':
case 'touchstart':
client.dragging = true;
client.lastX = x;
client.lastY = y;
self.isStartPoint = true;
!resizeEvent && _log(_logEventData.actionStartDrawing, _logEventData.variationSuccess);
break;
case 'mousemove':
case 'touchmove':
if (client.dragging) {
switch (event.type) {
case 'mousedown':
case 'touchstart':
client.dragging = true;
client.lastX = x;
client.lastY = y;
self.isStartPoint = true;
!resizeEvent && _log(_logEventData.actionStartDrawing, _logEventData.variationSuccess);
break;
case 'mousemove':
case 'touchmove':
if (client.dragging) {
update = {
id: self.videoFeed.stream.connection.connectionId,
fromId: self.session.connection.connectionId,
fromX: client.lastX,
fromY: client.lastY,
toX: x,
toY: y,
color: resizeEvent ? event.userColor : self.userColor,
lineWidth: self.lineWidth,
videoWidth: self.videoFeed.videoElement().clientWidth,
videoHeight: self.videoFeed.videoElement().clientHeight,
canvasWidth: canvas.width,
canvasHeight: canvas.height,
mirrored: mirrored,
startPoint: self.isStartPoint, // Each segment is treated as a new set of points
endPoint: false,
selectedItem: selectedItem
};
draw(update, true);
client.lastX = x;
client.lastY = y;
!resizeEvent && sendUpdate(update);
self.isStartPoint = false;
}
break;
case 'mouseup':
case 'touchend':
client.dragging = false;
update = {

@@ -364,3 +406,3 @@ id: self.videoFeed.stream.connection.connectionId,

startPoint: self.isStartPoint, // Each segment is treated as a new set of points
endPoint: false,
endPoint: true,
selectedItem: selectedItem

@@ -373,138 +415,68 @@ };

self.isStartPoint = false;
}
break;
case 'mouseup':
case 'touchend':
client.dragging = false;
update = {
id: self.videoFeed.stream.connection.connectionId,
fromId: self.session.connection.connectionId,
fromX: client.lastX,
fromY: client.lastY,
toX: x,
toY: y,
color: resizeEvent ? event.userColor : self.userColor,
lineWidth: self.lineWidth,
videoWidth: self.videoFeed.videoElement().clientWidth,
videoHeight: self.videoFeed.videoElement().clientHeight,
canvasWidth: canvas.width,
canvasHeight: canvas.height,
mirrored: mirrored,
startPoint: self.isStartPoint, // Each segment is treated as a new set of points
endPoint: true,
selectedItem: selectedItem
};
draw(update, true);
client.lastX = x;
client.lastY = y;
!resizeEvent && sendUpdate(update);
self.isStartPoint = false;
!resizeEvent && _log(_logEventData.actionEndDrawing, _logEventData.variationSuccess);
break;
case 'mouseout':
client.dragging = false;
}
} else if (selectedItem.id === 'OT_text') {
update = {
id: self.videoFeed.stream.connection.connectionId,
fromId: self.session.connection.connectionId,
fromX: x,
fromY: y + event.inputHeight, // Account for the height of the text input
color: event.userColor,
font: event.font,
text: event.text,
videoWidth: self.videoFeed.videoElement().clientWidth,
videoHeight: self.videoFeed.videoElement().clientHeight,
canvasWidth: canvas.width,
canvasHeight: canvas.height,
mirrored: mirrored,
selectedItem: selectedItem
};
draw(update);
!resizeEvent && sendUpdate(update);
} else {
// We have a shape or custom object
if (selectedItem && selectedItem.points) {
client.mX = x;
client.mY = y;
switch (event.type) {
case 'mousedown':
case 'touchstart':
client.isDrawing = true;
client.dragging = true;
client.startX = x;
client.startY = y;
!resizeEvent && _log(_logEventData.actionEndDrawing, _logEventData.variationSuccess);
break;
case 'mousemove':
case 'touchmove':
if (client.dragging) {
update = {
color: resizeEvent ? event.userColor : self.userColor,
lineWidth: resizeEvent ? event.lineWidth : self.lineWidth,
selectedItem: selectedItem
// INFO The points for scaling will get added when drawing is complete
};
case 'mouseout':
client.dragging = false;
}
} else if (selectedItem.id === 'OT_text') {
draw(update, true);
}
break;
case 'mouseup':
case 'touchend':
client.isDrawing = false;
update = {
id: self.videoFeed.stream.connection.connectionId,
fromId: self.session.connection.connectionId,
fromX: x,
fromY: y + event.inputHeight, // Account for the height of the text input
color: event.userColor,
font: event.font,
text: event.text,
videoWidth: self.videoFeed.videoElement().clientWidth,
videoHeight: self.videoFeed.videoElement().clientHeight,
canvasWidth: canvas.width,
canvasHeight: canvas.height,
mirrored: mirrored,
selectedItem: selectedItem
};
var points = selectedItem.points;
draw(update);
!resizeEvent && sendUpdate(update);
} else {
// We have a shape or custom object
if (selectedItem && selectedItem.points) {
client.mX = x;
client.mY = y;
if (points.length === 2) {
update = {
id: self.videoFeed.stream.connection.connectionId,
fromId: self.session.connection.connectionId,
fromX: client.startX,
fromY: client.startY,
toX: client.mX,
toY: client.mY,
color: resizeEvent ? event.userColor : self.userColor,
lineWidth: resizeEvent ? event.lineWidth : self.lineWidth,
videoWidth: self.videoFeed.videoElement().clientWidth,
videoHeight: self.videoFeed.videoElement().clientHeight,
canvasWidth: canvas.width,
canvasHeight: canvas.height,
mirrored: mirrored,
smoothed: false,
startPoint: true,
endPoint: true,
selectedItem: selectedItem
};
switch (event.type) {
case 'mousedown':
case 'touchstart':
client.isDrawing = true;
client.dragging = true;
client.startX = x;
client.startY = y;
break;
case 'mousemove':
case 'touchmove':
if (client.dragging) {
update = {
color: resizeEvent ? event.userColor : self.userColor,
lineWidth: resizeEvent ? event.lineWidth : self.lineWidth,
selectedItem: selectedItem
// INFO The points for scaling will get added when drawing is complete
};
drawHistory.push(update);
draw(update, true);
}
break;
case 'mouseup':
case 'touchend':
client.isDrawing = false;
!resizeEvent && sendUpdate(update);
} else {
var scale = scaleForPoints(points);
var points = selectedItem.points;
for (var i = 0; i < points.length; i++) {
var firstPoint = false;
var endPoint = false;
// Scale the points according to the difference between the start and end points
var pointX = client.startX + (scale.x * points[i][0]);
var pointY = client.startY + (scale.y * points[i][1]);
if (i === 0) {
client.lastX = pointX;
client.lastY = pointY;
firstPoint = true;
} else if (i === points.length - 1) {
endPoint = true;
}
if (points.length === 2) {
update = {
id: self.videoFeed.stream.connection.connectionId,
fromId: self.session.connection.connectionId,
fromX: client.lastX,
fromY: client.lastY,
toX: pointX,
toY: pointY,
fromX: client.startX,
fromY: client.startY,
toX: client.mX,
toY: client.mY,
color: resizeEvent ? event.userColor : self.userColor,

@@ -517,5 +489,6 @@ lineWidth: resizeEvent ? event.lineWidth : self.lineWidth,

mirrored: mirrored,
smoothed: selectedItem.enableSmoothing,
startPoint: firstPoint,
endPoint: endPoint
smoothed: false,
startPoint: true,
endPoint: true,
selectedItem: selectedItem
};

@@ -526,11 +499,53 @@

!resizeEvent && sendUpdate(update);
} else {
var scale = scaleForPoints(points);
client.lastX = pointX;
client.lastY = pointY;
for (var i = 0; i < points.length; i++) {
var firstPoint = false;
var endPoint = false;
// Scale the points according to the difference between the start and end points
var pointX = client.startX + (scale.x * points[i][0]);
var pointY = client.startY + (scale.y * points[i][1]);
if (i === 0) {
client.lastX = pointX;
client.lastY = pointY;
firstPoint = true;
} else if (i === points.length - 1) {
endPoint = true;
}
update = {
id: self.videoFeed.stream.connection.connectionId,
fromId: self.session.connection.connectionId,
fromX: client.lastX,
fromY: client.lastY,
toX: pointX,
toY: pointY,
color: resizeEvent ? event.userColor : self.userColor,
lineWidth: resizeEvent ? event.lineWidth : self.lineWidth,
videoWidth: self.videoFeed.videoElement().clientWidth,
videoHeight: self.videoFeed.videoElement().clientHeight,
canvasWidth: canvas.width,
canvasHeight: canvas.height,
mirrored: mirrored,
smoothed: selectedItem.enableSmoothing,
startPoint: firstPoint,
endPoint: endPoint
};
drawHistory.push(update);
!resizeEvent && sendUpdate(update);
client.lastX = pointX;
client.lastY = pointY;
}
draw(null);
}
draw(null);
}
client.dragging = false;
client.dragging = false;
}
}

@@ -540,342 +555,341 @@ }

}
}
addEventListeners(canvas, 'mousedown mousemove mouseup mouseout touchstart touchmove touchend', function (event) {
addEventListeners(canvas, 'mousedown mousemove mouseup mouseout touchstart touchmove touchend', function (event) {
// Handle text annotation separately and ignore mouse movements if we're not dragging.
var istextEvent = self.selectedItem && self.selectedItem.id === 'OT_text';
var notDragging = event.type === 'mousemove' && !client.dragging;
// Handle text annotation separately and ignore mouse movements if we're not dragging.
var istextEvent = self.selectedItem && self.selectedItem.id === 'OT_text';
var notDragging = event.type === 'mousemove' && !client.dragging;
if (istextEvent || notDragging) {
return;
}
if (istextEvent || notDragging) {
return;
}
event.preventDefault();
event.preventDefault();
// Save raw events to reprocess on canvas resize
event.selectedItem = self.selectedItem;
// Save raw events to reprocess on canvas resize
event.selectedItem = self.selectedItem;
if (event.selectedItem) {
event.canvas = {
width: canvas.width,
height: canvas.height,
offsetLeft: canvas.offsetLeft,
offsetTop: canvas.offsetTop
};
if (event.selectedItem) {
event.canvas = {
width: canvas.width,
height: canvas.height,
offsetLeft: canvas.offsetLeft,
offsetTop: canvas.offsetTop
};
event.userColor = self.userColor;
event.lineWidth = self.lineWidth;
eventHistory.push(event);
}
event.userColor = self.userColor;
event.lineWidth = self.lineWidth;
eventHistory.push(event);
}
updateCanvas(event);
updateCanvas(event);
});
});
/**
* We need intermediate event handling for text annotation since the user is adding
* text to an input element before it is actually added to the canvas. The original
* click event is assigned to textEvent, which is then updated before being passed
* to updateCanvas.
*/
/**
* We need intermediate event handling for text annotation since the user is adding
* text to an input element before it is actually added to the canvas. The original
* click event is assigned to textEvent, which is then updated before being passed
* to updateCanvas.
*/
/** Listen for a click on the canvas. When it occurs, append a text input
* that the user can edit and listen for keydown on the enter key. When enter is
* pressed, processTextEvent is called, the input element is removed, and the text
* is appended to the canvas.
*/
var textEvent;
var textInputId = 'textAnnotation';
var ignoreClicks = false;
var handleClick = function (event) {
/** Listen for a click on the canvas. When it occurs, append a text input
* that the user can edit and listen for keydown on the enter key. When enter is
* pressed, processTextEvent is called, the input element is removed, and the text
* is appended to the canvas.
*/
var textEvent;
var textInputId = 'textAnnotation';
var ignoreClicks = false;
var handleClick = function (event) {
event.preventDefault();
event.preventDefault();
if (!self.selectedItem || self.selectedItem.id !== 'OT_text' || ignoreClicks) {
return;
}
if (!self.selectedItem || self.selectedItem.id !== 'OT_text' || ignoreClicks) {
return;
}
ignoreClicks = true;
ignoreClicks = true;
// Save raw events to reprocess on canvas resize
event.selectedItem = self.selectedItem;
// Save raw events to reprocess on canvas resize
event.selectedItem = self.selectedItem;
createTextInput(event);
createTextInput(event);
};
};
// Listen for keydown on 'Enter' once the text input is appended
var handleKeyDown = function (event) {
// Listen for keydown on 'Enter' once the text input is appended
var handleKeyDown = function (event) {
// Enter
if (event.which === 13) {
processTextEvent();
}
// Escape
if (event.which === 27) {
context.getElementById(textInputId).remove();
textEvent = null;
}
// Enter
if (event.which === 13) {
processTextEvent();
}
// Escape
if (event.which === 27) {
context.getElementById(textInputId).remove();
textEvent = null;
}
ignoreClicks = false;
ignoreClicks = false;
};
};
var addKeyDownListener = function () {
context.addEventListener('keydown', handleKeyDown);
};
var addKeyDownListener = function () {
context.addEventListener('keydown', handleKeyDown);
};
var removeKeyDownListener = function () {
context.removeEventListener('keydown', handleKeyDown);
};
var removeKeyDownListener = function () {
context.removeEventListener('keydown', handleKeyDown);
};
/**
* Get the value of the text input and use it to create an "event".
*/
var processTextEvent = function () {
/**
* Get the value of the text input and use it to create an "event".
*/
var processTextEvent = function () {
var textInput = context.getElementById(textInputId);
var inputheight = textInput.clientHeight;
var textInput = context.getElementById(textInputId);
var inputheight = textInput.clientHeight;
if (!textInput.value) {
textEvent = null;
return;
}
if (!textInput.value) {
textEvent = null;
return;
}
textInput.remove();
removeKeyDownListener();
textInput.remove();
removeKeyDownListener();
textEvent.text = textInput.value;
textEvent.font = '16px Arial';
textEvent.userColor = self.userColor;
textEvent.text = textInput.value;
textEvent.font = '16px Arial';
textEvent.userColor = self.userColor;
textEvent.canvas = {
width: canvas.width,
height: canvas.height,
offsetLeft: canvas.offsetLeft,
offsetTop: canvas.offsetTop
}
eventHistory.push(textEvent);
updateCanvas(textEvent);
};
textEvent.canvas = {
width: canvas.width,
height: canvas.height,
offsetLeft: canvas.offsetLeft,
offsetTop: canvas.offsetTop
}
eventHistory.push(textEvent);
updateCanvas(textEvent);
};
var createTextInput = function (event) {
var createTextInput = function (event) {
var textInput = context.createElement('input');
var textInput = context.createElement('input');
textInput.setAttribute('type', 'text');
textInput.style.position = 'absolute';
textInput.style.top = event.clientY + 'px';
textInput.style.left = event.clientX + 'px';
textInput.style.background = 'rgba(255,255,255, .5)';
textInput.style.width = '100px';
textInput.style.maxWidth = '200px';
textInput.style.border = '1px dashed red';
textInput.style.fontSize = '16px';
textInput.style.color = self.userColor;
textInput.style.fontFamily = 'Arial';
textInput.style.zIndex = '1001';
textInput.setAttribute('data-canvas-origin', JSON.stringify({
x: event.offsetX,
y: event.offsetY
}));
textInput.id = textInputId;
textInput.setAttribute('type', 'text');
textInput.style.position = 'absolute';
textInput.style.top = event.clientY + 'px';
textInput.style.left = event.clientX + 'px';
textInput.style.background = 'rgba(255,255,255, .5)';
textInput.style.width = '100px';
textInput.style.maxWidth = '200px';
textInput.style.border = '1px dashed red';
textInput.style.fontSize = '16px';
textInput.style.color = self.userColor;
textInput.style.fontFamily = 'Arial';
textInput.style.zIndex = '1001';
textInput.setAttribute('data-canvas-origin', JSON.stringify({
x: event.offsetX,
y: event.offsetY
}));
textInput.id = textInputId;
context.body.appendChild(textInput);
textInput.focus();
context.body.appendChild(textInput);
textInput.focus();
textEvent = event;
textEvent.inputHeight = textInput.clientHeight;
addKeyDownListener();
textEvent = event;
textEvent.inputHeight = textInput.clientHeight;
addKeyDownListener();
};
};
addEventListeners(canvas, 'click', handleClick);
addEventListeners(canvas, 'click', handleClick);
/**
* End Handle text markup
*/
/**
* End Handle text markup
*/
var draw = function (update, resizeEvent) {
var draw = function (update, resizeEvent) {
if (!ctx) {
ctx = canvas.getContext('2d');
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.fillStyle = 'solid';
}
if (!ctx) {
ctx = canvas.getContext('2d');
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.fillStyle = 'solid';
}
// Clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Repopulate the canvas with items from drawHistory
drawHistory.forEach(function (history) {
// Repopulate the canvas with items from drawHistory
drawHistory.forEach(function (history) {
ctx.strokeStyle = history.color;
ctx.lineWidth = history.lineWidth;
ctx.strokeStyle = history.color;
ctx.lineWidth = history.lineWidth;
// INFO iOS serializes bools as 0 or 1
history.smoothed = !!history.smoothed;
history.startPoint = !!history.startPoint;
// INFO iOS serializes bools as 0 or 1
history.smoothed = !!history.smoothed;
history.startPoint = !!history.startPoint;
var secondPoint = false;
var isText = !!history.selectedItem && history.selectedItem.title === 'Text' && history.text;
var secondPoint = false;
var isText = !!history.selectedItem && history.selectedItem.title === 'Text' && history.text;
if (isText) {
if (isText) {
ctx.font = history.font;
ctx.fillStyle = history.color;
ctx.fillText(history.text, history.fromX, history.fromY);
ctx.font = history.font;
ctx.fillStyle = history.color;
ctx.fillText(history.text, history.fromX, history.fromY);
} else {
} else {
if (history.smoothed) {
if (history.startPoint) {
self.isStartPoint = true;
} else {
// If the start point flag was already set, we received the next point in the sequence
if (self.isStartPoint) {
secondPoint = true;
self.isStartPoint = false;
if (history.smoothed) {
if (history.startPoint) {
self.isStartPoint = true;
} else {
// If the start point flag was already set, we received the next point in the sequence
if (self.isStartPoint) {
secondPoint = true;
self.isStartPoint = false;
}
}
}
if (history.startPoint) {
// Close the last path and create a new one
ctx.closePath();
if (history.startPoint) {
// Close the last path and create a new one
ctx.closePath();
ctx.beginPath();
} else if (secondPoint) {
ctx.moveTo((history.fromX + history.toX) / 2, (history.fromY + history.toY) / 2);
} else {
// console.log('Points: (' + (history.fromX + history.toX) / 2 + ', ' + (history.fromY + history.toY) / 2 + ')');
// console.log('Control Points: (' + history.fromX + ', ' + history.fromY + ')');
ctx.quadraticCurveTo(history.fromX, history.fromY, (history.fromX + history.toX) / 2, (history.fromY + history.toY) / 2);
ctx.stroke();
}
} else {
ctx.beginPath();
} else if (secondPoint) {
ctx.moveTo((history.fromX + history.toX) / 2, (history.fromY + history.toY) / 2);
} else {
// console.log('Points: (' + (history.fromX + history.toX) / 2 + ', ' + (history.fromY + history.toY) / 2 + ')');
// console.log('Control Points: (' + history.fromX + ', ' + history.fromY + ')');
ctx.quadraticCurveTo(history.fromX, history.fromY, (history.fromX + history.toX) / 2, (history.fromY + history.toY) / 2);
ctx.moveTo(history.fromX, history.fromY);
ctx.lineTo(history.toX, history.toY);
ctx.stroke();
ctx.closePath();
}
} else {
ctx.beginPath();
ctx.moveTo(history.fromX, history.fromY);
ctx.lineTo(history.toX, history.toY);
ctx.stroke();
ctx.closePath();
}
}
});
});
var selectedItem = !!resizeEvent ? update.selectedItem : self.selectedItem;
var selectedItem = !!resizeEvent ? update.selectedItem : self.selectedItem;
if (selectedItem && (selectedItem.title === 'Pen' || selectedItem.title === 'Text')) {
if (selectedItem && (selectedItem.title === 'Pen' || selectedItem.title === 'Text')) {
if (update) {
if (update) {
if (selectedItem.title === 'Pen') {
ctx.strokeStyle = update.color;
ctx.lineWidth = update.lineWidth;
ctx.beginPath();
ctx.moveTo(update.fromX, update.fromY);
ctx.lineTo(update.toX, update.toY);
ctx.stroke();
ctx.closePath();
}
if (selectedItem.title === 'Pen') {
ctx.strokeStyle = update.color;
ctx.lineWidth = update.lineWidth;
ctx.beginPath();
ctx.moveTo(update.fromX, update.fromY);
ctx.lineTo(update.toX, update.toY);
ctx.stroke();
ctx.closePath();
}
if (selectedItem.title === 'Text') {
ctx.font = update.font;
ctx.fillStyle = update.color;
ctx.fillText(update.text, update.fromX, update.fromY);
}
if (selectedItem.title === 'Text') {
ctx.font = update.font;
ctx.fillStyle = update.color;
ctx.fillText(update.text, update.fromX, update.fromY);
}
drawHistory.push(update);
}
} else {
if (client.isDrawing) {
if (update) {
ctx.strokeStyle = update.color;
ctx.lineWidth = update.lineWidth;
drawHistory.push(update);
}
if (selectedItem && selectedItem.points) {
drawPoints(ctx, self.selectedItem.points);
} else {
if (client.isDrawing) {
if (update) {
ctx.strokeStyle = update.color;
ctx.lineWidth = update.lineWidth;
}
if (selectedItem && selectedItem.points) {
drawPoints(ctx, self.selectedItem.points);
}
}
}
}
};
};
var drawPoints = function (ctx, points) {
var scale = scaleForPoints(points);
var drawPoints = function (ctx, points) {
var scale = scaleForPoints(points);
ctx.beginPath();
ctx.beginPath();
if (points.length === 2) {
// We have a line
ctx.moveTo(client.startX, client.startY);
ctx.lineTo(client.mX, client.mY);
} else {
for (var i = 0; i < points.length; i++) {
// Scale the points according to the difference between the start and end points
var pointX = client.startX + (scale.x * points[i][0]);
var pointY = client.startY + (scale.y * points[i][1]);
if (points.length === 2) {
// We have a line
ctx.moveTo(client.startX, client.startY);
ctx.lineTo(client.mX, client.mY);
} else {
for (var i = 0; i < points.length; i++) {
// Scale the points according to the difference between the start and end points
var pointX = client.startX + (scale.x * points[i][0]);
var pointY = client.startY + (scale.y * points[i][1]);
if (self.selectedItem.enableSmoothing) {
if (i === 0) {
// Do nothing
} else if (i === 1) {
ctx.moveTo((pointX + client.lastX) / 2, (pointY + client.lastY) / 2);
client.lastX = (pointX + client.lastX) / 2;
client.lastX = (pointY + client.lastY) / 2;
if (self.selectedItem.enableSmoothing) {
if (i === 0) {
// Do nothing
} else if (i === 1) {
ctx.moveTo((pointX + client.lastX) / 2, (pointY + client.lastY) / 2);
client.lastX = (pointX + client.lastX) / 2;
client.lastX = (pointY + client.lastY) / 2;
} else {
ctx.quadraticCurveTo(client.lastX, client.lastY, (pointX + client.lastX) / 2, (pointY + client.lastY) / 2);
client.lastX = (pointX + client.lastX) / 2;
client.lastY = (pointY + client.lastY) / 2;
}
} else {
ctx.quadraticCurveTo(client.lastX, client.lastY, (pointX + client.lastX) / 2, (pointY + client.lastY) / 2);
client.lastX = (pointX + client.lastX) / 2;
client.lastY = (pointY + client.lastY) / 2;
if (i === 0) {
ctx.moveTo(pointX, pointY);
} else {
ctx.lineTo(pointX, pointY);
}
}
} else {
if (i === 0) {
ctx.moveTo(pointX, pointY);
} else {
ctx.lineTo(pointX, pointY);
}
client.lastX = pointX;
client.lastY = pointY;
}
client.lastX = pointX;
client.lastY = pointY;
}
}
ctx.stroke();
ctx.closePath();
};
ctx.stroke();
ctx.closePath();
};
var scaleForPoints = function (points) {
// mX and mY refer to the end point of the enclosing rectangle (touch up)
var minX = Number.MAX_VALUE;
var minY = Number.MAX_VALUE;
var maxX = 0;
var maxY = 0;
for (var i = 0; i < points.length; i++) {
if (points[i][0] < minX) {
minX = points[i][0];
} else if (points[i][0] > maxX) {
maxX = points[i][0];
}
var scaleForPoints = function (points) {
// mX and mY refer to the end point of the enclosing rectangle (touch up)
var minX = Number.MAX_VALUE;
var minY = Number.MAX_VALUE;
var maxX = 0;
var maxY = 0;
for (var i = 0; i < points.length; i++) {
if (points[i][0] < minX) {
minX = points[i][0];
} else if (points[i][0] > maxX) {
maxX = points[i][0];
}
if (points[i][1] < minY) {
minY = points[i][1];
} else if (points[i][1] > maxY) {
maxY = points[i][1];
if (points[i][1] < minY) {
minY = points[i][1];
} else if (points[i][1] > maxY) {
maxY = points[i][1];
}
}
}
var dx = Math.abs(maxX - minX);
var dy = Math.abs(maxY - minY);
var dx = Math.abs(maxX - minX);
var dy = Math.abs(maxY - minY);
var scaleX = (client.mX - client.startX) / dx;
var scaleY = (client.mY - client.startY) / dy;
var scaleX = (client.mX - client.startX) / dx;
var scaleY = (client.mY - client.startY) / dy;
return {
x: scaleX,
y: scaleY
return {
x: scaleX,
y: scaleY
};
};
};
var drawTextUpdate = function (update) {
var drawTextUpdate = function (update) {

@@ -886,854 +900,863 @@

};
};
var drawIncoming = function (update, resizeEvent, index) {
var drawIncoming = function (update, resizeEvent, index) {
var iCanvas = {
width: update.canvasWidth,
height: update.canvasHeight
};
var iCanvas = {
width: update.canvasWidth,
height: update.canvasHeight
};
var iVideo = {
width: update.videoWidth,
height: update.videoHeight
};
var iVideo = {
width: update.videoWidth,
height: update.videoHeight
};
var video = {
width: self.videoFeed.videoElement().clientWidth,
height: self.videoFeed.videoElement().clientHeight
};
var video = {
width: self.videoFeed.videoElement().clientWidth,
height: self.videoFeed.videoElement().clientHeight
};
var scale = 1;
var scale = 1;
var canvasRatio = canvas.width / canvas.height;
var videoRatio = video.width / video.height;
var iCanvasRatio = iCanvas.width / iCanvas.height;
var iVideoRatio = iVideo.width / iVideo.height;
var canvasRatio = canvas.width / canvas.height;
var videoRatio = video.width / video.height;
var iCanvasRatio = iCanvas.width / iCanvas.height;
var iVideoRatio = iVideo.width / iVideo.height;
/**
* This assumes that if the width is the greater value, video frames
* can be scaled so that they have equal widths, which can be used to
* find the offset in the y axis. Therefore, the offset on the x axis
* will be 0. If the height is the greater value, the offset on the y
* axis will be 0.
*/
if (canvasRatio < 0) {
scale = canvas.width / iCanvas.width;
} else {
scale = canvas.height / iCanvas.height;
}
/**
* This assumes that if the width is the greater value, video frames
* can be scaled so that they have equal widths, which can be used to
* find the offset in the y axis. Therefore, the offset on the x axis
* will be 0. If the height is the greater value, the offset on the y
* axis will be 0.
*/
if (canvasRatio < 0) {
scale = canvas.width / iCanvas.width;
} else {
scale = canvas.height / iCanvas.height;
}
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var iCenterX = iCanvas.width / 2;
var iCenterY = iCanvas.height / 2;
var iCenterX = iCanvas.width / 2;
var iCenterY = iCanvas.height / 2;
update.fromX = centerX - (scale * (iCenterX - update.fromX));
update.fromY = centerY - (scale * (iCenterY - update.fromY));
update.fromX = centerX - (scale * (iCenterX - update.fromX));
update.fromY = centerY - (scale * (iCenterY - update.fromY));
update.toX = centerX - (scale * (iCenterX - update.toX));
update.toY = centerY - (scale * (iCenterY - update.toY));
update.toX = centerX - (scale * (iCenterX - update.toX));
update.toY = centerY - (scale * (iCenterY - update.toY));
// INFO iOS serializes bools as 0 or 1
update.mirrored = !!update.mirrored;
// INFO iOS serializes bools as 0 or 1
update.mirrored = !!update.mirrored;
// Check if the incoming signal was mirrored
if (update.mirrored) {
update.fromX = canvas.width - update.fromX;
update.toX = canvas.width - update.toX;
}
// Check if the incoming signal was mirrored
if (update.mirrored) {
update.fromX = canvas.width - update.fromX;
update.toX = canvas.width - update.toX;
}
// Check to see if the active video feed is also mirrored (double negative)
if (mirrored) {
// Revert (Double negative)
update.fromX = canvas.width - update.fromX;
update.toX = canvas.width - update.toX;
}
// Check to see if the active video feed is also mirrored (double negative)
if (mirrored) {
// Revert (Double negative)
update.fromX = canvas.width - update.fromX;
update.toX = canvas.width - update.toX;
}
/** Keep history of updates for resize */
var updateForHistory = JSON.parse(JSON.stringify(update));
updateForHistory.canvasWidth = canvas.width;
updateForHistory.canvasHeight = canvas.height;
updateForHistory.videoWidth = video.width;
updateForHistory.videoHeight = video.height;
/** Keep history of updates for resize */
var updateForHistory = JSON.parse(JSON.stringify(update));
updateForHistory.canvasWidth = canvas.width;
updateForHistory.canvasHeight = canvas.height;
updateForHistory.videoWidth = video.width;
updateForHistory.videoHeight = video.height;
if (resizeEvent) {
updateHistory[index] = updateForHistory;
} else {
updateHistory.push(updateForHistory);
}
/** ********************************** */
if (resizeEvent) {
updateHistory[index] = updateForHistory;
} else {
updateHistory.push(updateForHistory);
}
/** ********************************** */
drawHistory.push(update);
drawHistory.push(update);
draw(null);
};
draw(null);
};
var drawUpdates = function (updates, resizeEvent) {
var drawUpdates = function (updates, resizeEvent) {
updates.forEach(function (update, index) {
if (self.videoFeed.stream && update.id === self.videoFeed.stream.connection.connectionId) {
drawIncoming(update, resizeEvent, index);
}
});
};
updates.forEach(function (update, index) {
if (self.videoFeed.stream && update.id === self.videoFeed.stream.connection.connectionId) {
drawIncoming(update, resizeEvent, index);
}
});
};
var clearCanvas = function (incoming, cid) {
// console.log('cid: ' + cid);
// Remove all elements from history that were drawn by the sender
drawHistory = drawHistory.filter(function (history) {
console.log(history.fromId);
return history.fromId !== cid;
});
var clearCanvas = function (incoming, cid) {
// console.log('cid: ' + cid);
// Remove all elements from history that were drawn by the sender
drawHistory = drawHistory.filter(function (history) {
console.log(history.fromId);
return history.fromId !== cid;
});
if (!incoming) {
if (self.session) {
self.session.signal({
type: 'otAnnotation_clear'
});
if (!incoming) {
if (self.session) {
self.session.signal({
type: 'otAnnotation_clear'
});
}
eventHistory = [];
} else {
updateHistory = [];
}
eventHistory = [];
} else {
updateHistory = [];
}
// Refresh the canvas
draw();
};
// Refresh the canvas
draw();
};
/** Signal Handling **/
if (self.videoFeed.session) {
self.videoFeed.session.on({
'signal:otAnnotation_pen': function (event) {
if (event.from.connectionId !== self.session.connection.connectionId) {
drawUpdates(JSON.parse(event.data));
/** Signal Handling **/
if (self.videoFeed.session) {
self.videoFeed.session.on({
'signal:otAnnotation_pen': function (event) {
if (event.from.connectionId !== self.session.connection.connectionId) {
drawUpdates(JSON.parse(event.data));
}
},
'signal:otAnnotation_text': function (event) {
if (event.from.connectionId !== self.session.connection.connectionId) {
drawUpdates(JSON.parse(event.data));
}
},
'signal:otAnnotation_history': function (event) {
// We will receive these from everyone in the room, only listen to the first
// person. Also the data is chunked together so we need all of that person's
if (!drawHistoryReceivedFrom || drawHistoryReceivedFrom === event.from.connectionId) {
drawHistoryReceivedFrom = event.from.connectionId;
drawUpdates(JSON.parse(event.data));
}
},
'signal:otAnnotation_clear': function (event) {
if (event.from.connectionId !== self.session.connection.connectionId) {
// Only clear elements drawn by the sender's (from) Id
clearCanvas(true, event.from.connectionId);
}
},
connectionCreated: function (event) {
if (drawHistory.length > 0 && event.connection.connectionId !== self.session.connection.connectionId) {
batchSignal('otWhiteboard_history', drawHistory, event.connection);
}
}
},
'signal:otAnnotation_text': function (event) {
if (event.from.connectionId !== self.session.connection.connectionId) {
drawUpdates(JSON.parse(event.data));
});
}
var batchSignal = function (data, toConnection) {
// We send data in small chunks so that they fit in a signal
// Each packet is maximum ~250 chars, we can fit 8192/250 ~= 32 updates per signal
var dataCopy = data.slice();
var signalError = function (err) {
if (err) {
TB.error(err);
}
},
'signal:otAnnotation_history': function (event) {
// We will receive these from everyone in the room, only listen to the first
// person. Also the data is chunked together so we need all of that person's
if (!drawHistoryReceivedFrom || drawHistoryReceivedFrom === event.from.connectionId) {
drawHistoryReceivedFrom = event.from.connectionId;
drawUpdates(JSON.parse(event.data));
};
var type = 'otAnnotation_pen';
var updateType = function (chunk) {
if (!chunk || !chunk[0] || !chunk[0].selectedItem || !chunk[0].selectedItem.id) {
return;
}
},
'signal:otAnnotation_clear': function (event) {
if (event.from.connectionId !== self.session.connection.connectionId) {
// Only clear elements drawn by the sender's (from) Id
clearCanvas(true, event.from.connectionId);
}
},
connectionCreated: function (event) {
if (drawHistory.length > 0 && event.connection.connectionId !== self.session.connection.connectionId) {
batchSignal('otWhiteboard_history', drawHistory, event.connection);
}
}
});
}
var id = chunk[0].selectedItem.id;
type = id === 'OT_text' ? 'otAnnotation_text' : 'otAnnotation_pen';
};
var batchSignal = function (data, toConnection) {
// We send data in small chunks so that they fit in a signal
// Each packet is maximum ~250 chars, we can fit 8192/250 ~= 32 updates per signal
var dataCopy = data.slice();
var signalError = function (err) {
if (err) {
TB.error(err);
while (dataCopy.length) {
var dataChunk = dataCopy.splice(0, Math.min(dataCopy.length, 32));
updateType(dataChunk);
var signal = {
type: type,
data: JSON.stringify(dataChunk)
};
if (toConnection) signal.to = toConnection;
self.session.signal(signal, signalError);
}
};
var type = 'otAnnotation_pen';
var updateType = function (chunk) {
if (!chunk || !chunk[0] || !chunk[0].selectedItem || !chunk[0].selectedItem.id) {
return;
var updateTimeout;
var sendUpdate = function (update) {
if (self.session) {
batchUpdates.push(update);
if (!updateTimeout) {
updateTimeout = setTimeout(function () {
batchSignal(batchUpdates);
batchUpdates = [];
updateTimeout = null;
}, 100);
}
}
var id = chunk[0].selectedItem.id;
type = id === 'OT_text' ? 'otAnnotation_text' : 'otAnnotation_pen';
};
while (dataCopy.length) {
var dataChunk = dataCopy.splice(0, Math.min(dataCopy.length, 32));
updateType(dataChunk);
var signal = {
type: type,
data: JSON.stringify(dataChunk)
};
if (toConnection) signal.to = toConnection;
self.session.signal(signal, signalError);
}
};
var updateTimeout;
var sendUpdate = function (update) {
if (self.session) {
batchUpdates.push(update);
if (!updateTimeout) {
updateTimeout = setTimeout(function () {
batchSignal(batchUpdates);
batchUpdates = [];
updateTimeout = null;
}, 100);
}
}
};
};
//--------------------------------------
// OPENTOK ANNOTATION TOOLBAR
//--------------------------------------
//--------------------------------------
// OPENTOK ANNOTATION TOOLBAR
//--------------------------------------
OTSolution.Annotations.Toolbar = function (options) {
var self = this;
var _toolbar = this;
OTSolution.Annotations.Toolbar = function (options) {
var self = this;
var _toolbar = this;
options || (options = {});
options || (options = {});
if (!options.session) {
throw new Error('OpenTok Annotation Widget requires an OpenTok session');
} else {
_session = options.session;
}
if (!options.session) {
throw new Error('OpenTok Annotation Widget requires an OpenTok session');
} else {
_session = options.session;
}
if (!_OTKAnalytics && !options.OTKAnalytics) {
throw new Error('OpenTok Annotation Widget requires an OpenTok Solution');
} else {
_OTKAnalytics = _OTKAnalytics || options.OTKAnalytics;
if (!_otkanalytics) {
_logAnalytics();
}
}
this.session = options.session;
this.parent = options.container;
this.externalWindow = options.externalWindow;
// TODO Allow 'style' objects to be passed in for buttons, menu toolbar, etc?
this.backgroundColor = options.backgroundColor || 'rgba(0, 0, 0, 0.7)';
this.buttonWidth = options.buttonWidth || '40px';
this.buttonHeight = options.buttonHeight || '40px';
this.iconWidth = options.iconWidth || '30px';
this.iconHeight = options.iconHeight || '30px';
this.items = options.items || [{
id: 'OT_pen',
title: 'Pen',
icon: '../images/annotation/freehand.png',
selectedIcon: '../images/annotation/freehand_selected.png'
}, {
id: 'OT_line',
title: 'Line',
icon: '../images/annotation/line.png',
selectedIcon: '../images/annotation/line_selected.png',
points: [
[0, 0],
[0, 1]
]
}, {
id: 'OT_shapes',
title: 'Shapes',
icon: '../images/annotation/shapes.png',
items: [{
id: 'OT_arrow',
title: 'Arrow',
icon: '../images/annotation/arrow.png',
points: [
[0, 1],
[3, 1],
[3, 0],
[5, 2],
[3, 4],
[3, 3],
[0, 3],
[0, 1] // Reconnect point
]
if (!_otkanalytics) {
_logAnalytics();
}
this.session = options.session;
this.parent = options.container;
this.externalWindow = options.externalWindow;
// TODO Allow 'style' objects to be passed in for buttons, menu toolbar, etc?
this.backgroundColor = options.backgroundColor || 'rgba(0, 0, 0, 0.7)';
this.buttonWidth = options.buttonWidth || '40px';
this.buttonHeight = options.buttonHeight || '40px';
this.iconWidth = options.iconWidth || '30px';
this.iconHeight = options.iconHeight || '30px';
this.items = options.items || [{
id: 'OT_pen',
title: 'Pen',
icon: '../images/annotation/freehand.png',
selectedIcon: '../images/annotation/freehand_selected.png'
}, {
id: 'OT_rect',
title: 'Rectangle',
icon: '../images/annotation/rectangle.png',
id: 'OT_line',
title: 'Line',
icon: '../images/annotation/line.png',
selectedIcon: '../images/annotation/line_selected.png',
points: [
[0, 0],
[1, 0],
[1, 1],
[0, 1],
[0, 0] // Reconnect point
[0, 1]
]
}, {
id: 'OT_oval',
title: 'Oval',
icon: '../images/annotation/oval.png',
enableSmoothing: true,
points: [
[0, 0.5],
[0.5 + 0.5 * Math.cos(5 * Math.PI / 4), 0.5 + 0.5 * Math.sin(5 * Math.PI / 4)],
[0.5, 0],
[0.5 + 0.5 * Math.cos(7 * Math.PI / 4), 0.5 + 0.5 * Math.sin(7 * Math.PI / 4)],
[1, 0.5],
[0.5 + 0.5 * Math.cos(Math.PI / 4), 0.5 + 0.5 * Math.sin(Math.PI / 4)],
[0.5, 1],
[0.5 + 0.5 * Math.cos(3 * Math.PI / 4), 0.5 + 0.5 * Math.sin(3 * Math.PI / 4)],
[0, 0.5],
[0.5 + 0.5 * Math.cos(5 * Math.PI / 4), 0.5 + 0.5 * Math.sin(5 * Math.PI / 4)]
]
}]
}, {
id: 'OT_text',
title: 'Text',
icon: '../images/annotation/text.png',
selectedIcon: '../images/annotation/text.png'
}, {
id: 'OT_colors',
title: 'Colors',
icon: '',
items: { /* Built dynamically */ }
}, {
id: 'OT_line_width',
title: 'Line Width',
icon: '../images/annotation/line_width.png',
items: { /* Built dynamically */ }
}, {
id: 'OT_clear',
title: 'Clear',
icon: '../images/annotation/clear.png'
}, {
id: 'OT_capture',
title: 'Capture',
icon: '../images/annotation/camera.png',
selectedIcon: '../images/annotation/camera_selected.png'
}];
this.colors = options.colors || [
'#1abc9c',
'#2ecc71',
'#3498db',
'#9b59b6',
'#34495e',
'#16a085',
'#27ae60',
'#2980b9',
'#8e44ad',
'#2c3e50',
'#f1c40f',
'#e67e22',
'#e74c3c',
'#ecf0f1',
'#95a5a6',
'#f39c12',
'#d35400',
'#c0392b',
'#bdc3c7',
'#7f8c8d'
];
id: 'OT_shapes',
title: 'Shapes',
icon: '../images/annotation/shapes.png',
items: [{
id: 'OT_arrow',
title: 'Arrow',
icon: '../images/annotation/arrow.png',
points: [
[0, 1],
[3, 1],
[3, 0],
[5, 2],
[3, 4],
[3, 3],
[0, 3],
[0, 1] // Reconnect point
]
}, {
id: 'OT_rect',
title: 'Rectangle',
icon: '../images/annotation/rectangle.png',
points: [
[0, 0],
[1, 0],
[1, 1],
[0, 1],
[0, 0] // Reconnect point
]
}, {
id: 'OT_oval',
title: 'Oval',
icon: '../images/annotation/oval.png',
enableSmoothing: true,
points: [
[0, 0.5],
[0.5 + 0.5 * Math.cos(5 * Math.PI / 4), 0.5 + 0.5 * Math.sin(5 * Math.PI / 4)],
[0.5, 0],
[0.5 + 0.5 * Math.cos(7 * Math.PI / 4), 0.5 + 0.5 * Math.sin(7 * Math.PI / 4)],
[1, 0.5],
[0.5 + 0.5 * Math.cos(Math.PI / 4), 0.5 + 0.5 * Math.sin(Math.PI / 4)],
[0.5, 1],
[0.5 + 0.5 * Math.cos(3 * Math.PI / 4), 0.5 + 0.5 * Math.sin(3 * Math.PI / 4)],
[0, 0.5],
[0.5 + 0.5 * Math.cos(5 * Math.PI / 4), 0.5 + 0.5 * Math.sin(5 * Math.PI / 4)]
]
}]
}, {
id: 'OT_text',
title: 'Text',
icon: '../images/annotation/text.png',
selectedIcon: '../images/annotation/text.png'
}, {
id: 'OT_colors',
title: 'Colors',
icon: '',
items: { /* Built dynamically */ }
}, {
id: 'OT_line_width',
title: 'Line Width',
icon: '../images/annotation/line_width.png',
items: { /* Built dynamically */ }
}, {
id: 'OT_clear',
title: 'Clear',
icon: '../images/annotation/clear.png'
}, {
id: 'OT_capture',
title: 'Capture',
icon: '../images/annotation/camera.png',
selectedIcon: '../images/annotation/camera_selected.png'
}];
this.colors = options.colors || [
'#1abc9c',
'#2ecc71',
'#3498db',
'#9b59b6',
'#34495e',
'#16a085',
'#27ae60',
'#2980b9',
'#8e44ad',
'#2c3e50',
'#f1c40f',
'#e67e22',
'#e74c3c',
'#ecf0f1',
'#95a5a6',
'#f39c12',
'#d35400',
'#c0392b',
'#bdc3c7',
'#7f8c8d'
];
this.cbs = [];
var canvases = [];
this.cbs = [];
var canvases = [];
/**
* Creates a sub-menu with a color picker.
*
* @param {String|Element} parent The parent div container for the color picker sub-menu.
* @param {Array} colors The array of colors to add to the palette.
* @param {Object} options options An object containing the following fields:
*
* - `openEvent` (String): The open event (default: `"click"`).
* - `style` (Object): Some style options:
* - `display` (String): The display value when the picker is opened (default: `"block"`).
* - `template` (String): The color item template. The `{color}` snippet will be replaced
* with the color value (default: `"<div data-col=\"{color}\" style=\"background-color: {color}\"></div>"`).
* - `autoclose` (Boolean): If `false`, the color picker will not be hidden by default (default: `true`).
*
* @constructor
*/
var ColorPicker = function (parent, colors, options) {
var self = this;
var context = _toolbar.externalWindow ? _toolbar.externalWindow.document : document;
/**
* Creates a sub-menu with a color picker.
*
* @param {String|Element} parent The parent div container for the color picker sub-menu.
* @param {Array} colors The array of colors to add to the palette.
* @param {Object} options options An object containing the following fields:
*
* - `openEvent` (String): The open event (default: `"click"`).
* - `style` (Object): Some style options:
* - `display` (String): The display value when the picker is opened (default: `"block"`).
* - `template` (String): The color item template. The `{color}` snippet will be replaced
* with the color value (default: `"<div data-col=\"{color}\" style=\"background-color: {color}\"></div>"`).
* - `autoclose` (Boolean): If `false`, the color picker will not be hidden by default (default: `true`).
*
* @constructor
*/
var ColorPicker = function (parent, colors, options) {
var self = this;
var context = _toolbar.externalWindow ? _toolbar.externalWindow.document : document;
this.getElm = function (el) {
if (typeof el === 'string') {
return context.querySelector(el);
}
return el;
};
this.getElm = function (el) {
if (typeof el === 'string') {
return context.querySelector(el);
}
return el;
};
this.render = function () {
var self = this,
html = '';
this.render = function () {
var self = this,
html = '';
self.colors.forEach(function (c) {
html += self.options.template.replace(/\{color\}/g, c);
});
self.colors.forEach(function (c) {
html += self.options.template.replace(/\{color\}/g, c);
});
self.elm.innerHTML = html;
};
self.elm.innerHTML = html;
};
this.close = function () {
this.elm.style.display = 'none';
};
this.close = function () {
this.elm.style.display = 'none';
};
this.open = function () {
this.elm.style.display = this.options.style.display;
};
this.open = function () {
this.elm.style.display = this.options.style.display;
};
this.colorChosen = function (cb) {
this.cbs.push(cb);
};
this.colorChosen = function (cb) {
this.cbs.push(cb);
};
this.set = function (c, p) {
var self = this;
self.color = c;
if (p === false) {
return;
this.set = function (c, p) {
var self = this;
self.color = c;
if (p === false) {
return;
}
self.cbs.forEach(function (cb) {
cb.call(self, c);
});
};
options = options || {};
options.openEvent = options.openEvent || 'click';
options.style = Object(options.style);
options.style.display = options.style.display || 'block';
options.template = options.template || '<div class=\"color-choice\" data-col=\"{color}\" style=\"background-color: {color}\"></div>';
self.elm = self.getElm(parent);
self.cbs = [];
self.colors = colors;
self.options = options;
self.render();
// Click on colors
self.elm.addEventListener('click', function (ev) {
var color = ev.target.getAttribute('data-col');
if (!color) {
return;
}
self.set(color);
self.close();
});
if (options.autoclose !== false) {
self.close();
}
self.cbs.forEach(function (cb) {
cb.call(self, c);
});
};
options = options || {};
options.openEvent = options.openEvent || 'click';
options.style = Object(options.style);
options.style.display = options.style.display || 'block';
options.template = options.template || '<div class=\"color-choice\" data-col=\"{color}\" style=\"background-color: {color}\"></div>';
self.elm = self.getElm(parent);
self.cbs = [];
self.colors = colors;
self.options = options;
self.render();
var panel;
this.createPanel = function (externalWindow) {
if (_toolbar.parent) {
var context = externalWindow ? externalWindow.document : document;
panel = context.createElement('div');
panel.setAttribute('id', 'OT_toolbar');
panel.setAttribute('class', 'OT_panel');
panel.style.width = '100%';
panel.style.height = '100%';
panel.style.backgroundColor = this.backgroundColor;
// panel.style.paddingLeft = '15px';
this.parent.appendChild(panel);
this.parent.style.position = 'relative';
this.parent.zIndex = 1000;
// Click on colors
self.elm.addEventListener('click', function (ev) {
var color = ev.target.getAttribute('data-col');
if (!color) {
return;
}
self.set(color);
self.close();
});
var toolbarItems = [];
var subPanel = context.createElement('div');
if (options.autoclose !== false) {
self.close();
}
};
for (var i = 0, total = this.items.length; i < total; i++) {
var item = this.items[i];
var panel;
this.createPanel = function (externalWindow) {
if (_toolbar.parent) {
var context = externalWindow ? externalWindow.document : document;
panel = context.createElement('div');
panel.setAttribute('id', 'OT_toolbar');
panel.setAttribute('class', 'OT_panel');
panel.style.width = '100%';
panel.style.height = '100%';
panel.style.backgroundColor = this.backgroundColor;
// panel.style.paddingLeft = '15px';
this.parent.appendChild(panel);
this.parent.style.position = 'relative';
this.parent.zIndex = 1000;
var button = context.createElement('input');
button.setAttribute('type', 'button');
button.setAttribute('id', item.id);
var toolbarItems = [];
var subPanel = context.createElement('div');
button.style.position = 'relative';
button.style.top = '50%';
button.style.transform = 'translateY(-50%)';
for (var i = 0, total = this.items.length; i < total; i++) {
var item = this.items[i];
if (item.id === 'OT_colors') {
button.style.webkitTransform = 'translateY(-85%)';
var button = context.createElement('input');
button.setAttribute('type', 'button');
button.setAttribute('id', item.id);
var colorPicker = context.createElement('div');
colorPicker.setAttribute('class', 'color-picker');
colorPicker.style.backgroundColor = this.backgroundColor;
this.parent.appendChild(colorPicker);
button.style.position = 'relative';
button.style.top = '50%';
button.style.transform = 'translateY(-50%)';
var pk = new ColorPicker('.color-picker', this.colors, {
externalWindow: _toolbar.externalWindow
});
if (item.id === 'OT_colors') {
button.style.webkitTransform = 'translateY(-85%)';
pk.colorChosen(function (color) {
var colorGroup = context.getElementById('OT_colors');
colorGroup.style.backgroundColor = color;
var colorPicker = context.createElement('div');
colorPicker.setAttribute('class', 'color-picker');
colorPicker.style.backgroundColor = this.backgroundColor;
this.parent.appendChild(colorPicker);
canvases.forEach(function (canvas) {
canvas.changeColor(color);
});
});
var pk = new ColorPicker('.color-picker', this.colors, {
externalWindow: _toolbar.externalWindow
});
var colorChoices = context.querySelectorAll('.color-choice');
pk.colorChosen(function (color) {
var colorGroup = context.getElementById('OT_colors');
colorGroup.style.backgroundColor = color;
for (var j = 0; j < colorChoices.length; j++) {
colorChoices[j].style.display = 'inline-block';
colorChoices[j].style.width = '30px';
colorChoices[j].style.height = '30px';
colorChoices[j].style.margin = '5px';
colorChoices[j].style.cursor = 'pointer';
colorChoices[j].style.borderRadius = '100%';
colorChoices[j].style.opacity = 0.7;
colorChoices[j].onmouseover = function () {
this.style.opacity = 1;
};
colorChoices[j].onmouseout = function () {
this.style.opacity = 0.7;
};
}
canvases.forEach(function (canvas) {
canvas.changeColor(color);
});
});
button.setAttribute('class', 'OT_color');
button.style.marginLeft = '10px';
button.style.marginRight = '10px';
button.style.borderRadius = '50%';
button.style.backgroundColor = this.colors[0];
button.style.width = this.iconWidth;
button.style.height = this.iconHeight;
button.style.paddingTop = this.buttonHeight.replace('px', '') - this.iconHeight.replace('px', '') + 'px';
} else {
button.style.background = 'url("' + item.icon + '") no-repeat';
button.style.backgroundSize = this.iconWidth + ' ' + this.iconHeight;
button.style.backgroundPosition = 'center';
button.style.width = this.buttonWidth;
button.style.height = this.buttonHeight;
}
var colorChoices = context.querySelectorAll('.color-choice');
// If we have an object as item.items, it was never set by the user
if (item.title === 'Line Width' && !Array.isArray(item.items)) {
// Add defaults
item.items = [{
id: 'OT_line_width_2',
title: 'Line Width 2',
size: 2
}, {
id: 'OT_line_width_4',
title: 'Line Width 4',
size: 4
}, {
id: 'OT_line_width_6',
title: 'Line Width 6',
size: 6
}, {
id: 'OT_line_width_8',
title: 'Line Width 8',
size: 8
}, {
id: 'OT_line_width_10',
title: 'Line Width 10',
size: 10
}, {
id: 'OT_line_width_12',
title: 'Line Width 12',
size: 12
}, {
id: 'OT_line_width_14',
title: 'Line Width 14',
size: 14
}];
}
for (var j = 0; j < colorChoices.length; j++) {
colorChoices[j].style.display = 'inline-block';
colorChoices[j].style.width = '30px';
colorChoices[j].style.height = '30px';
colorChoices[j].style.margin = '5px';
colorChoices[j].style.cursor = 'pointer';
colorChoices[j].style.borderRadius = '100%';
colorChoices[j].style.opacity = 0.7;
colorChoices[j].onmouseover = function () {
this.style.opacity = 1;
};
colorChoices[j].onmouseout = function () {
this.style.opacity = 0.7;
};
if (item.items) {
// Indicate that we have a group
button.setAttribute('data-type', 'group');
}
button.setAttribute('class', 'OT_color');
button.style.marginLeft = '10px';
button.style.marginRight = '10px';
button.style.borderRadius = '50%';
button.style.backgroundColor = this.colors[0];
button.style.width = this.iconWidth;
button.style.height = this.iconHeight;
button.style.paddingTop = this.buttonHeight.replace('px', '') - this.iconHeight.replace('px', '') + 'px';
} else {
button.style.background = 'url("' + item.icon + '") no-repeat';
button.style.backgroundSize = this.iconWidth + ' ' + this.iconHeight;
button.style.backgroundPosition = 'center';
button.style.width = this.buttonWidth;
button.style.height = this.buttonHeight;
}
button.setAttribute('data-col', item.title);
button.style.border = 'none';
button.style.cursor = 'pointer';
// If we have an object as item.items, it was never set by the user
if (item.title === 'Line Width' && !Array.isArray(item.items)) {
// Add defaults
item.items = [{
id: 'OT_line_width_2',
title: 'Line Width 2',
size: 2
}, {
id: 'OT_line_width_4',
title: 'Line Width 4',
size: 4
}, {
id: 'OT_line_width_6',
title: 'Line Width 6',
size: 6
}, {
id: 'OT_line_width_8',
title: 'Line Width 8',
size: 8
}, {
id: 'OT_line_width_10',
title: 'Line Width 10',
size: 10
}, {
id: 'OT_line_width_12',
title: 'Line Width 12',
size: 12
}, {
id: 'OT_line_width_14',
title: 'Line Width 14',
size: 14
}];
toolbarItems.push(button.outerHTML);
}
if (item.items) {
// Indicate that we have a group
button.setAttribute('data-type', 'group');
}
panel.innerHTML = toolbarItems.join('');
button.setAttribute('data-col', item.title);
button.style.border = 'none';
button.style.cursor = 'pointer';
panel.onclick = function (ev) {
var group = ev.target.getAttribute('data-type') === 'group';
var itemName = ev.target.getAttribute('data-col');
var id = ev.target.getAttribute('id');
toolbarItems.push(button.outerHTML);
}
panel.innerHTML = toolbarItems.join('');
panel.onclick = function (ev) {
var group = ev.target.getAttribute('data-type') === 'group';
var itemName = ev.target.getAttribute('data-col');
var id = ev.target.getAttribute('id');
// Close the submenu if we are clicking on an item and not a group button
if (!group) {
self.items.forEach(function (item) {
if (item.title !== 'Clear' && item.title === itemName) {
if (self.selectedItem) {
var lastBtn = context.getElementById(self.selectedItem.id);
if (lastBtn) {
lastBtn.style.background = 'url("' + self.selectedItem.icon + '") no-repeat';
lastBtn.style.backgroundSize = self.iconWidth + ' ' + self.iconHeight;
lastBtn.style.backgroundPosition = 'center';
// Close the submenu if we are clicking on an item and not a group button
if (!group) {
self.items.forEach(function (item) {
if (item.title !== 'Clear' && item.title === itemName) {
if (self.selectedItem) {
var lastBtn = context.getElementById(self.selectedItem.id);
if (lastBtn) {
lastBtn.style.background = 'url("' + self.selectedItem.icon + '") no-repeat';
lastBtn.style.backgroundSize = self.iconWidth + ' ' + self.iconHeight;
lastBtn.style.backgroundPosition = 'center';
}
}
}
if (item.selectedIcon) {
var selBtn = context.getElementById(item.id);
if (selBtn) {
selBtn.style.background = 'url("' + item.selectedIcon + '") no-repeat';
selBtn.style.backgroundSize = self.iconWidth + ' ' + self.iconHeight;
selBtn.style.backgroundPosition = 'center';
if (item.selectedIcon) {
var selBtn = context.getElementById(item.id);
if (selBtn) {
selBtn.style.background = 'url("' + item.selectedIcon + '") no-repeat';
selBtn.style.backgroundSize = self.iconWidth + ' ' + self.iconHeight;
selBtn.style.backgroundPosition = 'center';
}
}
}
self.selectedItem = item;
self.selectedItem = item;
attachDefaultAction(item);
attachDefaultAction(item);
canvases.forEach(function (canvas) {
canvas.selectItem(self.selectedItem);
});
canvases.forEach(function (canvas) {
canvas.selectItem(self.selectedItem);
});
return false;
}
});
subPanel.style.display = 'none';
} else {
self.items.forEach(function (item) {
if (item.title === itemName) {
self.selectedGroup = item;
return false;
}
});
subPanel.style.display = 'none';
} else {
self.items.forEach(function (item) {
if (item.title === itemName) {
self.selectedGroup = item;
if (item.items) {
subPanel.setAttribute('class', 'OT_subpanel');
subPanel.style.backgroundColor = self.backgroundColor;
subPanel.style.width = '100%';
subPanel.style.height = '100%';
subPanel.style.paddingLeft = '15px';
subPanel.style.display = 'none';
self.parent.appendChild(subPanel);
if (item.items) {
subPanel.setAttribute('class', 'OT_subpanel');
subPanel.style.backgroundColor = self.backgroundColor;
subPanel.style.width = '100%';
subPanel.style.height = '100%';
subPanel.style.paddingLeft = '15px';
subPanel.style.display = 'none';
self.parent.appendChild(subPanel);
if (Array.isArray(item.items)) {
var submenuItems = [];
if (Array.isArray(item.items)) {
var submenuItems = [];
if (item.id === 'OT_line_width') {
// We want to dynamically create icons for the list of possible line widths
item.items.forEach(function (subItem) {
// INFO Using a div here - not input to create an inner div representing the line width - better option?
var itemButton = context.createElement('div');
itemButton.setAttribute('data-col', subItem.title);
itemButton.setAttribute('id', subItem.id);
itemButton.style.position = 'relative';
itemButton.style.top = '50%';
itemButton.style.transform = 'translateY(-50%)';
itemButton.style['float'] = 'left';
itemButton.style.width = self.buttonWidth;
itemButton.style.height = self.buttonHeight;
itemButton.style.border = 'none';
itemButton.style.cursor = 'pointer';
if (item.id === 'OT_line_width') {
// We want to dynamically create icons for the list of possible line widths
item.items.forEach(function (subItem) {
// INFO Using a div here - not input to create an inner div representing the line width - better option?
var itemButton = context.createElement('div');
itemButton.setAttribute('data-col', subItem.title);
itemButton.setAttribute('id', subItem.id);
itemButton.style.position = 'relative';
itemButton.style.top = '50%';
itemButton.style.transform = 'translateY(-50%)';
itemButton.style['float'] = 'left';
itemButton.style.width = self.buttonWidth;
itemButton.style.height = self.buttonHeight;
itemButton.style.border = 'none';
itemButton.style.cursor = 'pointer';
var lineIcon = context.createElement('div');
// TODO Allow devs to change this?
lineIcon.style.backgroundColor = '#FFFFFF';
lineIcon.style.width = '80%';
lineIcon.style.height = subItem.size + 'px';
lineIcon.style.position = 'relative';
lineIcon.style.left = '50%';
lineIcon.style.top = '50%';
lineIcon.style.transform = 'translateX(-50%) translateY(-50%)';
// Prevents div icon from catching events so they can be passed to the parent
lineIcon.style.pointerEvents = 'none';
var lineIcon = context.createElement('div');
// TODO Allow devs to change this?
lineIcon.style.backgroundColor = '#FFFFFF';
lineIcon.style.width = '80%';
lineIcon.style.height = subItem.size + 'px';
lineIcon.style.position = 'relative';
lineIcon.style.left = '50%';
lineIcon.style.top = '50%';
lineIcon.style.transform = 'translateX(-50%) translateY(-50%)';
// Prevents div icon from catching events so they can be passed to the parent
lineIcon.style.pointerEvents = 'none';
itemButton.appendChild(lineIcon);
itemButton.appendChild(lineIcon);
submenuItems.push(itemButton.outerHTML);
});
} else {
item.items.forEach(function (subItem) {
var itemButton = context.createElement('input');
itemButton.setAttribute('type', 'button');
itemButton.setAttribute('data-col', subItem.title);
itemButton.setAttribute('id', subItem.id);
itemButton.style.background = 'url("' + subItem.icon + '") no-repeat';
itemButton.style.position = 'relative';
itemButton.style.top = '50%';
itemButton.style.transform = 'translateY(-50%)';
itemButton.style.backgroundSize = self.iconWidth + ' ' + self.iconHeight;
itemButton.style.backgroundPosition = 'center';
itemButton.style.width = self.buttonWidth;
itemButton.style.height = self.buttonHeight;
itemButton.style.border = 'none';
itemButton.style.cursor = 'pointer';
submenuItems.push(itemButton.outerHTML);
});
} else {
item.items.forEach(function (subItem) {
var itemButton = context.createElement('input');
itemButton.setAttribute('type', 'button');
itemButton.setAttribute('data-col', subItem.title);
itemButton.setAttribute('id', subItem.id);
itemButton.style.background = 'url("' + subItem.icon + '") no-repeat';
itemButton.style.position = 'relative';
itemButton.style.top = '50%';
itemButton.style.transform = 'translateY(-50%)';
itemButton.style.backgroundSize = self.iconWidth + ' ' + self.iconHeight;
itemButton.style.backgroundPosition = 'center';
itemButton.style.width = self.buttonWidth;
itemButton.style.height = self.buttonHeight;
itemButton.style.border = 'none';
itemButton.style.cursor = 'pointer';
submenuItems.push(itemButton.outerHTML);
});
submenuItems.push(itemButton.outerHTML);
});
}
subPanel.innerHTML = submenuItems.join('');
}
}
subPanel.innerHTML = submenuItems.join('');
if (id === 'OT_shapes' || id === 'OT_line_width') {
if (subPanel) {
subPanel.style.display = 'block';
}
pk.close();
} else if (id === 'OT_colors') {
if (subPanel) {
subPanel.style.display = 'none';
}
pk.open();
}
}
});
}
if (id === 'OT_shapes' || id === 'OT_line_width') {
if (subPanel) {
subPanel.style.display = 'block';
}
pk.close();
} else if (id === 'OT_colors') {
if (subPanel) {
subPanel.style.display = 'none';
}
pk.open();
}
}
self.cbs.forEach(function (cb) {
cb.call(self, id);
});
}
};
self.cbs.forEach(function (cb) {
cb.call(self, id);
});
};
subPanel.onclick = function (ev) {
var group = ev.target.getAttribute('data-type') === 'group';
var itemName = ev.target.getAttribute('data-col');
var id = ev.target.getAttribute('id');
subPanel.style.display = 'none';
subPanel.onclick = function (ev) {
var group = ev.target.getAttribute('data-type') === 'group';
var itemName = ev.target.getAttribute('data-col');
var id = ev.target.getAttribute('id');
subPanel.style.display = 'none';
if (!group) {
self.selectedGroup.items.forEach(function (item) {
if (item.id !== 'OT_clear' && item.id === id) {
if (self.selectedItem) {
var lastBtn = document.getElementById(self.selectedItem.id);
if (lastBtn) {
lastBtn.style.background = 'url("' + self.selectedItem.icon + '") no-repeat';
lastBtn.style.backgroundSize = self.iconWidth + ' ' + self.iconHeight;
lastBtn.style.backgroundPosition = 'center';
}
}
if (!group) {
self.selectedGroup.items.forEach(function (item) {
if (item.id !== 'OT_clear' && item.id === id) {
if (self.selectedItem) {
var lastBtn = document.getElementById(self.selectedItem.id);
if (lastBtn) {
lastBtn.style.background = 'url("' + self.selectedItem.icon + '") no-repeat';
lastBtn.style.backgroundSize = self.iconWidth + ' ' + self.iconHeight;
lastBtn.style.backgroundPosition = 'center';
if (item.selectedIcon) {
var selBtn = document.getElementById(item.id);
if (lastBtn) {
selBtn.style.background = 'url("' + item.selectedIcon + '") no-repeat';
selBtn.style.backgroundSize = self.iconWidth + ' ' + self.iconHeight;
selBtn.style.backgroundPosition = 'center';
}
}
}
if (item.selectedIcon) {
var selBtn = document.getElementById(item.id);
if (lastBtn) {
selBtn.style.background = 'url("' + item.selectedIcon + '") no-repeat';
selBtn.style.backgroundSize = self.iconWidth + ' ' + self.iconHeight;
selBtn.style.backgroundPosition = 'center';
}
self.selectedItem = item;
attachDefaultAction(item);
canvases.forEach(function (canvas) {
canvas.selectItem(self.selectedItem);
});
return false;
}
});
}
self.selectedItem = item;
self.cbs.forEach(function (cb) {
cb.call(self, id);
});
};
attachDefaultAction(item);
context.getElementById('OT_clear').onclick = function () {
canvases.forEach(function (canvas) {
canvas.clear();
});
};
}
};
canvases.forEach(function (canvas) {
canvas.selectItem(self.selectedItem);
});
!this.externalWindow && this.createPanel();
return false;
}
});
var attachDefaultAction = function (item) {
if (!item.points) {
// Attach default actions
if (item.id === 'OT_line') {
self.selectedItem.points = [
[0, 0],
[0, 1]
];
} else if (item.id === 'OT_arrow') {
self.selectedItem.points = [
[0, 1],
[3, 1],
[3, 0],
[5, 2],
[3, 4],
[3, 3],
[0, 3],
[0, 1] // Reconnect point
];
} else if (item.id === 'OT_rect') {
self.selectedItem.points = [
[0, 0],
[1, 0],
[1, 1],
[0, 1],
[0, 0] // Reconnect point
];
} else if (item.id === 'OT_oval') {
self.selectedItem.enableSmoothing = true;
self.selectedItem.points = [
[0, 0.5],
[0.5 + 0.5 * Math.cos(5 * Math.PI / 4), 0.5 + 0.5 * Math.sin(5 * Math.PI / 4)],
[0.5, 0],
[0.5 + 0.5 * Math.cos(7 * Math.PI / 4), 0.5 + 0.5 * Math.sin(7 * Math.PI / 4)],
[1, 0.5],
[0.5 + 0.5 * Math.cos(Math.PI / 4), 0.5 + 0.5 * Math.sin(Math.PI / 4)],
[0.5, 1],
[0.5 + 0.5 * Math.cos(3 * Math.PI / 4), 0.5 + 0.5 * Math.sin(3 * Math.PI / 4)],
[0, 0.5],
[0.5 + 0.5 * Math.cos(5 * Math.PI / 4), 0.5 + 0.5 * Math.sin(5 * Math.PI / 4)]
];
}
}
};
self.cbs.forEach(function (cb) {
cb.call(self, id);
});
};
/**
* Callback function for toolbar menu item click events.
* @param cb The callback function used to handle the click event.
*/
this.itemClicked = function (cb) {
this.cbs.push(cb);
};
context.getElementById('OT_clear').onclick = function () {
canvases.forEach(function (canvas) {
canvas.clear();
});
};
}
};
/**
* Links an annotation canvas to the toolbar so that menu actions can be handled on it.
* @param canvas The annotation canvas to be linked to the toolbar.
*/
this.addCanvas = function (canvas) {
var self = this;
canvas.link(self.session);
canvas.colors(self.colors);
canvases.push(canvas);
};
!this.externalWindow && this.createPanel();
/**
* Removes the annotation canvas with the specified connectionId from its parent container and
* unlinks it from the toolbar.
* @param connectionId The stream's connection ID for the video feed whose canvas should be removed.
*/
this.removeCanvas = function (connectionId) {
canvases.forEach(function (annotationView) {
var canvas = annotationView.canvas();
if (annotationView.videoFeed.stream.connection.connectionId === connectionId) {
if (canvas.parentNode) {
canvas.parentNode.removeChild(canvas);
}
}
});
var attachDefaultAction = function (item) {
if (!item.points) {
// Attach default actions
if (item.id === 'OT_line') {
self.selectedItem.points = [
[0, 0],
[0, 1]
];
} else if (item.id === 'OT_arrow') {
self.selectedItem.points = [
[0, 1],
[3, 1],
[3, 0],
[5, 2],
[3, 4],
[3, 3],
[0, 3],
[0, 1] // Reconnect point
];
} else if (item.id === 'OT_rect') {
self.selectedItem.points = [
[0, 0],
[1, 0],
[1, 1],
[0, 1],
[0, 0] // Reconnect point
];
} else if (item.id === 'OT_oval') {
self.selectedItem.enableSmoothing = true;
self.selectedItem.points = [
[0, 0.5],
[0.5 + 0.5 * Math.cos(5 * Math.PI / 4), 0.5 + 0.5 * Math.sin(5 * Math.PI / 4)],
[0.5, 0],
[0.5 + 0.5 * Math.cos(7 * Math.PI / 4), 0.5 + 0.5 * Math.sin(7 * Math.PI / 4)],
[1, 0.5],
[0.5 + 0.5 * Math.cos(Math.PI / 4), 0.5 + 0.5 * Math.sin(Math.PI / 4)],
[0.5, 1],
[0.5 + 0.5 * Math.cos(3 * Math.PI / 4), 0.5 + 0.5 * Math.sin(3 * Math.PI / 4)],
[0, 0.5],
[0.5 + 0.5 * Math.cos(5 * Math.PI / 4), 0.5 + 0.5 * Math.sin(5 * Math.PI / 4)]
];
}
}
};
canvases = canvases.filter(function (annotationView) {
return annotationView.videoFeed.stream.connection.connectionId !== connectionId;
});
};
/**
* Callback function for toolbar menu item click events.
* @param cb The callback function used to handle the click event.
*/
this.itemClicked = function (cb) {
this.cbs.push(cb);
};
/**
* Removes the toolbar and all associated annotation canvases from their parent containers.
*/
this.remove = function () {
/**
* Links an annotation canvas to the toolbar so that menu actions can be handled on it.
* @param canvas The annotation canvas to be linked to the toolbar.
*/
this.addCanvas = function (canvas) {
var self = this;
canvas.link(self.session);
canvas.colors(self.colors);
canvases.push(canvas);
};
try {
panel.parentNode.removeChild(panel);
} catch (e) {
console.log(e);
}
/**
* Removes the annotation canvas with the specified connectionId from its parent container and
* unlinks it from the toolbar.
* @param connectionId The stream's connection ID for the video feed whose canvas should be removed.
*/
this.removeCanvas = function (connectionId) {
canvases.forEach(function (annotationView) {
var canvas = annotationView.canvas();
if (annotationView.videoFeed.stream.connection.connectionId === connectionId) {
canvases.forEach(function (annotationView) {
var canvas = annotationView.canvas();
if (canvas.parentNode) {
canvas.parentNode.removeChild(canvas);
}
}
});
});
canvases = canvases.filter(function (annotationView) {
return annotationView.videoFeed.stream.connection.connectionId !== connectionId;
});
canvases = [];
};
};
/**
* Removes the toolbar and all associated annotation canvases from their parent containers.
*/
this.remove = function () {
try {
panel.parentNode.removeChild(panel);
} catch (e) {
console.log(e);
}
canvases.forEach(function (annotationView) {
var canvas = annotationView.canvas();
if (canvas.parentNode) {
canvas.parentNode.removeChild(canvas);
}
});
canvases = [];
};
};
}.call(this));

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc