Skip to content

Instantly share code, notes, and snippets.

@jrue
Last active August 9, 2023 14:21
Show Gist options
  • Star 40 You must be signed in to star a gist
  • Fork 26 You must be signed in to fork a gist
  • Save jrue/a2aaf36b3c096925ccbf to your computer and use it in GitHub Desktop.
Save jrue/a2aaf36b3c096925ccbf to your computer and use it in GitHub Desktop.
HTML & CSS Wheel Of Fortune / Bingo Game
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Wheel of Fortune Bingo</title>
<!--
MIT License
Copyright (c) 2017 Jeremy Rue
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-->
<style type="text/css">
text{
font-family:Helvetica, Arial, sans-serif;
font-size:11px;
pointer-events:none;
}
#chart{
position:absolute;
width:500px;
height:500px;
top:0;
left:0;
}
#question{
position: absolute;
width:400px;
height:500px;
top:0;
left:520px;
}
#question h1{
font-size: 50px;
font-weight: bold;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: absolute;
padding: 0;
margin: 0;
top:50%;
-webkit-transform:translate(0,-50%);
transform:translate(0,-50%);
}
</style>
</head>
<body>
<div id="chart"></div>
<div id="question"><h1></h1></div>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
var padding = {top:20, right:40, bottom:0, left:0},
w = 500 - padding.left - padding.right,
h = 500 - padding.top - padding.bottom,
r = Math.min(w, h)/2,
rotation = 0,
oldrotation = 0,
picked = 100000,
oldpick = [],
color = d3.scale.category20();//category20c()
//randomNumbers = getRandomNumbers();
//http://osric.com/bingo-card-generator/?title=HTML+and+CSS+BINGO!&words=padding%2Cfont-family%2Ccolor%2Cfont-weight%2Cfont-size%2Cbackground-color%2Cnesting%2Cbottom%2Csans-serif%2Cperiod%2Cpound+sign%2C%EF%B9%A4body%EF%B9%A5%2C%EF%B9%A4ul%EF%B9%A5%2C%EF%B9%A4h1%EF%B9%A5%2Cmargin%2C%3C++%3E%2C{+}%2C%EF%B9%A4p%EF%B9%A5%2C%EF%B9%A4!DOCTYPE+html%EF%B9%A5%2C%EF%B9%A4head%EF%B9%A5%2Ccolon%2C%EF%B9%A4style%EF%B9%A5%2C.html%2CHTML%2CCSS%2CJavaScript%2Cborder&freespace=true&freespaceValue=Web+Design+Master&freespaceRandom=false&width=5&height=5&number=35#results
var data = [
{"label":"Question 1", "value":1, "question":"What CSS property is used for specifying the area between the content and its border?"}, // padding
{"label":"Question 2", "value":1, "question":"What CSS property is used for changing the font?"}, //font-family
{"label":"Question 3", "value":1, "question":"What CSS property is used for changing the color of text?"}, //color
{"label":"Question 4", "value":1, "question":"What CSS property is used for changing the boldness of text?"}, //font-weight
{"label":"Question 5", "value":1, "question":"What CSS property is used for changing the size of text?"}, //font-size
{"label":"Question 6", "value":1, "question":"What CSS property is used for changing the background color of a box?"}, //background-color
{"label":"Question 7", "value":1, "question":"Which word is used for specifying an HTML tag that is inside another tag?"}, //nesting
{"label":"Question 8", "value":1, "question":"Which side of the box is the third number in: margin:1px 1px 1px 1px; ?"}, //bottom
{"label":"Question 9", "value":1, "question":"What are the fonts that don't have serifs at the ends of letters called?"}, //sans-serif
{"label":"Question 10", "value":1, "question":"With CSS selectors, what character prefix should one use to specify a class?"}, //period
{"label":"Question 11", "value":1, "question":"With CSS selectors, what character prefix should one use to specify an ID?"}, //pound sign
{"label":"Question 12", "value":1, "question":"In an HTML document, which tag holds all of the content people see?"}, //<body>
{"label":"Question 13", "value":1, "question":"In an HTML document, which tag indicates an unordered list?"}, //<ul>
{"label":"Question 14", "value":1, "question":"In an HTML document, which tag indicates the most important heading of your document?"}, //<h1>
{"label":"Question 15", "value":1, "question":"What CSS property is used for specifying the area outside a box?"}, //margin
{"label":"Question 16", "value":1, "question":"What type of bracket is used for HTML tags?"}, //< >
{"label":"Question 17", "value":1, "question":"What type of bracket is used for CSS rules?"}, // { }
{"label":"Question 18", "value":1, "question":"Which HTML tag is used for specifying a paragraph?"}, //<p>
{"label":"Question 19", "value":1, "question":"What should always be the very first line of code in your HTML?"}, //<!DOCTYPE html>
{"label":"Question 20", "value":1, "question":"What HTML tag holds all of the metadata tags for your page?"}, //<head>
{"label":"Question 21", "value":1, "question":"In CSS, what character separates a property from a value?"}, // colon
{"label":"Question 22", "value":1, "question":"What HTML tag holds all of your CSS code?"}, // <style>
{"label":"Question 23", "value":1, "question":"What file extension should you use for your web pages?"}, // .html
{"label":"Question 24", "value":1, "question":"Which coding language is used for marking up content and structure on a web page?"}, // HTML
{"label":"Question 25", "value":1, "question":"Which coding language is used for specifying the design of a web page?"}, // CSS
{"label":"Question 26", "value":1, "question":"Which coding language is used for adding functionality to a web page?"}, // JavaScript
{"label":"Question 27", "value":1, "question":"What CSS property is used for making the edges of a box visible?"}, // border
{"label":"Question 28", "value":1, "question":"What character symbol is used at the end of each CSS statement?"},//semi-colon
{"label":"Question 29", "value":1, "question":"By default, how wide is a <div> box?"}, //100%
{"label":"Question 30", "value":1, "question":"What character symbol do I use to specify multiple CSS selectors in one code block?"} //comma
];
var svg = d3.select('#chart')
.append("svg")
.data([data])
.attr("width", w + padding.left + padding.right)
.attr("height", h + padding.top + padding.bottom);
var container = svg.append("g")
.attr("class", "chartholder")
.attr("transform", "translate(" + (w/2 + padding.left) + "," + (h/2 + padding.top) + ")");
var vis = container
.append("g");
var pie = d3.layout.pie().sort(null).value(function(d){return 1;});
// declare an arc generator function
var arc = d3.svg.arc().outerRadius(r);
// select paths, use arc generator to draw
var arcs = vis.selectAll("g.slice")
.data(pie)
.enter()
.append("g")
.attr("class", "slice");
arcs.append("path")
.attr("fill", function(d, i){ return color(i); })
.attr("d", function (d) { return arc(d); });
// add the text
arcs.append("text").attr("transform", function(d){
d.innerRadius = 0;
d.outerRadius = r;
d.angle = (d.startAngle + d.endAngle)/2;
return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")translate(" + (d.outerRadius -10) +")";
})
.attr("text-anchor", "end")
.text( function(d, i) {
return data[i].label;
});
container.on("click", spin);
function spin(d){
container.on("click", null);
//all slices have been seen, all done
console.log("OldPick: " + oldpick.length, "Data length: " + data.length);
if(oldpick.length == data.length){
console.log("done");
container.on("click", null);
return;
}
var ps = 360/data.length,
pieslice = Math.round(1440/data.length),
rng = Math.floor((Math.random() * 1440) + 360);
rotation = (Math.round(rng / ps) * ps);
picked = Math.round(data.length - (rotation % 360)/ps);
picked = picked >= data.length ? (picked % data.length) : picked;
if(oldpick.indexOf(picked) !== -1){
d3.select(this).call(spin);
return;
} else {
oldpick.push(picked);
}
rotation += 90 - Math.round(ps/2);
vis.transition()
.duration(3000)
.attrTween("transform", rotTween)
.each("end", function(){
//mark question as seen
d3.select(".slice:nth-child(" + (picked + 1) + ") path")
.attr("fill", "#111");
//populate question
d3.select("#question h1")
.text(data[picked].question);
oldrotation = rotation;
container.on("click", spin);
});
}
//make arrow
svg.append("g")
.attr("transform", "translate(" + (w + padding.left + padding.right) + "," + ((h/2)+padding.top) + ")")
.append("path")
.attr("d", "M-" + (r*.15) + ",0L0," + (r*.05) + "L0,-" + (r*.05) + "Z")
.style({"fill":"black"});
//draw spin circle
container.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", 60)
.style({"fill":"white","cursor":"pointer"});
//spin text
container.append("text")
.attr("x", 0)
.attr("y", 15)
.attr("text-anchor", "middle")
.text("SPIN")
.style({"font-weight":"bold", "font-size":"30px"});
function rotTween(to) {
var i = d3.interpolate(oldrotation % 360, rotation);
return function(t) {
return "rotate(" + i(t) + ")";
};
}
function getRandomNumbers(){
var array = new Uint16Array(1000);
var scale = d3.scale.linear().range([360, 1440]).domain([0, 100000]);
if(window.hasOwnProperty("crypto") && typeof window.crypto.getRandomValues === "function"){
window.crypto.getRandomValues(array);
console.log("works");
} else {
//no support for crypto, get crappy random numbers
for(var i=0; i < 1000; i++){
array[i] = Math.floor(Math.random() * 100000) + 1;
}
}
return array;
}
</script>
</body>
</html>
@jauschalley
Copy link

