opentok-annotation
Advanced tools
Comparing version 1.0.29 to 1.0.30
@@ -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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
338191
4008