Created
March 23, 2013 12:48
-
-
Save shadabahmed/5227612 to your computer and use it in GitHub Desktop.
A CodePen by Shadab Ahmed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="rumor"> | |
<div class="dropdown"> | |
<label>Algorithm:</label> | |
<select id="algo"> | |
</select> | |
| |
<label>Number of People:</label> | |
<input id="count" type="text" value="60" name="count"/> | |
<label>Speed:</label> | |
<select name="speed" id="speed"> | |
<option value="10">Slow</option> | |
<option value="5">Medium</option> | |
<option value="1">Fast</option> | |
</select> | |
<input id="start" type="button" value="Start"/> | |
</div> | |
<div class="total"> | |
Total Messages : <span id="msg_count">0</span><span class="message"></span> | |
</div> | |
<div class="cells"> | |
</div> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Arrow | |
@draw = (ele1, ele2)-> | |
pt1 = getCenter(ele1) | |
pt2 = getCenter(ele2) | |
distance = getDistance(pt1, pt2) | |
$arrow = $('<div class=\"arrow\"></div>') | |
$('body').append($arrow) | |
$arrow.css({left: pt1[0], top: pt1[1],width: Math.floor(distance)}) | |
rotation_trans = "rotate(#{Math.ceil(getSlope(pt1, pt2))}deg)" | |
$arrow.css('-webkit-transform', rotation_trans) | |
$arrow.css('-moz-transform', rotation_trans) | |
$arrow.css('transform', rotation_trans) | |
@delete = ($arrow)-> | |
$arrow.remove() | |
getCenter = (ele)-> | |
offset = ele.offset() | |
[offset.left + ele.width()/2, offset.top + ele.height()/2] | |
getSlope = (pt1, pt2)-> | |
console.log [pt1[1]-pt2[1], pt2[0] - pt1[0]] | |
r = Math.atan2(pt2[1]-pt1[1], pt2[0] - pt1[0]) | |
r *180 / Math.PI | |
getDistance = (pt1, pt2)-> | |
Math.sqrt(Math.pow(pt1[0] - pt2[0],2) + Math.pow(pt1[1] - pt2[1],2)) | |
class Grid | |
ele = undefined | |
[max_width, cell_count, cell_size] = [0, 0, 70] | |
[rows, cols, cell_count] = [0, 0, 0] | |
connections = {} | |
@init = (selector, n)-> | |
[ele, cell_count] = [$(selector), n] | |
max_width = ele.width() | |
ele.addClass('grid') | |
calculateRowsCols() | |
addCells() | |
@connectCells = (cell1, cell2)-> | |
[$cell1, $cell2] = [getCell(cell1), getCell(cell2)] | |
$cell1.addClass 'outgoing' | |
$cell2.addClass 'incoming' | |
connections["#{cell1}-#{cell2}"] = Arrow.draw($cell1, $cell2) | |
@disconnectCells = (cell1, cell2)-> | |
[$cell1, $cell2] = [getCell(cell1), getCell(cell2)] | |
$cell1.removeClass 'outgoing' | |
$cell2.removeClass 'incoming' | |
Arrow.delete(connections["#{cell1}-#{cell2}"]) | |
@clear = -> | |
ele.find('.incoming').removeClass('incoming') | |
ele.find('.outgoing').removeClass('outgoing') | |
for own key, id of connections | |
Arrow.delete(id) | |
@setCellText = (cellNo, text)-> | |
getCell(cellNo).find('span.rumor-cnt').text(text) | |
addCells = ()-> | |
tags = "<table><tbody>" | |
for x in [1..rows] | |
tags += "<tr>" | |
for y in [1..cols] | |
cellNo = (x - 1)*cols + y | |
break if cellNo > cell_count | |
tags += "<td><div class=\"container\">\ | |
<span class=\"top left\">#{cellNo}</span>\ | |
<span class=\"bottom right rumor-cnt\"></span>\ | |
</div></td>" | |
tags += "</tbody></table>" | |
ele.html(tags) | |
calculateRowsCols = ()-> | |
cols = Math.floor(max_width / cell_size) | |
rows = Math.ceil(cell_count / cols) | |
getCell = (cellNo)-> | |
cellRow = Math.ceil(cellNo / cols) | |
cellCol = (cellNo % cols) | |
cellCol = cols if cellCol == 0 | |
$cell = ele.find("table tr:nth-child(#{cellRow}) td:nth-child(#{cellCol})") | |
class Rumor | |
state = {} | |
total_messages = 0 | |
timeout = undefined | |
@delay = 50 | |
init = (n)-> | |
clearTimeout(timeout) | |
Grid.init('.cells', n) | |
Grid.clear() | |
for i in [1..n] | |
Grid.setCellText(i,1) | |
state[i] = 1 | |
@start = (algo, n)-> | |
init(n) | |
total_messages = 0 | |
algoCaller = -> | |
return if rumorSpread(state,n) | |
Grid.clear() | |
next_messages = algo(state, n) | |
$('.message').text("Person #{next_messages[0][0]} sends #{next_messages.length} message(s)") if next_messages[0] && next_messages[0][0] | |
for [sender, receiver, message_cnt] in next_messages | |
Grid.connectCells(sender, receiver) | |
Grid.setCellText(receiver, state[receiver] + message_cnt) | |
state[receiver] += message_cnt | |
total_messages += 1 | |
timeout = setTimeout(algoCaller, Rumor.delay) | |
$("#msg_count").text(total_messages) | |
setTimeout(algoCaller, Rumor.delay) | |
rumorSpread = (state, n)-> | |
spread = true | |
for own num, rumor_cnt of state | |
if rumor_cnt < n | |
spread = false | |
break | |
spread | |
algos = {} | |
algos[1] = | |
name: "All rumors in one message" | |
func: (state, n)-> | |
this.max = 1 if !this.max || this.max > n | |
this.max_num = 1 if !this.max_num || this.max_num > n | |
messages = [] | |
if max_num == n | |
for i in [1..n] | |
continue if i == max_num | |
messages.push [max_num, i, max - state[i]] | |
else | |
messages.push [max_num, max_num + 1, max] | |
this.max += 1 | |
this.max_num += 1 | |
messages | |
algos[2] = | |
name: "Only one rumor in one message" | |
func: (state, n)-> | |
messages = [] | |
this.itr = 1 if !this.itr || this.itr > n | |
for i in [1..n] | |
continue if i == this.itr | |
messages.push [this.itr, i, 1] | |
this.itr += 1 | |
messages | |
$(-> | |
for own index,algo of algos | |
$("#algo").append("<option value=\"#{index}\">#{algo.name}</option>") | |
$('#speed').change(-> | |
Rumor.delay = parseInt($(this).val()) * 50 | |
) | |
$('#start').click(-> | |
$("#msg_count").text(0) | |
Rumor.delay = parseInt($('#speed').val()) * 50 | |
Rumor.start(algos[$("#algo").val()].func, parseInt($("#count").val())) | |
) | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@import "compass"; | |
.arrow{ | |
position: absolute; | |
z-index: 9999; | |
border-top: 1px solid black; | |
background-color: black; | |
width: 100px; | |
@include apply-origin(0,0); | |
@include translate3d(0,0,0); | |
@include border-radius(4px); | |
@include box-shadow(#EEE 0 0 10px 5px); | |
opacity: 0.4; | |
&:after{ | |
content: "►"; | |
position: absolute; | |
right: -5px; | |
color: #000000; | |
font-size: 10px; | |
top: -6px | |
} | |
} | |
.rumor{ | |
font-family: "Helvetica"; | |
.total{ | |
padding: 10px; | |
#msg_count{ | |
color: grey; | |
font-weight: bold; | |
} | |
.message{ | |
padding: 0 50px; | |
} | |
} | |
} | |
.dropdown { | |
padding: 10px; | |
} | |
.grid table{ | |
border-collapse:collapse; | |
tr{ | |
position: normal; | |
} | |
tr td{ | |
width: 60px; | |
height: 60px; | |
border: 1px solid grey; | |
font-size: 10px; | |
background: url( data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAA3UlEQVR4Xu3asQ2DMBAF0LMIBVVGSEvPAs4GjMBoGSEjmAWoaRkhtaV/ucJSWqL4ohD9L53c3uOusUxQVdmTYRjOdtytovglWY3Lsjz29nWSnTFoad41sXykq1V1wKt5f4R4AORnQgABBBAQHQDpa4B1XefagL7vj71CquoLAOAKAMAJEEAAAQQQQAABBBBAAO8D/z0BAggggAACCCCg6zr1B/B9gIBbqanU8QA557ltW/EB+N8HpqZpBMB0yBX6ZHUMfrFjqw1IdkTxTwKwVZ+AZfzCHysphDC+o30CYFgMjsAPnYQAAAAASUVORK5CYII=) center center no-repeat; | |
&.incoming{ | |
background-color: #B3D1B2; | |
} | |
&.outgoing{ | |
background-color: #F7D4BE; | |
} | |
.container{ | |
position: relative; | |
width: 100%; | |
height: 100%; | |
span{ | |
position: absolute; | |
padding: 3px; | |
&.top{ | |
top: 0px; | |
} | |
&.bottom{ | |
bottom: 0px; | |
} | |
&.left{ | |
left: 0px; | |
color: blue; | |
} | |
&.right{ | |
right: 0px; | |
color: green; | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment