1<!DOCTYPE html> 2<html itemscope itemtype="http://schema.org/WebPage"> 3<head> 4 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> 6 <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0, user-scalable=no"> 7 8 <title>Canvas Designer supporting Collaboration | HTML5, WebRTC</title> 9 <meta name="description" content="HTML5 Canvas Designer ® Muaz Khan â A tool aimed to give you a full-fledged drawing surface and also auto generate appropriate code for you in different formats! Generator/Tool/Editor â 2D API/Context"> 10</head> 11<body>
12<script src="canvas-designer-widget.js"></script>
12 13 14<style> 15* { 16 -webkit-user-select: none; 17 -moz-user-select: none; 18 -o-user-select: none; 19 -ms-user-select: none; 20 user-select: none; 21} 22input[type=text] { 23 -webkit-user-select: initial; 24 -moz-user-select: initial; 25 -o-user-select: initial; 26 -ms-user-select: initial; 27 user-select: initial; 28} 29 30button, input { 31 font-family: Myriad, Arial, Verdana; 32 font-weight: normal; 33 border-top-left-radius: 3px; 34 border-top-right-radius: 3px; 35 border-bottom-right-radius: 3px; 36 border-bottom-left-radius: 3px; 37 padding: 4px 12px; 38 text-decoration: none; 39 color: rgb(27, 26, 26); 40 display: inline-block; 41 box-shadow: rgb(255, 255, 255) 1px 1px 0px 0px inset; 42 text-shadow: none; 43 background: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0.05, rgb(241, 241, 241)), to(rgb(230, 230, 230))); 44 font-size: 20px; 45 border: 1px solid red; 46 outline:none; 47} 48button:hover, button:hover, input:focus { 49 background: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(5%, rgb(221, 221, 221)), to(rgb(250, 250, 250))); 50 border: 1px solid rgb(142, 142, 142); 51} 52button[disabled], input[disabled] { 53 background: rgb(249, 249, 249); 54 border: 1px solid rgb(218, 207, 207); 55 color: rgb(197, 189, 189); 56} 57 58input { 59 background: white; 60} 61 62.extra-controls { 63 position: fixed; 64 right: 21%; 65} 66 67#room-id { 68 width: 55%; 69 margin-right: 2px; 70} 71 72/* popup box */ 73.black_overlay { 74 display: none; 75 position: absolute; 76 top: 0%; 77 left: 0%; 78 width: 100%; 79 height: 100%; 80 background-color: black; 81 z-index:1001; 82 -moz-opacity: 0.8; 83 opacity:.80; 84 filter: alpha(opacity=80); 85} 86.white_content { 87 display: none; 88 position: absolute; 89 top: 30%; 90 left: 40%; 91 width: 16%; 92 height: 15%; 93 padding: 16px; 94 border: 10px solid rgb(9, 159, 243); 95 background-color: rgba(255, 255, 255, 0.94); 96 z-index:1002; 97 overflow: hidden; 98 border-radius: 5px; 99 min-width: 300px; 100 min-height: 120px; 101} 102 103.white_content hr {
104 border-top: 4px solid rgb(9, 159, 243); 105 margin: 9px -20px; 106} 107 108#btn-undo, #btn-close-undo-popup, #btn-close-dataURL-popup, #btn-close-comments-popup, #btn-getDataURL { 109 font-size: 1.2em; 110 padding: 2px 9px; 111} 112 113#btn-close-undo-popup, #btn-close-dataURL-popup, #btn-close-comments-popup { 114 padding: 0 6px; 115 border-radius: 50%; 116 padding-bottom: 1px; 117 color: red; 118} 119 120.white_content select { 121 font-size: 1.2em; 122 border: 1px solid; 123 padding: 0; 124 outline: none!important; 125 border: 1px solid black !important; 126 float: left; 127} 128.white_content select option { 129 padding: 2px 5px; 130 border-bottom: 1px solid black; 131} 132.white_content select option:last-child { 133 border-bottom: 0; 134} 135 136.white_content option:checked, .white_content option[selected] { 137 background-color: #06CDFF!important; 138 background:linear-gradient(#06CDFF, #06CDFF)!important; 139 color: white!important; 140} 141 142.white_content select[disabled] { 143 background-color: rgba(232, 229, 229, 0.17); 144 color: rgb(84, 82, 82); 145} 146 147div#comments-popup { 148 width: 100%; 149 left: 0; 150 top: 0; 151 height: 100%; 152 border: 0; 153 padding: 0; 154 border-radius: 0; 155 overflow: auto; 156} 157 158#btn-comments { 159 color: red; 160 margin-top: 5px; 161 font-size: 24px; 162 text-shadow: 1px 1px white; 163} 164 165#h2-close-popup { 166 background: yellow; 167 padding: 5px 10px; 168 border-bottom: 1px solid red; 169 margin: 0; 170 color: red; 171} 172</style> 173 174<div id="widget-container" style="position: fixed;bottom: 0;right: 20%;left: 20%;height: 100%;border: 1px solid black; border-top:0; border-bottom: 0;"></div> 175 176<div id="fade" class="black_overlay"></div> 177 178<div id="action-controls" style="width: 19%; padding: 1%;position: absolute;left:0;"> 179 <video controls autoplay playsinline style="width: 105%;margin-left: -15px;margin-top: -23px; display: none;"></video> 180 181 <div id="select-tools"> 182 <h2>Select Tools</h2> 183 <input type="checkbox" id="pencil" checked> 184 <label for="pencil">pencil</label><br> 185 186 <input type="checkbox" id="marker" checked> 187 <label for="marker">marker</label><br> 188 189 <input type="checkbox" id="eraser" checked> 190 <label for="eraser">eraser</label><br> 191 192 <input type="checkbox" id="text" checked> 193 <label for="text">text</label><br> 194 195 <input type="checkbox" id="image" checked> 196 <label for="image">image</label><br> 197 198 <input type="checkbox" id="pdf" checked> 199 <label for="pdf">pdf</label><br> 200 201 <input type="checkbox" id="line" checked> 202 <label for="line">line</label><br> 203 204 <input type="checkbox" id="arrow" checked> 205 <label for="arrow">arrow</label><br> 206 207 <input type="checkbox" id="zoom"> 208 <label for="zoom">zoom</label><br> 209 210 <input type="checkbox" id="dragSingle" checked> 211 <label for="dragSingle">dragSingle</label><br> 212 213 <input type="checkbox" id="dragMultiple" checked> 214 <label for="dragMultiple">dragMultiple</label><br> 215 216 <input type="checkbox" id="arc" checked> 217 <label for="arc">arc</label><br> 218 219 <input type="checkbox" id="rectangle" checked> 220 <label for="rectangle">rectangle</label><br> 221 222 <input type="checkbox" id="quadratic" checked> 223 <label for="quadratic">quadratic</label><br> 224 225 <input type="checkbox" id="bezier" checked> 226 <label for="bezier">bezier</label><br> 227 228 <input type="checkbox" id="undo" checked> 229 <label for="undo">undo</label><br> 230 231 <input type="checkbox" id="lineWidth" checked> 232 <label for="lineWidth">lineWidth</label><br> 233 234 <input type="checkbox" id="colorsPicker" checked> 235 <label for="colorsPicker">colorsPicker</label><br> 236 237 <input type="checkbox" id="extraOptions" checked> 238 <label for="extraOptions">extraOptions</label><br> 239 240 <input type="checkbox" id="code" checked> 241 <label for="code">code</label><br><br> 242 </div> 243 244 <hr> 245 <div> 246 Number of users connected with you: <b id="number-of-connected-users">0</b> 247 248 <br><br> 249 250 <div id="hide-on-datachannel-opened"> 251 You can open a private WebRTC room to sync dashboard with private users. 252 253 <br><br> 254 255 <input type="text" id="room-id" placeholder="room-id"> 256 <button id="open-room">Open</button> 257 </div> 258 </div> 259 260 <hr> 261 <h2>Shortcut Keys</h2> 262 ctrl+t (to display text-fonts box)<br> 263 ctrl+z (to undo last-single shape)<br>
264 ctrl+a (to select all shapes)<br> 265 ctrl+c (copy last-selected shape)<br> 266 ctrl+v (paste last-copied shape)<br><br> 267 ctrl+mousedown (to copy/paste all shapes) 268</div> 269 270<div class="extra-controls"> 271 <button id="export-as-image">Export as Image</button> 272 <button id="btn-display-undo-popup">Undo</button> 273</div> 274 275<div id="light" class="white_content"> 276 <button id="btn-close-undo-popup" style="float:right;">x</button> 277 278 <select id="undo-options" size="4"> 279 <option>Last Shape</option> 280 <option>All Shapes</option> 281 <option>Last Multiple</option> 282 <option disabled>Specific Range</option> 283 </select> 284 285 <div style="display: none;margin-top: 20px;margin-bottom: 20px;margin-right: 12px;float: right;"> 286 Digit/Number:<br> 287 <input type="text" id="number-of-shapes-to-undo" style="padding: 0;width: 90px;text-align: center;border-radius: 0;margin-top: 6px;"> 288 </div> 289 290 <br><br><br><br><br> 291 292 <button id="btn-undo" style="float:right;">Undo</button> 293</div> 294 295<div id="dataURL-popup" class="white_content"> 296 <button id="btn-close-dataURL-popup" style="float:right;">x</button> 297 298 <select id="data-url-format" size="4"> 299 <option>image/png</option> 300 <option>image/jpeg</option> 301 <option>image/gif</option> 302 <option>image/webp</option> 303 </select> 304 305 <a id="link-to-image" target="_blank" download="image.png"></a> 306 307 <br><br><br><br><br> 308 309 <button id="btn-getDataURL" style="float:right;">Get DataURL</button> 310</div> 311 312<div id="comments-popup" class="white_content"> 313 <button id="btn-close-comments-popup" style="float:right;">x</button> 314 315 <h2 id="h2-close-popup">Click right-side "x" button to close this popup.</h2> 316 <section class="experiment"> 317 <h2 class="header" id="feedback">Feedback</h2> 318 <div> 319 <textarea id="message" style="height: 8em; margin: .2em; width: 98%; border: 1px solid rgb(189, 189, 189); outline: none; resize: vertical;" placeholder="Have any message? Suggestions or something went wrong?"></textarea> 320 </div> 321 <button id="send-message" style="font-size: 1em;">Send Message</button><small style="margin-left:1em;">Enter your email too; if you want "direct" reply!</small> 322 </section> 323</div> 324 325<div style="position: fixed; right: 0; width: 19%; padding: 1%;top:0; text-align: center;"> 326 <h1>Canvas Designer!</h1> 327 <h2> 328 <a href="https://github.com/muaz-khan/Canvas-Designer">This tool is Open-Sourced!</a> 329 </h2> 330 331 Author: <a href="https://github.com/muaz-khan">Muaz Khan</a> 332 333 <hr> 334 <h2><a href="https://github.com/muaz-khan/Canvas-Designer#how-to-use">How to use in your own site?</a></h2> 335 336 <hr> 337 338 <h2><a href="https://muazkhan.com:9001/demos/dashboard/">WebRTC Dashboard</a></h2> 339 340 <br><br><br> 341 342 <div style="text-align:cener;margin-top:15px;"> 343 <p style="font-size:22px;color:red;">Ask Questions Here:</p> 344 <button id="btn-comments">Comments<br>Discussion</button> 345 </div> 346</div> 347
348<script> 349document.getElementById('room-id').onkeyup = document.getElementById('room-id').onblur = function() { 350 localStorage.setItem('canvas-designer-roomid', this.value); 351}; 352 353if (localStorage.getItem('canvas-designer-roomid')) { 354 document.getElementById('room-id').value = localStorage.getItem('canvas-designer-roomid'); 355} 356 357document.getElementById('open-room').onclick = function() { 358 var roomid = document.getElementById('room-id').value; 359 if (!roomid.length) return alert('Please enter roomid.'); 360 361 this.disabled = true; 362 363 connection.open(roomid, onOpenRoom); 364 365 this.parentNode.innerHTML = '<a href="#' + roomid + '" target="_blank">Please share this link</a>'; 366}; 367 368var designer = new CanvasDesigner(); 369 370// you can place widget.html anywhere 371designer.widgetHtmlURL = 'widget.html'; 372designer.widgetJsURL = 'widget.min.js' 373 374designer.addSyncListener(function(data) { 375 connection.send(data); 376}); 377 378designer.setSelected('pencil'); 379 380designer.setTools({ 381 pencil: true, 382 text: true, 383 image: true, 384 pdf: true, 385 eraser: true, 386 line: true, 387 arrow: true, 388 dragSingle: true, 389 dragMultiple: true, 390 arc: true, 391 rectangle: true, 392 quadratic: true, 393 bezier: true, 394 marker: true, 395 zoom: false, 396 lineWidth: true, 397 colorsPicker: true, 398 extraOptions: true, 399 code: true, 400 undo: true 401}); 402 403designer.appendTo(document.getElementById('widget-container')); 404 405Array.prototype.slice.call(document.getElementById('action-controls').querySelectorAll('input[type=checkbox]')).forEach(function(checkbox) { 406 checkbox.onchange = function() { 407 designer.destroy(); 408 409 designer.addSyncListener(function(data) { 410 connection.send(data); 411 }); 412 413 var tools = {}; 414 Array.prototype.slice.call(document.getElementById('action-controls').querySelectorAll('input[type=checkbox]')).forEach(function(checkbox2) { 415 if (checkbox2.checked) { 416 tools[checkbox2.id] = true; 417 } 418 }); 419 designer.setTools(tools); 420 designer.appendTo(document.getElementById('widget-container')); 421 }; 422}); 423 424var undoOptions = document.getElementById('undo-options'); 425 426document.getElementById('btn-display-undo-popup').onclick = function() { 427 document.getElementById('light').style.display = 'block'; 428 document.getElementById('fade').style.display = 'block'; 429}; 430 431var txtNumberOfShapesToUndo = document.getElementById('number-of-shapes-to-undo'); 432txtNumberOfShapesToUndo.onkeyup = function() { 433 localStorage.setItem('number-of-shapes-to-undo', txtNumberOfShapesToUndo.value); 434} 435 436if (localStorage.getItem('number-of-shapes-to-undo')) { 437 txtNumberOfShapesToUndo.value = localStorage.getItem('number-of-shapes-to-undo'); 438 txtNumberOfShapesToUndo.onkeyup(); 439} 440 441undoOptions.onchange = function() { 442 txtNumberOfShapesToUndo.parentNode.style.display = 'none'; 443 444 if (undoOptions.value === 'Specific Range') { 445 // 446 } else if (undoOptions.value === 'Last Multiple') { 447 txtNumberOfShapesToUndo.parentNode.style.display = 'block'; 448 } 449 450 localStorage.setItem('undo-options', undoOptions.value); 451}; 452 453undoOptions.onclick = undoOptions.onchange; 454 455if (localStorage.getItem('undo-options')) { 456 undoOptions.value = localStorage.getItem('undo-options'); 457 undoOptions.onchange(); 458} 459 460document.getElementById('btn-undo').onclick = function() { 461 if (undoOptions.value === 'All Shapes') { 462 designer.undo('all'); 463 } else if (undoOptions.value === 'Specific Range') { 464 designer.undo({ 465 specificRange: { 466 start: -1, 467 end: -1 468 } 469 }); 470 } else if (undoOptions.value === 'Last Shape') { 471 designer.undo(-1); 472 } else if (undoOptions.value === 'Last Multiple') { 473 var numberOfLastShapes = txtNumberOfShapesToUndo.value; 474 numberOfLastShapes = parseInt(numberOfLastShapes || 0) || 0; 475 designer.undo({ 476 numberOfLastShapes: numberOfLastShapes 477 }); 478 } 479 480 closeUndoPopup(); 481}; 482 483function closeUndoPopup() { 484 document.getElementById('light').style.display = 'none'; 485 document.getElementById('fade').style.display = 'none'; 486 487 undoOptions.onchange(); 488} 489document.getElementById('btn-close-undo-popup').onclick = closeUndoPopup; 490 491function closeDataURLPopup() { 492 document.getElementById('dataURL-popup').style.display = 'none'; 493 document.getElementById('fade').style.display = 'none'; 494 495 dataURLFormat.onchange(); 496} 497document.getElementById('btn-close-dataURL-popup').onclick = closeDataURLPopup; 498 499document.getElementById('export-as-image').onclick = function() { 500 linkToImage.innerHTML = linkToImage.href = linkToImage.style = ''; 501 502 document.getElementById('dataURL-popup').style.display = 'block'; 503 document.getElementById('fade').style.display = 'block'; 504 505 getDataURL(); 506}; 507 508function getDataURL(callback) { 509 callback = callback || function() {}; 510 var format = dataURLFormat.value; 511 designer.toDataURL(format || 'image/png', function(dataURL) { 512 linkToImage.style = 'margin-left: 10px;display: block;text-align: center;margin-bottom: -50px;'; 513 linkToImage.href = dataURL; 514 linkToImage.innerHTML = 'Click to Download Image'; 515 linkToImage.download = 'image.' + (format || 'image/png').split('/')[1]; 516 517 callback(dataURL, format); 518 }); 519} 520 521var dataURLFormat = document.getElementById('data-url-format'); 522var linkToImage = document.getElementById('link-to-image'); 523 524dataURLFormat.onchange = function() { 525 localStorage.setItem('data-url-format', dataURLFormat.value); 526 getDataURL(); 527}; 528dataURLFormat.onclick = dataURLFormat.onchange; 529 530if (localStorage.getItem('data-url-format')) { 531 dataURLFormat.value = localStorage.getItem('data-url-format'); 532 dataURLFormat.onchange(); 533} 534 535document.getElementById('btn-getDataURL').onclick = function() { 536 getDataURL(function(dataURL, format) { 537 window.open(dataURL); 538 }); 539 540 // closeDataURLPopup(); 541}; 542 543document.getElementById('btn-close-comments-popup').onclick = function() { 544 document.getElementById('comments-popup').style.display = 'none'; 545 document.getElementById('fade').style.display = 'none'; 546 547 dataURLFormat.onchange(); 548}; 549 550function showCommentsPopup(e) { 551 document.getElementById('comments-popup').style.display = 'block'; 552 document.getElementById('fade').style.display = 'block'; 553} 554document.getElementById('btn-comments').onclick = showCommentsPopup; 555if (location.hash.length && location.hash.indexOf('comment') !== -1) { 556 showCommentsPopup(); 557} 558</script>
558 559
560<script src="https://muazkhan.com:9001/dist/RTCMultiConnection.min.js"></script>
vendor: 1 bytes, line 560
560
561<script src="https://muazkhan.com:9001/socket.io/socket.io.js"></script>
561 562
563<script> 564var connection = new RTCMultiConnection(); 565 566connection.socketURL = 'https://muazkhan.com:9001/'; 567connection.socketMessageEvent = 'canvas-designer'; 568 569connection.enableFileSharing = false; 570connection.session = { 571 audio: true, 572 video: true, 573 data: true 574}; 575connection.sdpConstraints.mandatory = { 576 OfferToReceiveAudio: true, 577 OfferToReceiveVideo: true 578}; 579connection.dontCaptureUserMedia = true; 580if (location.hash.replace('#', '').length) { 581 var roomid = location.hash.replace('#', ''); 582 connection.join(roomid); 583} 584 585connection.onUserStatusChanged = function(event) { 586 var infoBar = document.getElementById('hide-on-datachannel-opened'); 587 if (event.status == 'online') { 588 infoBar.innerHTML = event.userid + ' is <b>online</b>.'; 589 } 590 591 if (event.status == 'offline') { 592 infoBar.innerHTML = event.userid + ' is <b>offline</b>.'; 593 } 594 595 numberOfConnectedUsers.innerHTML = connection.getAllParticipants().length; 596}; 597 598var numberOfConnectedUsers = document.getElementById('number-of-connected-users'); 599connection.onopen = function(event) { 600 var infoBar = document.getElementById('hide-on-datachannel-opened'); 601 infoBar.innerHTML = '<b>' + event.userid + '</b> is ready to collaborate with you.'; 602 603 if (designer.pointsLength <= 0) { 604 // make sure that remote user gets all drawings synced. 605 setTimeout(function() { 606 connection.send('plz-sync-points'); 607 }, 1000); 608 } 609 610 numberOfConnectedUsers.innerHTML = connection.getAllParticipants().length; 611 612 if(connection.isInitiator) { 613 setTimeout(function() { 614 designer.renderStream(); 615 }, 1000); 616 } 617}; 618 619connection.onclose = connection.onerror = connection.onleave = function() { 620 numberOfConnectedUsers.innerHTML = connection.getAllParticipants().length; 621}; 622 623connection.onmessage = function(event) { 624 if (event.data === 'plz-sync-points') { 625 designer.sync(); 626 return; 627 } 628 629 designer.syncData(event.data); 630}; 631</script>
631 632
633<script src="dev/webrtc-handler.js"></script>
vendor: 1 bytes, line 633
633
634<script> 635function onOpenRoom() { 636 // capture canvas-2d stream 637 // and share in realtime using RTCPeerConnection.addStream 638 // requires: dev/webrtc-handler.js 639 designer.captureStream(function(stream) { 640 connection.attachStreams = [stream]; 641 connection.onstream({ 642 stream: stream 643 }); 644 }); 645} 646 647var video = document.querySelector('video'); 648 649connection.onstream = function(event) { 650 if (connection.isInitiator && event.mediaElement) return; 651 652 video.style.display = ''; 653 video.srcObject = event.stream; 654 655 document.getElementById('select-tools').style.display = 'none'; 656}; 657 658connection.onstreamended = function() { 659 video.src = null; 660 video.style.display = 'none'; 661}; 662 663connection.iceServers = []; 664connection.iceServers.push({ 665 urls: 'stun:muazkhan.com:3478', 666 credential: 'muazkh', 667 username: 'hkzaum' 668}); 669connection.iceServers.push({ 670 urls: 'turns:muazkhan.com:5349', 671 credential: 'muazkh', 672 username: 'hkzaum' 673}); 674connection.iceServers.push({ 675 urls: 'turn:muazkhan.com:3478', 676 credential: 'muazkh', 677 username: 'hkzaum' 678}); 679</script>
679 680
681<script src="https://www.webrtc-experiment.com/common.js" async></script>
681 682
683<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-5443396847776866" 684 crossorigin="anonymous"></script>
684 685</body> 686</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.