Thanks for sharing. This is excellent.

@hafsaulusal
Copy link

Hi!

I want to move the rotation from client side to server side. Is there any way that we can directly select question 1 programatically, after rotating wheel?

@BizEvolv
Copy link

BizEvolv commented Sep 3, 2018

I created a wordpress plugin called RafflePress see here https://www.youtube.com/watch?v=TV0ZKt12gOM&t=29s - i just want to thank the author for this amazing script, without it I would have never been able to create it.

@LukasFrm
Copy link

LukasFrm commented Mar 5, 2019

Hope this will be of help to somebody:
1) To increase/decrease spin time edit the x in:
vis
.transition()
.duration(x)
2) To have an answer value that can never be chosen/won:
include the answer's data array index value in the oldpick array at the very top of js script

@chennyboy123
Copy link

Hi
Is it possible to make the questions appear in the center of the screen and make everything else fade into the background in the meantime?

@zandonline
Copy link

is there any way to set background image for each slice?

@jrue
Copy link
Author

jrue commented Mar 5, 2020

is there any way to set background image for each slice?

Yes, you'll need to modify the color variable. Look for this line of code:

color = d3.scale.category20();

The category20 basically pulls from this D3 color pallet

If you want your own custom colors, just modify the code, replacing the line of code like so, to include as many colors as you want.

