Packet Tracer

by David Joseph Guzsik

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/interact.js/1.2.6/interact.min.js"></script>
<script src="https://npmcdn.com/[email protected]/dist/draggabilly.pkgd.js"></script>
<canvas id="lines"></canvas>
<ul id="devices">
  <li class="device" style="top:34px;left:66px" id="Router0">
    <img src="https://upload.wikimedia.org/wikipedia/commons/5/5c/Router.svg">
    <div class="meta">
      <span class="name">1841</span>
      <span class="name">Router0</span>
    </div>
  </li>
  <li class="device" style="top:34px;left:200px" id="Router1">
    <img src="https://upload.wikimedia.org/wikipedia/commons/5/5c/Router.svg">
    <div class="meta">
      <span class="name">1841</span>
      <span class="name">Router1</span>
    </div>
  </li>
  <li class="device" style="top:100px;left:50px" id="Switch0">
    <img src="http://www.clker.com/cliparts/b/0/c/c/1343841796926375646Switch%20Final.svg">
    <div class="meta">
      <span class="name">2950-24</span>
      <span class="name">Switch0</span>
    </div>
  </li>
  <li class="device" style="top:180px;left:80px" id="PC0">
    <img src="http://www.clker.com/cliparts/A/A/2/P/j/7/computer-pc.svg">
    <div class="meta">
      <span class="name">PC</span>
      <span class="name">PC0</span>
    </div>
  </li>
</ul>

CSS

html, body {
  margin: 0;
  overflow: hidden;
  height: 100%;
  width: 100%;
}
#lines, #devices {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  user-select: none;
}
#lines { background: #fff }
#devices {
  list-style: none;
  margin: 0;
  padding: 0;
  opacity: 1;
}
#devices img {
  width: 50px;
  height: 34px;
}
#devices > .device {
  position: relative;
  display: inline-block;
  text-align: center;
}
#devices > .device.selected img,
#devices > .device:active img {
  filter: brightness(150%);
}
#devices > .device > .meta {
  position: absolute;
  top: 34px;
  left: 0;
  width: 100%;
  cursor: default;
  pointer-events: none;
}
#devices > .device > .meta > * {
  display: block;
  white-space: nowrap;
  line-hieght: 1em;
  font-size: 8pt;
  font-family: verdana;
  text-shadow:
    0 0 1px white,
    0 0 2px white,
    0 0 3px white,
    0 0 4px white,
    0 0 5px white,
    0 0 6px white,
    0 0 7px white,
    0 0 10px white;
}

JavaScript

$.fn.getCenter = function(){
  var $this = $(this),
  		offset = $this.offset(),
      width = $this.width(),
      height = $this.height();

	return {
  	x: offset.left + width / 2,
  	y: offset.top + height / 2,
  };
}
function circle(ctx, centerX, centerY, radius, fill){
  ctx.beginPath();
  ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
  ctx.fillStyle = fill;
  ctx.fill();
  ctx.closePath();
}
function calcDists(el1c, el2c, rev){
  var distX = el2c.x - el1c.x,
      distY = el2c.y - el1c.y,
      distance = Math.sqrt(Math.pow(distX, 2)+Math.pow(distY, 2));
  distX /= distance;
  distY /= distance;
  return {
  	distX: distX,
    distY: distY,
    mag: distance,
  }
}
// http://stackoverflow.com/a/9947720/1344955
var curveOffest = 0.3;
$(function(){
  $('.device').draggabilly({
    containment: '#devices',
    handle: 'img',
  }).on('dragStart',function(event,pointer){
  	$('.selected').removeClass('selected');
    $(this).addClass('selected');
  }).on('dragMove',function(){
  	redrawConnections();
  });
  $('#devices').on('mousedown','.device',function(e){
  	e.stopPropagation();
  	$('.selected').removeClass('selected');
    $(this).addClass('selected');
  });
  $('body').on('mousedown',function(){
  	$('.selected').removeClass('selected');
  });
  
  var ConnectionTypes = {
  	console: 0,
  	straightThrough: 1,
  	crossOver: 2,
  };
  
  var connections = [
      {
        type: ConnectionTypes.crossOver,
        devices: ['Router0','Router1'],
      },
      {
        type: ConnectionTypes.straightThrough,
        devices: ['Router0','Switch0'],
      },
      {
        type: ConnectionTypes.straightThrough,
        devices: ['PC0','Switch0'],
      },
      {
        type: ConnectionTypes.console,
        devices: ['PC0','Switch0'],
      },
    ],
    canvas = $('#lines').get(0),
    ctx = canvas.getContext("2d"),
    connDotDist = 35;
  function redrawConnections(){
  	ctx.canvas.width  = window.innerWidth;
  	ctx.canvas.height =...