D3 positioning using force diagram

Used for Meet the Team

by Ben Clayton

HTML

<script src="//d3js.org/d3.v3.min.js"></script>
<!-- D3 animation library used to provide force diagram -->
<h1>Meet The Team</h1>
<div id="mtt"></div>

CSS

#mtt {
		height:1000px;
		padding:100px;
		position:relative;
	}

	#mtt .wrapper {
		height:400px;
		width:350px;
	}

	#mtt .wrapper .person {
		height:350px;
		width:350px;
		background-repeat: no-repeat;
	}

	#mtt .wrapper .person.shake {
		animation: shake 0.4s cubic-bezier(.36,.07,.19,.97) both;
		transform: translate3d(0, 0, 0);
		backface-visibility: hidden;
		perspective: 1000px;
	}

	@keyframes shake {
		10%, 90% {
			transform: translate3d(-2px, 0, 0);
		}

		20%, 80% {
			transform: translate3d(4px, 0, 0);
		}

		30%, 50%, 70% {
			transform: translate3d(-8px, 0, 0);
		}

		40%, 60% {
			transform: translate3d(8px, 0, 0);
		}
	}

	#mtt .wrapper .title  {
		position:relative;
		left:200px;
		opacity: 0;
	}

	/* CSS not required, was used to style the boxes draw by D3 animation code
	.link {
		stroke: #2E2E2E;
		stroke-width: 2px;
	}

	.node {
		stroke: #fff;
		stroke-width: 2px;
	}

	.textClass {
		stroke: #323232;
		font-family: "Lucida Grande", "Droid Sans", Arial, Helvetica, sans-serif;
		font-weight: normal;
		stroke-width: .5;
		font-size: 14px;
	}

	.box {
		width : 350px;
		height : 350px;
		position: absolute;
		border: 1px solid red;
		z-index: 10;
	}
	*/

JavaScript

//=============================================================================================================
//=============================================================================================================

class teamPerson {
	constructor( qty, url, id, person ) {
		this.qty = qty; // quantity of people within the single sprite image
		this.spriteURL = url;// url of sprite
		this.id = id;// offset in sprite of particular person
		this.person = person;// person's data, like 'title' and 'name'

		// constants
		this.width = 350;
		this.height = 350;
		this.changePictureTime = 2000;
		this.timeStartDelay = 6000;// use to delay randomely between 0 and this value before first shake
		this.timePicChangeInShake = 200;// delay after shake starts to picture change
		this.timeShakeClass = 600;// time allowed for shake to occur (change css manually also)
		this.timeTitleFlyIn = 1000;// animation time for text to fly in
		this.timeTitleFlyOut = 300;// animation time for text to fly out


		this.$person = null;
		this.$wrapper = null;
		this.$title = null;
		this.frame = 0;// horizontal offset to choose a particular frame for a person from sprite
		this.x = 0;
		this.y = 0;
	}

	interface(){
		// static html
		this.$person = $( "<div></div>" );
		this.$person.css( "background-image","url(" + this.spriteURL + ")" );

		this.$person.css( "background-size","300% " + ( this.qty * 100 ) + "%" ); // 300% 300% ; scale so one person of sprite to fit the 350x350 window */

		this.setFrame(0);
		this.$person.addClass( "person" );
		this.$wrapper = $( "<div></div>" );
		this.$wrapper.addClass( "wrapper" );
		this.$wrapper.css( "position", "absolute" );
		this.$wrapper.append( this.$person );

		this.$title = $( "<div><h3>" + this.person.title + "</h3></div>" );
		this.$title.addClass( "title" );
		this.$wrapper.append( this.$title );

		// mouse event handlers
		this.$wrapper.on( "mouseover", function(){
			this.showTitle()
		}.bind( this ));
		this.$wrapper.on(...