color = ["#111111", "#222222", "#333333", "#444444", "#555555"];

@zandonline
Copy link

thanks, color is a solid color but I want use images as background not solid colors

@zandonline
Copy link

zandonline commented Mar 6, 2020

this is the code i use to put images in slices
`var defs = arcs.append("defs");
var pattern = defs.append("pattern")
.attr("id", function (d, i) { return "img" + i; })
.attr("patternUnits", "userSpaceOnUse")//objectBoundingBox,userSpaceOnUse
.attr("width", "1000")
.attr("height", "1000")
;
var image = pattern.append("image")
.attr("xlink:href", function (d, i) { return data[i].background; })
// .attr("x", "-200")
// .attr("y", "-200")
.attr("width", "1000")
.attr("height", "250")
/**/.attr("transform", function (d) {
d.innerRadius = 0;
d.outerRadius = r;
d.angle = (d.startAngle + d.endAngle) / 2;
return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")translate(" + (d.outerRadius - 10) + ")";
})

    arcs.append("path")
        .attr("fill", function (d, i) { return color(i); })
        //   .attr("fill", function(d, i){ return data[i].color; })
        //  .attr("fill","url(#img1)")
        // .attr("fill", function (d, i) { return "url(#img" + i + ")"; })
        .attr("d", function (d) { return arc(d); })`

