-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
realtime voting web app tutorial from spectra hackathon
- Loading branch information
1 parent
72c970f
commit ff51d27
Showing
10 changed files
with
547 additions
and
1 deletion.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,7 @@ Missed an LSH tutorial? Check out the source code & slides here. | |
| [Learn AngularJS](https://github.com/Ladies-Storm-Hackathons/Tutorials/tree/master/learn-angularjs) | [Online, Aug 16th @ 5pm EST](https://www.facebook.com/events/1748805382027851) | [email protected] | Beginner | HTML/CSS and some Javascript would be a bonus | | ||
| [Intro to APIs & Build Your Own Twitter Bot](https://github.com/Ladies-Storm-Hackathons/Tutorials/tree/master/Intro-To-APIs-Twitter) | [Online, Sept 3rd @ 7pm CDT](https://www.facebook.com/events/293728037657127/) | [email protected] | Beginner | Python knowledge is a bonus | | ||
| [How To Prep for the Job Hunt](https://www.facebook.com/events/1732511737001747/) | [Online, Sept 20th @ 4PM EDT](https://www.facebook.com/events/1732511737001747/) | [email protected] | All | Anyone looking for their first internship or a full time job | | ||
|
||
| [Intro to Pub/Sub & Build a Realtime Voting Web app with Social Media APIs](https://github.com/Ladies-Storm-Hackathons/Tutorials/tree/master/javascript-realtime-voting-app-workshop) | [Spectra Hackathon @ YouTube HQ, July 23](https://www.sospectra.com) | [email protected] | Intermediate | JavaScript, HTML/CSS knowledge is a bonus | | ||
### Upcoming Tutorials | ||
| Tutorial Title | Location/Time | Speaker Contact Info | Level | Previous Skills Required | | ||
| :-------------------: | :-----------: | :------------------: | :---: | :----------------------: | | ||
|
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<p>This realtime voting web app was made for the first technical workshop I led as an evangelist intern, and also the largest technical workshop I have ever led. I found that the app could appeal to programmers of all skill levels because it was easily customizable, which could make for fun conversation and competition. <a href ="https://twitter.com/stephenlb">Stephen</a>, PubNub’s CTO, and <a href = "https://twitter.com/sw1tch">Ian</a>, an engineer, evangelist, and all-around special snowflake had a mini contest over who would have the most votes. The project could also be easily added expanded to use social media APIs and widgets.</p> | ||
![css-bar-graph](https://cloud.githubusercontent.com/assets/8932430/16998422/345eac1c-4e6e-11e6-9981-99dc681579d6.png) | ||
|
||
##Layout Setup for Keys, Buttons | ||
<p>First things first--get your PubNub publish and subscribe keys! Even though you are only publishing data, and not subscribing, you still need them both to initialize your PubNub object. | ||
</p> | ||
<p> | ||
Next, you create a dictionary of polling options. The values are the counts of the number of votes, starting at zero. | ||
</p> | ||
![voting-web-app-with-eon-javascript-buttons](https://cloud.githubusercontent.com/assets/8932430/16998425/371a5c44-4e6e-11e6-884a-f170251d01fa.png) | ||
<p>To set up the buttons in JavaScript, iterate through the keys in the dictionary, call document.createElement(‘BUTTON’) on each, set attributes like ID and style, and set the innerHTML to be the key of the dictionary. The event listener for each button would be the voteUp function, which increments the counts. | ||
</p> | ||
|
||
##Update Vote Counts from Button Clicked | ||
<p>VoteUp takes in a key, and increments that key’s value. It then publishes the dictionary to your channel. The incrementing and publishing must be wrapped in a JavaScript closure in order to distinguish the incrementing of counts between the buttons. | ||
</p> | ||
|
||
##EON chart | ||
<p> | ||
A bar graph best visualizes voting. To draw the graph in an HTML div titled chart, you just need to call the chart method on your eon object, and pass some parameters into it. Some are required, like your PubNub instance and your channel, but others are completely optional. | ||
</p> | ||
|
||
![eon-chart-realtime-voting-web-app](https://cloud.githubusercontent.com/assets/8932430/16998415/2dc785a4-4e6e-11e6-85b3-d961c7ba47be.png) | ||
|
||
#Storage and Playback with PubNub History API | ||
<p> | ||
Now, voting is most fun if lots of people do it! What if someone comes in from another browser after you? You need to keep track of previous votes with PubNub’s storage and playback, or History API. Even though you set history to be true above, you also need to go to your dashboard to enable the History API. Because each publish returns an associative array, or dictionary, of that total vote count, you only need to get the last message. The count of history is set to one, and the callback will take in that one, long message, and see that there is something there. It will then set your chart to be that long message, or associative array, of old votes. | ||
</p> | ||
|
||
##PubNub Voting App Conclusion | ||
<p> | ||
There you have it! This is the bare minimum you need for a realtime voting application. View the project in action <a href = "http://pubnub.github.io/eon-chart/examples/votes.html"> here</a>. To take it further, you could set a timer so the chart only takes in new votes for a certain amount of time, or use PubNub BLOCKS (still in beta, but launching soon) to restrict the number of times someone could vote. | ||
</p> | ||
|
||
##App Extras using Social Media Widgets, API | ||
<p> | ||
To make the workshop more fun (and to help fill up two hours), I added some extra features with Twitter widgets and the Facebook API. | ||
</p> | ||
###Web Intents with Twitter Widgets | ||
<p> | ||
Attendees learned about web intents, which let visitors to your website tweet, reply, like, follow, or reply from your site. The tweet intent let them create a pre-composed tweet that could be tweeted from a button on their site. | ||
</p> | ||
<p> | ||
Each parameter is optional, but the text, hashtags, and via ones are the most fun. Text sets the tweet, and via lets you include another twitter user. | ||
</p> | ||
###Working with the Facebook API | ||
![facebook-widget-extra-realtime-voting-web-app-with-eon](https://cloud.githubusercontent.com/assets/8932430/16998427/391d6536-4e6e-11e6-8413-53ae6205d27f.png) | ||
<p> | ||
The Facebook API was more complex. Everyone needed their own API keys, and the API features needed to run on a local server. It needed to check that you were logged in to Facebook before it could post a previously-composed status automatically for you, and then made a call to the Facebook API. | ||
</p> | ||
####What will you use EON for? |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
var pubKey = "pub-c-568f9a32-f440-4d58-9cee-e23cd1d12e7a"; | ||
var subKey = "sub-c-2e615be4-439b-11e6-971e-02ee2ddab7fe"; | ||
var chan = "Spectra"; | ||
|
||
var pollOptions = { | ||
eon: { | ||
"Mushu" : 0.0, | ||
"Erlich" :0.0, | ||
"Stephen" : 0.0, | ||
"Tomomi" : 0.0, | ||
"Ian" : 0.0 | ||
} | ||
}; | ||
|
||
var pb = PUBNUB.init({ | ||
publish_key: pubKey, | ||
subscribe_key: subKey | ||
}); | ||
|
||
//button layout, click action | ||
function setupButtons() { //buttons | ||
var buttonColor; | ||
for(key in pollOptions.eon) { | ||
var b = document.createElement('BUTTON'); | ||
b.setAttribute('id', 'button' + key); | ||
b.setAttribute('style', 'left:10%;width:6%;margin-left:4%;margin-top:4%;margin-bottom:5%;background-color:buttonColor;color:white;'); | ||
b.innerHTML = key; | ||
b.addEventListener("click", voteUp(key)); | ||
document.body.appendChild(b); | ||
|
||
} //for | ||
} //setup | ||
setupButtons(); //buttons | ||
|
||
//get history | ||
function initOlderVotes() { | ||
pb.history({ | ||
channel: chan, | ||
count: 1, | ||
callback: function(msg) { | ||
console.log("msg is ", msg); | ||
var voteHistory = msg[0]; | ||
if(voteHistory.length) { | ||
pollOptions = voteHistory[0]; | ||
} | ||
}, //callback | ||
}); //history | ||
} //initOlderVotes() | ||
|
||
initOlderVotes(); | ||
|
||
|
||
//publish -> keeps tally | ||
function publishResults() { | ||
pb.publish({ | ||
channel: chan, | ||
message: pollOptions, | ||
callback: function(m) { | ||
console.log("publishing!"); | ||
} | ||
}); | ||
} //publishResults() | ||
|
||
|
||
function voteUp(pollOptionKey) { | ||
return function() { | ||
console.log(pollOptions); | ||
pollOptions.eon[pollOptionKey] += 1.0; | ||
publishResults(); | ||
} //JS closure each button has unique function | ||
} | ||
|
||
//embed | ||
function drawChart() { | ||
eon.chart({ | ||
pubnub: pb, //same pubnub object, gets data from channel | ||
channel: chan, //same channel | ||
history: true, | ||
generate: { | ||
bindto: '#chart', | ||
data: { | ||
labels: true, | ||
type: 'bar', | ||
colors: { | ||
'Mushu': '#cc6699', | ||
'Erlich': '#0099cc', | ||
'Stephen': '#ffcc99', | ||
'Tomomi': '#33cccc', | ||
'Ian': '#0000ff' | ||
} | ||
}, | ||
bar: { | ||
width: { | ||
ratio: 0.5 | ||
} | ||
}, | ||
tooltip: { | ||
show: false //hover over and see chart of counts | ||
} | ||
} | ||
}); | ||
} | ||
|
||
drawChart(); | ||
|
||
|
||
//fb | ||
window.fbAsyncInit = function() { | ||
FB.init({ | ||
appId : 'your-app-id', | ||
xfbml : true, | ||
version : 'v2.7' | ||
}); | ||
}; | ||
|
||
(function(d, s, id){ | ||
var js, fjs = d.getElementsByTagName(s)[0]; | ||
if (d.getElementById(id)) { | ||
return; | ||
} | ||
js = d.createElement(s); | ||
|
||
js.id = id; | ||
js.src = "//connect.facebook.net/en_US/sdk.js"; | ||
fjs.parentNode.insertBefore(js, fjs); | ||
}(document, 'script', 'facebook-jssdk')); | ||
|
||
// Only works after `FB.init` is called | ||
function myFacebookLogin() { | ||
FB.login(function(){ | ||
// Note: The call will only work if you accept the permission request | ||
FB.api('/me/feed', 'post', {message: 'Hello, world! Having fun building a realtime voting app with #PubNub and #Twitter and #Facebook APIs #sospectra'}); | ||
}, {scope: 'publish_actions'}); | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/*all buttons have same width, pos, etc. only difference is color */ | ||
a: hover { | ||
background-color: #f5dfdf; | ||
} | ||
#buttonMushu { | ||
background-color:rgb(204,102,153); | ||
} | ||
#buttonErlich { | ||
background-color:rgb(0,153,204); | ||
} | ||
#buttonStephen { | ||
background-color:rgb(255,204,153); | ||
} | ||
#buttonTomomi { | ||
background-color:rgb(51,204,204); | ||
} | ||
#buttonIan { | ||
background-color:rgb(0,0,255); | ||
} | ||
|
||
#logoDiv { | ||
position: absolute; | ||
top:0; | ||
right:0; | ||
} | ||
|
||
#logoDiv img{ | ||
width:125px; | ||
height:100px; | ||
} | ||
|
||
#autoPostStatus { | ||
margin-top: 3%; | ||
margin-left: 4%; | ||
background-color: #3b5998; | ||
border: none; | ||
color: white; /*fb blue color */ | ||
text-align: center; | ||
padding: 12px 28px; | ||
font-size: 16px; | ||
} | ||
|
||
#twitterButton { | ||
margin-top: -7%; | ||
margin-left:55%; | ||
} | ||
|
||
#chart { | ||
width: 70%; | ||
height: 650px; | ||
top: 25%; | ||
background-color: #927FB8; | ||
margin-left: 4%; | ||
} | ||
|
||
h2 { | ||
color: #cc33ff; | ||
margin-left: 3%; | ||
font-size: 50px; | ||
} | ||
|
||
body { | ||
height: 100%; | ||
width: 100%; | ||
background-image: url("sky2.jpg"); | ||
background-repeat: no-repeat; | ||
background-size: cover; | ||
background-attachment: fixed; | ||
background-size: cover; | ||
background-position: top left; | ||
} | ||
|
||
footer { | ||
float:right; | ||
background-color:#927FB8; | ||
text-align:center; | ||
right:0; | ||
width:40%; | ||
position:fixed; | ||
left:0px; | ||
bottom:0px; | ||
height:5%; | ||
width:100%; | ||
font-size:1.5em; | ||
color: black; | ||
vertical-align: center; | ||
line-height: 60px; | ||
} | ||
|
||
footer a { | ||
color: #f5dfdf; | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
<!DOCTYPE html> | ||
<html lang="pt" xmlns:fb="http://www.facebook.com/2008/fbml"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<meta property="og:title" content="Lizzie's webapp" /> | ||
<title>Realtime survey with PubNub and EON.js--final version</title> | ||
<script src="http://cdnjs.cloudflare.com/ajax/libs/d3/3.4.13/d3.min.js"></script> | ||
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script> | ||
<script src="http://cdn.pubnub.com/pubnub-3.4.4.js"></script> | ||
<script type="text/javascript" src="http://pubnub.github.io/eon/v/eon/0.0.10/eon.js"></script> | ||
<link type="text/css" rel="stylesheet" href="http://pubnub.github.io/eon/v/eon/0.0.10/eon.css" /> | ||
<link rel="stylesheet" href="style.css" /> <!--CSS --> | ||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" /> | ||
<!--Twitter --> | ||
<script type="text/javascript" async src="https://platform.twitter.com/widgets.js"></script> | ||
</head> | ||
<body> | ||
<div id="fb-root"></div> | ||
<!-- USE 'Asynchronous Loading' version, for IE8 to work | ||
http://developers.facebook.com/docs/reference/javascript/FB.init/ --> | ||
|
||
<button id = "autoPostStatus" onclick="myFacebookLogin();">Post prev-composed status</button> | ||
<!--FB init buttons --> | ||
<div | ||
class="fb-like" | ||
data-share="true" | ||
data-width="450" | ||
data-show-faces="true"> | ||
</div> | ||
<div class = "container"> | ||
<h2><font color = "#6600cc">Who would you vote for president?</font></h2> | ||
</div> | ||
<div id="chart"></div> | ||
<script src="quiz.js"></script> | ||
<div id ="logoDiv"> | ||
<img src = "spectralogo2.png" /> | ||
</div> | ||
<div id = "twitterButton"> | ||
<a href="https://twitter.com/intent/tweet?text=making+a+realtime+web+voting+app+with+@pubnub+at+spectra+hackathon+at+@youtube&hashtags=sospectra&via=lizziepika">Tweet</a> | ||
</div> | ||
</body> | ||
<footer> | ||
<p id = "leftP" style="padding-bottom:25;">PubNub <a href="https://twitter.com/hashtag/projecteon" target="_blank">#projecteon</a> demo by <a href="https://twitter.com/lizziepika" target="_blank">@lizziepika</a></p> | ||
</footer> | ||
</html> | ||
|
||
</footer> | ||
</html> |
Oops, something went wrong.