but its not working properly

@ANIMIL
Copy link

ANIMIL commented May 15, 2020

Hi there,

Thanks for this amazing code!
There is only one thing: I cannot change the position. It will always be at the same place. Could someone tell me where in the code I can change that?

That will be great ;)

@wpswpswps
Copy link

Thanks a lot ... same question as trtrancuong751984 - how could we add a link to the answer?

Thanks again

@jrue
Copy link
Author

jrue commented Jul 14, 2020

Thanks a lot ... same question as trtrancuong751984 - how could we add a link to the answer?

Thanks again

@wpswpswps I haven't tested this, but try changing line 157 from

.text( function(d, i) {

to

.html( function(d, i) {

Then to add a link, just put some html in the question. You'll need to use single quotes

"question" : 'Some question with a <a href="https://google.com">link</a>'

@wpswpswps
Copy link

wpswpswps commented Jul 14, 2020

That doesn't seem to work but I'll keep trying.... and thanks for trying

@jrue
Copy link
Author

jrue commented Jul 14, 2020

That doesn't seem to work but I'll keep trying.... and thanks for trying

@wpswpswps Sorry, I meant line 206. I got the wrong line.

Change:

.text(data[picked].question);

to

.html(data[picked].question);

@wpswpswps
Copy link

You're awesome... thanks so much. I'll use this so much

@mikeletulle
Copy link

I was asked to create a custom app on our Salesforce platform where customers can choose charities for us to donate to. Thanks to this I was done in a morning :) Thanks so much for sharing!

@RufusDu
Copy link

RufusDu commented Jan 15, 2021

Hi thank you so much for making this code available. I've been trying to add one sound every time spin is clicked and would appreciate your help please?

@slagatoras
Copy link

slagatoras commented Jan 26, 2021

hi thank you for the code! is there any way to open a modal on certain labels? instead of text?

@rpsingh1
Copy link

rpsingh1 commented Feb 9, 2021

Thanks for sharing. This is excellent.

@adarsh7880-india
Copy link

Thanks a lot how could we add a button to the answar

@Nikki-pokharna
Copy link

Thanks for sharing. Great Work. Can you please explain why "https://d3js.org/d3.v3.min.js" this file has been included in the code?

@girlangelette
Copy link

Jeremy, such an awesome idea, thank you :)

@jrue
Copy link
Author

jrue commented May 6, 2021

Can you please explain why "https://d3js.org/d3.v3.min.js" this file has been included in the code?

This is the data visualization library that makes it run. For more info, see http://d3js.org/

@Staibocktsching
Copy link

How can I do that so that the answers don't disappear and the wheel always works.

@Noruman99
Copy link

Can I make the question show a picture and a text instead of just text? If so can you explain how can I do that.

@jrue
Copy link
Author

jrue commented Jan 19, 2022

@Noruman99 Maybe. On line 206 change .text(data[picked].question); to .html(data[picked].question); and include some HTML, like an img tag, in your json data. I haven't tested it, so I'm not sure what issues you might run into. It will probably require a little adjusting to the size and position of the text.

@leanvaz
Copy link

leanvaz commented Apr 7, 2022

Thanks a lot ... - How could we make the questions always vertical?

Thanks again

@arshohag
Copy link

How Can I change the spin wheel text color from black to others?

@arshohag
Copy link

Also how to make the wheel with some padding in between slices like the screenshot
image 1
?

@habibi1220
Copy link

Hi Dear Teacher!

I want to move the rotation from client side to server side. Is there any way that we can directly select question 1 programmatically, after rotating wheel? How can I select question after rotation?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment