Canvas text is not all displaying - javascript

I'm recreating the classic Sandwich Alignment Chart using the HTML5 canvas, but my programatic titles for the blocks are not working properly.
They seem to print out fine in the console, so I cannot see why they don't all get rendered on the canvas.
Below is my latest Alignment Chart code.
// we create a canvas element
var canvas = document.getElementById('chart');
var height = 500;
var width = height * 1.5;
var blockWidth = width / 4;
var blockHeight = height / 4;
var largestFont = height / 12;
const subject = 'Sandwich';
const yAxisTerm = 'Structure';
const xAxisTerm = 'Ingredients';
const alignmentDegrees = ['Purist', 'Neutral', 'Rebel']
const alignmentDet = [
'Hardline Traditionalist',
'True Neutral',
`Radical ${subject} Anarchy`
]
const xDegrees = alignmentDegrees.map(degree => ({
title: `${xAxisTerm} ${degree}`
}));
const yDegrees = alignmentDegrees.map(degree => ({
title: `${yAxisTerm} ${degree}`
}));
const degreeColours = ['#264211', '#7B5C09', '#600000']
const blockColours = ['#303030', '#454545', '#595959', '#727272', '#828282'];
canvas.height = height*2;
canvas.width = width*2;
// getting the context will allow to manipulate the image
var context = canvas.getContext("2d");
// We create a new imageData.
var imageData = context.createImageData(width, height);
// The property data will contain an array of int8
var data = imageData.data;
context.lineWidth = 2;
context.strokeStyle = "black";
context.fillStyle = "white";
context.fillRect(0, 0, canvas.width, canvas.height);
context.stroke();
context.lineWidth = 2;
context.strokeStyle = "black";
for (let row = 0; row < 3; row++) {
const rowColours = blockColours.slice(row, row + 3)
for (let col = 0; col < 3; col++) {
context.fillStyle = rowColours[col];
context.fillRect(
width - blockWidth * (1 + row),
height - blockHeight * (1 + col),
blockWidth,
blockHeight
);
context.stroke();
const yBlockText = `${yAxisTerm} ${alignmentDegrees[col]},`;
const xBlockText = `${xAxisTerm} ${alignmentDegrees[row]}`;
context.fillStyle = "white";
context.font = `${largestFont/3}px Impact`;
const topTextX = blockWidth * (1 + row);
const topTextY = blockHeight * (1 + col) + largestFont / 2;
if (col === row) {
console.log(`${topTextX}, ${topTextY}, ${alignmentDet[col]}`)
context.fillText(
alignmentDet[col],
topTextX,
topTextY,
blockWidth
)
} else {
console.log(`${topTextX}, ${topTextY}, ${yBlockText} ${xBlockText}`)
context.fillText(
yBlockText,
topTextX,
topTextY,
blockWidth
)
context.fillText(
xBlockText,
topTextX,
topTextY + largestFont / 2,
blockWidth
)
}
}
};
context.beginPath();
context.strokeStyle = 'grey';
context.moveTo(blockWidth * 0.1, blockHeight * 2);
context.lineTo(blockWidth * 0.9, blockHeight * 2);
context.stroke();
context.beginPath();
context.strokeStyle = 'grey';
context.moveTo(blockWidth * 0.1, blockHeight * 3);
context.lineTo(blockWidth * 0.9, blockHeight * 3);
context.stroke();
context.beginPath();
context.strokeStyle = 'grey';
context.moveTo(blockWidth * 2, blockHeight * 0.5);
context.lineTo(blockWidth * 2, blockHeight * 0.9);
context.stroke();
context.beginPath();
context.strokeStyle = 'grey';
context.moveTo(blockWidth * 3, blockHeight * 0.5);
context.lineTo(blockWidth * 3, blockHeight * 0.9);
context.stroke();
context.fillStyle = "#e5e5e5";
context.fillRect(0, 0, canvas.width, blockHeight * 0.45);
context.stroke();
// text
context.fillStyle = "#ACACAC";
context.font = `${largestFont}px Impact`
context.textBaseline = 'middle';
context.textAlign = "center";
context.fillText(`The ${subject} Alignment chart`.toUpperCase(), canvas.width / 2, blockHeight * 0.25, canvas.width);
yDegrees.forEach((degreeText, index) => {
context.fillStyle = degreeColours[index];
context.font = `${largestFont/2}px Impact`;
context.fillText(degreeText.title, blockWidth / 2, blockHeight * (1 + index) + largestFont / 2, blockWidth)
})
xDegrees.forEach((degreeText, index) => {
context.fillStyle = degreeColours[index];
context.font = `${largestFont/2}px Impact`;
context.fillText(degreeText.title, blockWidth * (1.5 + index), blockHeight * (0.6), blockWidth)
})
function createData(type, mimetype) {
var value = canvas.toDataURL(mimetype);
if (value.indexOf(mimetype) > 0) { // we check if the format is supported
return {
type: type,
value: value
}
} else {
return false;
}
}
<canvas id="chart"></canvas>

Change the following:
context.fillRect(
width - blockWidth * (1 + row),
height - blockHeight * (1 + col),
blockWidth,
blockHeight
);
to:
context.fillRect(
blockWidth * (1 + row),
blockHeight * (1 + col),
blockWidth,
blockHeight
);
What you are doing is drawing the rectangle from right to left while writing the text in the grid from left to right and it wipes out what was plotted previously.
While this fixes the text issue you need to make adjustment to get the background colors correctly, by reversing the list of colours used:
const blockColours = ['#828282', '#727272', '#595959', '#454545', '#303030'];

Related

Making a Graph/Curve with Javascript and HTML

I am trying to make a program that you can can input numbers into, and it creates a graph based off of those (like Desmos, but the numbers you input don't need to be formatted like (1, 0) and you can control the spacing of the numbers). I am coding this in Javascript, and HTML for the actual inputs and canvas.
I have tried using this website as a foundation to help me create the curve.
Here is the combined Javascript and HTML code:
<!DOCTYPE html>
<html>
<body>
<form>
<label></label>
<input id="numbers" value="Numbers">
<button onClick="refresh()">Submit</button>
</form>
<form>
<label></label>
<input id="spacing" value="Spacing">
<button onClick="refresh()">Submit</button>
</form>
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>
<script>
refresh()
numbers = document.getElementById("numbers").value;
function refresh(){
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.moveTo(20, 20);
ctx.bezierCurveTo(numbers);
ctx.stroke();
}
</script>
</html>
Please note that I know that the canvas does not work (the variable numbers isn's working, any help?), but my main concern is that this code doesn't create a graph like I want it to. I want to type in numbers, and have it plot invisible points x numbers above the "ground" (the bottom of the canvas) and then use bezier to make a curve go through those invisible points (don't make the points, that was the only way I could think of explaining it).
For my internship, I was asked to develop a lightweight web application for some of our internal operations. One of the functions I wanted to include was a graph/chart that plotted Sales data for a selected employee. I also wanted to be able to change the resolution of the chart's x-axis such that I could view Sales by day, week, month, quarter, or year.
Here's what I came up with using just basic JavaScript and HTML Canvas.
Regarding the fix_dpi() function (that may be confusing to new coders, like myself), here was an article explaining what it is and why you will want to adjust for it: https://medium.com/wdstack/fixing-html5-2d-canvas-blur-8ebe27db07da .
Also, note that my drawYTicks() function has a special case for the "50K" and "500K" labels. If you need something a little more general, just copy the code of from drawXTicks() and make the minor changes necessary for it's domain.
Code:
<script>
let canvas = document.getElementById('canvas'), ctx = canvas.getContext('2d'), dpi = window.devicePixelRatio;
let xOrig = canvas.width * 0.15;
let yOrig = canvas.height * 0.85;
let xLen = canvas.width * 0.7;
let yLen = canvas.height * 0.7;
function fix_dpi() {
let style = {
height() {
return +getComputedStyle(canvas).getPropertyValue('height').slice(0, -2);
},
width() {
return +getComputedStyle(canvas).getPropertyValue('width').slice(0, -2);
}
}
canvas.setAttribute('width', style.width() * dpi);
canvas.setAttribute('height', style.height() * dpi);
xOrig = canvas.width * 0.15;
yOrig = canvas.height * 0.85;
xLen = canvas.width * 0.7;
yLen = canvas.height * 0.7;
}
function draw() {
fix_dpi(); //fixes dpi for sharper image...
var dataSet = // int[][] containing the data.
var xLabs = // a string[] containing x-labels.
var yLabs = // a string[] containing y-labels.
var range = // an integer expressing the top of your range (x-axis);
var domain = // an integer expressing the top of your domain (y-axis)
console.log(xLabs);
console.log(xLabs.length);
console.log(yLabs);
console.log(yLabs.length);
drawChartTitle("Employee (Total) Sales History");
fillDataSpace(dataSet, range, domain, '#3F3');
drawDataLine(dataSet, range, domain, '#000');
drawDataPoints(dataSet, range, domain, '#F00');
drawXTicks(xLabs);
drawYTicks(yLabs);
drawAxes();
}
function drawChartTitle(title) {
ctx.save();
ctx.fillStyle = '#000';
ctx.font = '24px Times New Roman';
ctx.textAlign = 'center';
ctx.fillText(title, canvas.width / 2, canvas.height * 0.1);
ctx.restore();
}
function drawAxes(color='#000') {
ctx.save();
ctx.beginPath();
ctx.strokeStyle = color;
ctx.moveTo(xOrig, (yOrig - yLen));
ctx.lineTo(xOrig, yOrig);
ctx.lineTo((xOrig + xLen),yOrig);
ctx.stroke();
ctx.restore();
}
function drawYTicks(yLabs) {
//Note: two of the ticks have to be handled separately
//for this program, 50K and 500K.
ctx.save();
let tickLen = canvas.height / 50;
let yDivs = yLen / (yLabs.length - 1);
let tickX = xOrig - tickLen / 2;
let labX = xOrig - tickLen;
ctx.beginPath();
ctx.strokeStyle = '#000';
ctx.fillStyle = '#000';
ctx.font = '12px Times New Roman';
ctx.textAlign = 'right';
if (yLabs.length >= 4) {
yDivs = yLen / (yLabs.length - 3);
//Draw million dollar ticks and labels
for (let i = 3; i < yLabs.length; i++) {
let tickY = yOrig - yDivs * (i-2);
ctx.moveTo(tickX, tickY);
ctx.lineTo((tickX + tickLen), tickY);
}
for (let i = 3; i < yLabs.length; i++) {
let labY = yOrig - yDivs * (i-2) + 4;
ctx.fillText(yLabs[i], labX, labY);
}
//Draw 50K and 500K
let fifty = yOrig - yDivs * 0.1;
ctx.moveTo(tickX, fifty);
ctx.lineTo((tickX + tickLen), fifty);
ctx.fillText(yLabs[1], labX, fifty + 4);
let fHundredK = yOrig - yDivs * 0.5;
ctx.moveTo(tickX, fHundredK);
ctx.lineTo((tickX + tickLen), fHundredK);
ctx.fillText(yLabs[2], labX, fHundredK + 4);
}
else if (yLabs.length == 3) {
yDivs = yLen / (yLabs.length - 2);
//Draw 50K and 500K only
let fifty = yOrig - yDivs * 0.1;
ctx.moveTo(tickX, fifty);
ctx.lineTo((tickX + tickLen), fifty);
ctx.fillText(yLabs[1], labX, fifty + 4);
let fHundredK = yOrig - yDivs;
ctx.moveTo(tickX, fHundredK);
ctx.lineTo((tickX + tickLen), fHundredK);
ctx.fillText(yLabs[2], labX, fHundredK + 4);
}
else {
//Draw 50K only
let fifty = yOrig - yDivs;
ctx.moveTo(tickX, fifty);
ctx.lineTo((tickX + tickLen), fifty);
ctx.fillText(yLabs[1], labX, fifty + 4);
}
let zero = yOrig;
ctx.moveTo(tickX, zero);
ctx.lineTo((tickX + tickLen), zero);
ctx.fillText(yLabs[0], labX, zero + 4);
ctx.stroke();
ctx.restore();
}
function drawXTicks(xLabs) {
ctx.save();
let tickLen = canvas.height / 50;
let xDivs = xLen / (xLabs.length - 1);
ctx.beginPath();
ctx.strokeStyle = '#000';
for (let i = 0; i < xLabs.length; i++) {
let tickX = xOrig + xDivs * i;
let tickY = yOrig + tickLen / 2;
ctx.moveTo(tickX, tickY);
ctx.lineTo(tickX, (tickY - tickLen));
}
ctx.stroke();
ctx.restore();
for (let i = 0; i < xLabs.length; i++) {
ctx.save();
ctx.fillStyle = '#000';
ctx.font = '12px Times New Roman';
ctx.textAlign = 'right';
ctx.translate((canvas.width*0.15) + (xDivs * i), canvas.height*0.15);
ctx.rotate(-Math.PI / 4);
let labY = canvas.height * 0.52;
let labX = -canvas.width * 0.38;
ctx.fillText(xLabs[i], labX, labY);
ctx.restore();
}
}
function drawDataPoints(coords, maxX, maxY, color='#000') {
ctx.save();
if (coords.length >= 2) {
let xScale = xLen / maxX;
let yScale = yLen / maxY;
let pointCir = canvas.height / 200;
ctx.beginPath();
for (let i = 0; i < coords.length; i++) {
let xp = xOrig + coords[i][0] * xScale;
let yp = yOrig - coords[i][1] * yScale;
ctx.moveTo(xp, yp);
ctx.arc(xp, yp, pointCir, 0, Math.PI * 2);
}
ctx.fillStyle = color;
ctx.fill();
ctx.strokeStyle = color;
ctx.stroke();
}
else {
ctx.fillStyle = '#000';
ctx.font = '24px Sans-Serif';
ctx.fillText('There is no data to display', (xOrig + xLen * 0.3), (yOrig - yLen * 0.5));
}
ctx.restore();
}
function drawDataLine(coords, maxX, maxY, color='#000') {
ctx.save();
if (coords.length >= 2) {
let xScale = xLen / maxX;
let yScale = yLen / maxY;
let xp = xOrig + coords[0][0] * xScale;
let yp = yOrig - coords[0][1] * yScale;
ctx.beginPath();
ctx.moveTo(xp, yp);
for (let i = 1; i < coords.length; i++) {
xp = xOrig + coords[i][0] * xScale;
yp = yOrig - coords[i][1] * yScale;
ctx.lineTo(xp, yp);
}
ctx.strokeStyle = color;
ctx.stroke();
}
else {
ctx.fillStyle = '#000';
ctx.font = '24px Sans-Serif';
ctx.fillText('There is no data to display', (xOrig + xLen * 0.3), (yOrig - yLen * 0.5));
}
ctx.restore();
}
function fillDataSpace(coords, maxX, maxY, color = '#00F') {
ctx.save();
if (coords.length >= 2) {
let xScale = xLen / maxX;
let yScale = yLen / maxY;
let xp = xOrig + coords[0][0] * xScale;
let yp = yOrig - coords[0][1] * yScale;
var lingrad = ctx.createLinearGradient(xOrig, yOrig - yLen, xOrig + xLen, yOrig);
lingrad.addColorStop(0, '#FFF');
lingrad.addColorStop(0.5, color);
lingrad.addColorStop(1, '#FFF');
ctx.beginPath();
ctx.moveTo(xp, yp);
for (let i = 1; i < coords.length; i++) {
xp = xOrig + coords[i][0] * xScale;
yp = yOrig - coords[i][1] * yScale;
ctx.lineTo(xp, yp);
}
ctx.lineTo(xOrig + xLen, yOrig);
ctx.lineTo(xOrig, yOrig);
ctx.closePath();
ctx.strokeStyle = lingrad;
ctx.stroke();
ctx.fillStyle = lingrad;
ctx.fill();
}
else {
ctx.fillStyle = '#000';
ctx.font = '24px Sans-Serif';
ctx.fillText('There is no data to display', (xOrig + xLen * 0.3), (yOrig - yLen * 0.5));
}
ctx.restore();
}
</script>
Here's what it looks like with some rendered data: Employee Sales Chart
Final note: I handled the collection of the data points and data labels using a static class object within my program, and passed this object to the HTML (Razor) page for my project. But, this solution should work if you have a way to get the data to your JS functions. If nothing else, you can start playing with this by defining the dataSet, xLabs, yLabs, range, and domain variables first and then figuring out how to pass larger data sets to the function later.

Color Wheel Picker Canvas javascript

I want to achieve something like this with canvas
something i want to achieve is i can maybe generate the color wheel like this
$("#id").colorWheel({
width: 200,
height: 200
});
i already try to google it , and i can't find a perfect color wheel picker , i just need the color wheel without any sliders , i already try iro js , but i can't remove the sliders from the plugin , can someone help me to create this color wheel with javascript/Jquery and canvas?
There is an answer to this question on codereview.stackexchange.com: https://codereview.stackexchange.com/questions/69887/drawing-a-color-wheel-faster
Just for fun, here is an implementation:
/**
* degreesToRadians
*
* #param {number} degrees
* #returns {number} radians
*/
function degreesToRadians(degrees) {
return degrees * (Math.PI / 180);
}
/**
* generateColorWheel
*
* #param {number} [size=400]
* #param {string} [centerColor="white"]
* #returns {HTMLCanvasElement}
*/
function generateColorWheel(size, centerColor) {
if (size === void 0) { size = 400; }
if (centerColor === void 0) { centerColor = "white"; }
//Generate main canvas to return
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = canvas.height = size;
//Generate canvas clone to draw increments on
var canvasClone = document.createElement("canvas");
canvasClone.width = canvasClone.height = size;
var canvasCloneCtx = canvasClone.getContext("2d");
//Initiate variables
var angle = 0;
var hexCode = [255, 0, 0];
var pivotPointer = 0;
var colorOffsetByDegree = 4.322;
//For each degree in circle, perform operation
while (angle++ < 360) {
//find index immediately before and after our pivot
var pivotPointerbefore = (pivotPointer + 3 - 1) % 3;
var pivotPointerAfter = (pivotPointer + 3 + 1) % 3;
//Modify colors
if (hexCode[pivotPointer] < 255) {
//If main points isn't full, add to main pointer
hexCode[pivotPointer] = (hexCode[pivotPointer] + colorOffsetByDegree > 255 ? 255 : hexCode[pivotPointer] + colorOffsetByDegree);
}
else if (hexCode[pivotPointerbefore] > 0) {
//If color before main isn't zero, subtract
hexCode[pivotPointerbefore] = (hexCode[pivotPointerbefore] > colorOffsetByDegree ? hexCode[pivotPointerbefore] - colorOffsetByDegree : 0);
}
else if (hexCode[pivotPointer] >= 255) {
//If main color is full, move pivot
hexCode[pivotPointer] = 255;
pivotPointer = (pivotPointer + 1) % 3;
}
//clear clone
canvasCloneCtx.clearRect(0, 0, size, size);
//Generate gradient and set as fillstyle
var grad = canvasCloneCtx.createRadialGradient(size / 2, size / 2, 0, size / 2, size / 2, size / 2);
grad.addColorStop(0, centerColor);
grad.addColorStop(1, "rgb(" + hexCode.map(function (h) { return Math.floor(h); }).join(",") + ")");
canvasCloneCtx.fillStyle = grad;
//draw full circle with new gradient
canvasCloneCtx.globalCompositeOperation = "source-over";
canvasCloneCtx.beginPath();
canvasCloneCtx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2);
canvasCloneCtx.closePath();
canvasCloneCtx.fill();
//Switch to "Erase mode"
canvasCloneCtx.globalCompositeOperation = "destination-out";
//Carve out the piece of the circle we need for this angle
canvasCloneCtx.beginPath();
canvasCloneCtx.arc(size / 2, size / 2, 0, degreesToRadians(angle + 1), degreesToRadians(angle + 1));
canvasCloneCtx.arc(size / 2, size / 2, size / 2 + 1, degreesToRadians(angle + 1), degreesToRadians(angle + 1));
canvasCloneCtx.arc(size / 2, size / 2, size / 2 + 1, degreesToRadians(angle + 1), degreesToRadians(angle - 1));
canvasCloneCtx.arc(size / 2, size / 2, 0, degreesToRadians(angle + 1), degreesToRadians(angle - 1));
canvasCloneCtx.closePath();
canvasCloneCtx.fill();
//Draw carved-put piece on main canvas
ctx.drawImage(canvasClone, 0, 0);
}
//return main canvas
return canvas;
}
//TEST
//Get color wheel canvas
var colorWheel = generateColorWheel(300);
//Add color wheel canvas to document
document.body.appendChild(colorWheel);
//Add ouput field
var p = document.body.appendChild(document.createElement("p"));
/**
* colorWheelMouse
*
* #param {MouseEvent} evt
*/
function colorWheelMouse(evt) {
var ctx = colorWheel.getContext("2d");
var data = ctx.getImageData(evt.offsetX, evt.offsetY, 1, 1);
p.innerHTML = "RGB: " + data.data.slice(0, 3).join(',');
}
//Bind mouse event
colorWheel.onmousemove = colorWheelMouse;
I created a simplified version of the accepted answer above.
function degreesToRadians(degrees) {
return degrees * (Math.PI / 180);
}
function drawColorWheel(canvas, size = 150) {
const context = canvas.getContext('2d');
canvas.width = size;
canvas.height = size;
const centerColor = 'white';
// Initiate variables
let angle = 0;
const hexCode = [0, 0, 255];
let pivotPointer = 0;
const colorOffsetByDegree = 4.322;
const radius = size / 2;
// For each degree in circle, perform operation
while (angle < 360) {
// find index immediately before and after our pivot
const pivotPointerbefore = (pivotPointer + 3 - 1) % 3;
// Modify colors
if (hexCode[pivotPointer] < 255) {
// If main points isn't full, add to main pointer
hexCode[pivotPointer] =
hexCode[pivotPointer] + colorOffsetByDegree > 255 ?
255 :
hexCode[pivotPointer] + colorOffsetByDegree;
} else if (hexCode[pivotPointerbefore] > 0) {
// If color before main isn't zero, subtract
hexCode[pivotPointerbefore] =
hexCode[pivotPointerbefore] > colorOffsetByDegree ?
hexCode[pivotPointerbefore] - colorOffsetByDegree :
0;
} else if (hexCode[pivotPointer] >= 255) {
// If main color is full, move pivot
hexCode[pivotPointer] = 255;
pivotPointer = (pivotPointer + 1) % 3;
}
const rgb = `rgb(${hexCode.map(h => Math.floor(h)).join(',')})`;
const grad = context.createRadialGradient(
radius,
radius,
0,
radius,
radius,
radius
);
grad.addColorStop(0, centerColor);
grad.addColorStop(1, rgb);
context.fillStyle = grad;
// draw circle portion
context.globalCompositeOperation = 'source-over';
context.beginPath();
context.moveTo(radius, radius);
context.arc(
radius,
radius,
radius,
degreesToRadians(angle),
degreesToRadians(360)
);
context.closePath();
context.fill();
angle++;
}
}
const canvas = document.getElementById('canvas');
drawColorWheel(canvas, 150);
https://codepen.io/Dianoga/pen/BbKawE

How To Get Value Of Canvas From A Wheel

How To Get The Value Of A Canvas . I have wheel which is rotating on mouse over the wheel stops now i want to echo out the value on which it was stopped. It is printing the whole array . Not the one on which the wheel stop.
$("#canvas").mouseover(function(){
backup= ctx;
alert(myData);
ctx = null;
});
this is the fiddle: https://jsfiddle.net/z61n9ccx/3/
Here is the full code:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
var PI2 = Math.PI * 2;
var myData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
var cx = 150;
var cy = 150;
var radius = 150;
var wheel = document.createElement('canvas');
var wheelCtx = wheel.getContext('2d');
var indicator = document.createElement('canvas');
var indicatorCtx = indicator.getContext('2d');
var angle = PI2 - PI2 / 4;
var myColor = [];
for (var i = 0; i < myData.length; i++) {
myColor.push(randomColor());
}
makeWheel();
makeIndicator();
requestAnimationFrame(animate);
function makeWheel() {
wheel.width = wheel.height = radius * 2 + 2;
wheelCtx.lineWidth = 1;
wheelCtx.font = '40px Pacifico, cursive';
wheelCtx.textAlign = 'center';
wheelCtx.textBaseline = 'middle';
var cx = wheel.width / 2;
var cy = wheel.height / 2;
var sweepAngle = PI2 / myData.length;
var startAngle = 0;
for (var i = 0; i < myData.length; i++) {
// calc ending angle based on starting angle
var endAngle = startAngle + sweepAngle;
// draw the wedge
wheelCtx.beginPath();
wheelCtx.moveTo(cx, cy);
wheelCtx.arc(cx, cy, radius, startAngle, endAngle, false);
wheelCtx.closePath();
wheelCtx.fillStyle = myColor[i];
wheelCtx.strokeStyle = 'black';
wheelCtx.fill();
wheelCtx.stroke();
// draw the label
var midAngle = startAngle + (endAngle - startAngle) / 2;
var labelRadius = radius * .85;
var x = cx + (labelRadius) * Math.cos(midAngle);
var y = cy + (labelRadius) * Math.sin(midAngle);
wheelCtx.fillStyle = 'gold';
wheelCtx.fillText(myData[i], x, y);
wheelCtx.strokeText(myData[i], x, y);
// increment angle
startAngle += sweepAngle;
}
}
function makeIndicator() {
indicator.width = indicator.height = radius + radius / 10;
indicatorCtx.font = '40px Georgia';
indicatorCtx.textAlign = 'center';
indicatorCtx.textBaseline = 'middle';
indicatorCtx.fillStyle = 'skyblue';
indicatorCtx.strokeStyle = 'blue';
indicatorCtx.lineWidth = 1;
var cx = indicator.width / 2;
var cy = indicator.height / 2;
indicatorCtx.beginPath();
indicatorCtx.moveTo(cx - radius / 8, cy);
indicatorCtx.lineTo(cx, cy - indicator.height / 2);
indicatorCtx.lineTo(cx + radius / 8, cy);
indicatorCtx.closePath();
indicatorCtx.fillStyle = 'skyblue'
indicatorCtx.fill();
indicatorCtx.stroke();
indicatorCtx.beginPath();
indicatorCtx.arc(cx, cy, radius / 3, 0, PI2);
indicatorCtx.closePath();
indicatorCtx.fill();
indicatorCtx.stroke();
indicatorCtx.fillStyle = 'blue';
indicatorCtx.fillText('Prizes', cx, cy);
}
function animate(time) {
ctx.clearRect(0, 0, cw, ch);
ctx.translate(cw / 2, ch / 2);
ctx.rotate(angle);
ctx.drawImage(wheel, -wheel.width / 2, -wheel.height / 2);
ctx.rotate(-angle);
ctx.translate(-cw / 2, -ch / 2);
ctx.drawImage(indicator, cw / 2 - indicator.width / 2, ch / 2 - indicator.height / 2)
angle += PI2 / 360;
requestAnimationFrame(animate);
}
function randomColor() {
return ('#' + Math.floor(Math.random() * 16777215).toString(16));
}
var backup = null;
$("#canvas").mouseover(function() {
backup = ctx;
alert(myData);
ctx = null;
});
$("#canvas").mouseout(function() {
// backup= ctx;
ctx = backup;
animate();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<canvas id="canvas" width="600" height="600" style="background-color:#ffff">
</canvas>
I added a counter, and then use that as a index: https://jsfiddle.net/Twisty/L6nws9yz/2/
HTML
<canvas id="canvas" width="310" height="310" style="background-color:#ffff">
</canvas>
<div id="counterBox">
<label>Counter:</label>
<span></span>
</div>
<div id="countBox">
<label>Index:</label>
<span></span>
</div>
JS
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
var PI2 = Math.PI * 2;
var myData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
var cx = 150;
var cy = 150;
var radius = 150;
var wheel = document.createElement('canvas');
var wheelCtx = wheel.getContext('2d');
var indicator = document.createElement('canvas');
var indicatorCtx = indicator.getContext('2d');
var currentSelection = 12;
var counter = 360;
var angle = PI2 - PI2 / 4;
var myColor = [];
for (var i = 0; i < myData.length; i++) {
myColor.push(randomColor());
}
makeWheel();
makeIndicator();
requestAnimationFrame(animate);
function makeWheel() {
wheel.width = wheel.height = radius * 2 + 2;
wheelCtx.lineWidth = 1;
wheelCtx.font = '40px Pacifico, cursive';
wheelCtx.textAlign = 'center';
wheelCtx.textBaseline = 'middle';
var cx = wheel.width / 2;
var cy = wheel.height / 2;
var sweepAngle = PI2 / myData.length;
var startAngle = 0;
for (var i = 0; i < myData.length; i++) {
// calc ending angle based on starting angle
var endAngle = startAngle + sweepAngle;
// draw the wedge
wheelCtx.beginPath();
wheelCtx.moveTo(cx, cy);
wheelCtx.arc(cx, cy, radius, startAngle, endAngle, false);
wheelCtx.closePath();
wheelCtx.fillStyle = myColor[i];
wheelCtx.strokeStyle = 'black';
wheelCtx.fill();
wheelCtx.stroke();
// draw the label
var midAngle = startAngle + (endAngle - startAngle) / 2;
var labelRadius = radius * .85;
var x = cx + (labelRadius) * Math.cos(midAngle);
var y = cy + (labelRadius) * Math.sin(midAngle);
wheelCtx.fillStyle = 'gold';
wheelCtx.fillText(myData[i], x, y);
wheelCtx.strokeText(myData[i], x, y);
// increment angle
startAngle += sweepAngle;
}
}
function makeIndicator() {
indicator.width = indicator.height = radius + radius / 10;
indicatorCtx.font = '40px Georgia';
indicatorCtx.textAlign = 'center';
indicatorCtx.textBaseline = 'middle';
indicatorCtx.fillStyle = 'skyblue';
indicatorCtx.strokeStyle = 'blue';
indicatorCtx.lineWidth = 1;
var cx = indicator.width / 2;
var cy = indicator.height / 2;
indicatorCtx.beginPath();
indicatorCtx.moveTo(cx - radius / 8, cy);
indicatorCtx.lineTo(cx, cy - indicator.height / 2);
indicatorCtx.lineTo(cx + radius / 8, cy);
indicatorCtx.closePath();
indicatorCtx.fillStyle = 'skyblue'
indicatorCtx.fill();
indicatorCtx.stroke();
indicatorCtx.beginPath();
indicatorCtx.arc(cx, cy, radius / 3, 0, PI2);
indicatorCtx.closePath();
indicatorCtx.fill();
indicatorCtx.stroke();
indicatorCtx.fillStyle = 'blue';
indicatorCtx.fillText('Prizes', cx, cy);
}
var lastloop = new Date;
var thisloop = new Date;
var fps = 0;
function animate(time) {
ctx.clearRect(0, 0, cw, ch);
ctx.translate(cw / 2, ch / 2);
ctx.rotate(angle);
ctx.drawImage(wheel, -wheel.width / 2, -wheel.height / 2);
ctx.rotate(-angle);
ctx.translate(-cw / 2, -ch / 2);
ctx.drawImage(indicator, cw / 2 - indicator.width / 2, ch / 2 - indicator.height / 2)
angle += PI2 / 360;
thisloop = new Date;
fps = 1000 / (thisloop - lastloop);
lastloop = thisloop;
counter--;
if (counter < 1) {
counter = 360;
}
$("#counterBox span").html(counter);
var index = counter / 30;
$("#countBox span").html(Math.round(index));
//$("#fpsBox span").html(fps);
requestAnimationFrame(animate);
}
function randomColor() {
return ('#' + Math.floor(Math.random() * 16777215).toString(16));
}
var backup = null;
$("#canvas").mouseover(function() {
backup = ctx;
alert(myData[Math.round(counter / 30)-1]);
ctx = null;
});
$("#canvas").mouseout(function() {
// backup= ctx;
ctx = backup;
animate();
});
Counter is set to 360 and then each frame decreases it. Take that and divide by 30 (360 / 12), and you can count each wedge. I round up and now I have 0 - 11 count.
Update
I moved the Index into a global space. To make it more precise, I used the % operator like so:
counter--;
if (counter == 0) {
counter = 360;
}
$("#counterBox span").html(counter);
if (counter % 30 === 0) {
index--;
}
$("#countBox span").html(Math.round(index));
if (index === 0) {
index = 12;
}
When you mouse over, you get the selection:
$("#canvas").mouseover(function() {
backup = ctx;
alert(index);
ctx = null;
});
I wrapped everything in an IIFE so that there aren't any global variables.
Updated Example
It's important to note that the angle calculation is:
angle = degree * Math.PI / 180;
With that being said, you can calculate the current degree and normalize it using:
(angle * (180 / Math.PI)) % 360
I added a function called getValue which takes an angle parameter:
function getValue(angle) {
var degree = (angle * (180 / Math.PI)) % 360,
offsetIndex = (Math.floor(degree / sweepDegree) + offset) % myData.length,
normalizedIndex = Math.abs(offsetIndex - (myData.length - 1));
return myData[normalizedIndex];
}
It essentially calculates the current degree, normalizes it taking into account what the initial degree was when the animation was initialized (which is the offset). Then it divides the degree by the sweep degree, which is 30 in this case since there are 12 items (i.e., 360/12 === 30) and rounds down.
var sweepDegree = 360 / myData.length;
var offset = (360 - (angle * (180 / Math.PI)) % 360) / sweepDegree;
This should work for a varying number of array items. In other words, nothing is hardcoded for a set length of 12 items (like in your case), so it should work for any given number of items.
Then you can simply use the getValue function in the mouseover event listener:
Updated Example
$("#canvas").mouseover(function() {
// ...
alert(getValue(angle));
});
(function() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
var PI2 = Math.PI * 2;
var myData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
var cx = 150;
var cy = 150;
var radius = 150;
var wheel = document.createElement('canvas');
var wheelCtx = wheel.getContext('2d');
var indicator = document.createElement('canvas');
var indicatorCtx = indicator.getContext('2d');
var angle = PI2 - PI2 / 4;
var sweepDegree = 360 / myData.length;
var offset = (360 - (angle * (180 / Math.PI)) % 360) / sweepDegree;
var myColor = [];
for (var i = 0; i < myData.length; i++) {
myColor.push(randomColor());
}
makeWheel();
makeIndicator();
requestAnimationFrame(animate);
function makeWheel() {
wheel.width = wheel.height = radius * 2 + 2;
wheelCtx.lineWidth = 1;
wheelCtx.font = '40px Pacifico, cursive';
wheelCtx.textAlign = 'center';
wheelCtx.textBaseline = 'middle';
var cx = wheel.width / 2;
var cy = wheel.height / 2;
var sweepAngle = PI2 / myData.length;
var startAngle = 0;
for (var i = 0; i < myData.length; i++) {
// calc ending angle based on starting angle
var endAngle = startAngle + sweepAngle;
// draw the wedge
wheelCtx.beginPath();
wheelCtx.moveTo(cx, cy);
wheelCtx.arc(cx, cy, radius, startAngle, endAngle, false);
wheelCtx.closePath();
wheelCtx.fillStyle = myColor[i];
wheelCtx.strokeStyle = 'black';
wheelCtx.fill();
wheelCtx.stroke();
// draw the label
var midAngle = startAngle + (endAngle - startAngle) / 2;
var labelRadius = radius * .85;
var x = cx + (labelRadius) * Math.cos(midAngle);
var y = cy + (labelRadius) * Math.sin(midAngle);
wheelCtx.fillStyle = 'gold';
wheelCtx.fillText(myData[i], x, y);
wheelCtx.strokeText(myData[i], x, y);
// increment angle
startAngle += sweepAngle;
}
}
function makeIndicator() {
indicator.width = indicator.height = radius + radius / 10;
indicatorCtx.font = '40px Georgia';
indicatorCtx.textAlign = 'center';
indicatorCtx.textBaseline = 'middle';
indicatorCtx.fillStyle = 'skyblue';
indicatorCtx.strokeStyle = 'blue';
indicatorCtx.lineWidth = 1;
var cx = indicator.width / 2;
var cy = indicator.height / 2;
indicatorCtx.beginPath();
indicatorCtx.moveTo(cx - radius / 8, cy);
indicatorCtx.lineTo(cx, cy - indicator.height / 2);
indicatorCtx.lineTo(cx + radius / 8, cy);
indicatorCtx.closePath();
indicatorCtx.fillStyle = 'skyblue'
indicatorCtx.fill();
indicatorCtx.stroke();
indicatorCtx.beginPath();
indicatorCtx.arc(cx, cy, radius / 3, 0, PI2);
indicatorCtx.closePath();
indicatorCtx.fill();
indicatorCtx.stroke();
indicatorCtx.fillStyle = 'blue';
indicatorCtx.fillText('Prizes', cx, cy);
}
function animate(time) {
if (ctx === null) {
return
}
ctx.clearRect(0, 0, cw, ch);
ctx.translate(cw / 2, ch / 2);
ctx.rotate(angle);
ctx.drawImage(wheel, -wheel.width / 2, -wheel.height / 2);
ctx.rotate(-angle);
ctx.translate(-cw / 2, -ch / 2);
ctx.drawImage(indicator, cw / 2 - indicator.width / 2, ch / 2 - indicator.height / 2)
angle += PI2 / 360;
requestAnimationFrame(animate);
}
function randomColor() {
return ('#' + Math.floor(Math.random() * 16777215).toString(16));
}
var backup = null;
$("#canvas").mouseover(function() {
backup = ctx;
ctx = null;
alert(getValue(angle));
});
$("#canvas").mouseout(function() {
ctx = backup;
animate();
});
function getValue(angle) {
var degree = (angle * (180 / Math.PI)) % 360,
offsetIndex = (Math.floor(degree / sweepDegree) + offset) % myData.length,
normalizedIndex = Math.abs(offsetIndex - (myData.length - 1));
return myData[normalizedIndex];
}
})();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<canvas id="canvas" width="600" height="600" style="background-color:#ffff">
</canvas>

Why is my HTML canvas not rotating?

Canvas script:
function clock_hand_hh(hh) {
var hh_canvas = document.getElementById('clock_hand_hh');
var hh_context = hh_canvas.getContext('2d');
hh_canvas.width = 500;
hh_canvas.height = 500;
var centerX = hh_canvas.width / 2;
var centerY = hh_canvas.height / 2;
var radius = 10;
hh_context.beginPath();
hh_context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
hh_context.fillStyle = '#000000';
hh_context.fill();
hh_context.lineWidth = 5;
hh_context.strokeStyle = '#000000';
hh_context.stroke();
hh_context.beginPath();
hh_context.bezierCurveTo(centerX, centerY, centerX - 10, centerY - 50, centerX, centerY - 100);
hh_context.bezierCurveTo(centerX, centerY-100, centerX + 10, centerY - 50, centerX, centerY);
hh_context.fillStyle = '#000000';
hh_context.fill();
hh_context.lineWidth = 2;
hh_context.strokeStyle = '#000000';
hh_context.stroke();
if (hh > 12) {
hh = hh - 12;
}
//alert((hh / 12) * 2 * Math.PI);
hh_context.translate(centerX, centerY);
hh_context.rotate((hh / 12) * 2 * Math.PI);
}
Note: The alert(which I commented) is showing the correct value of angle of rotation required (in radians) for canvas.
You just move it twice: you draw using center variables, and then move coordinates also...
function clock_hand_hh(hh) {
var hh_canvas = document.getElementById('clock_hand_hh');
var hh_context = hh_canvas.getContext('2d');
hh_canvas.width = 500;
hh_canvas.height = 500;
var centerX = hh_canvas.width / 2;
var centerY = hh_canvas.height / 2;
var radius = 10;
hh_context.translate(centerX, centerY);
hh_context.rotate((hh / 12) * 2 * Math.PI);
hh_context.beginPath();
hh_context.arc(0, 0, radius, 0, 2 * Math.PI, false);
hh_context.fillStyle = '#000000';
hh_context.fill();
hh_context.lineWidth = 5;
hh_context.strokeStyle = '#000000';
hh_context.stroke();
hh_context.beginPath();
hh_context.bezierCurveTo(0, 0, -10, -50, 0, -100);
hh_context.bezierCurveTo(0, -100, 10, -50, 0, 0);
hh_context.fillStyle = '#000000';
hh_context.fill();
hh_context.lineWidth = 2;
hh_context.strokeStyle = '#000000';
hh_context.stroke();
if (hh > 12) {
hh = hh % 12 + 1;
}
//alert((hh / 12) * 2 * Math.PI);
}
clock_hand_hh(4);
<canvas id="clock_hand_hh" style="width: 200px; height: 200px;"></canvas>
When you translate or rotate context it means you move and rotate the coordinate system with which you want to work. It does not affect the image already drawn.
What you need to do, is to modify the coordinate system before you start drawing. So just move the following two lines before the first beginPath() statement.
hh_context.translate(centerX, centerY);
hh_context.rotate((hh / 12) * 2 * Math.PI);

If/Then Javascript to Display HTML Code

I have some html5 and javascript code to create a spinning roulette wheel. It is split up into 14 outcomes. My question is, how can I get some unique HTML code to display per each outcome of the wheel. For example, if the wheel lands on Business, some text will appear below the wheel that has information on Business.
Here is my HTML code and below it is a link to a working example:
<!--[if IE]><script type="text/javascript" src="/sites/default/files/1010/source/excanvas.js"></script><![endif]-->
<input type="button" value="spin" onclick="spin();" style="float: left;" />
<canvas id="wheelcanvas" width="800" height="750"></canvas>
<script type="application/javascript">
var colors = ["#B8D430", "#3AB745", "#029990", "#3501CB",
"#2E2C75", "#673A7E", "#CC0071", "#F80120",
"#F35B20", "#FB9A00", "#FFCC00", "#FEF200", "#B2DF00", "#5C8300"];
var classes = ["Business", "Office Education", "Continuing Care Assistant", "Practical Nursing",
"Primary Care Paramedic", "Early Childhood Education", "Cooking", "Electrician",
"Heavy Equipment Operator", "Industrial Mechanic - Millwright", "Plumbing & Pipefitting", "Truck Driver Training", "Welding", "Power Engineering"];
var startAngle = 0;
var arc = Math.PI / 7;
var spinTimeout = null;
var spinArcStart = 10;
var spinTime = 0;
var spinTimeTotal = 0;
var ctx;
function draw() {
drawRouletteWheel();
}
function drawRouletteWheel() {
var canvas = document.getElementById("wheelcanvas");
if (canvas.getContext) {
var outsideRadius = 300;
var textRadius = 260;
var insideRadius = 100;
ctx = canvas.getContext("2d");
ctx.clearRect(5,0,1000,1000);
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.font = 'bold 10px sans-serif';
for(var i = 0; i < 14; i++) {
var angle = startAngle + i * arc;
ctx.fillStyle = colors[i];
ctx.beginPath();
ctx.arc(400, 400, outsideRadius, angle, angle + arc, false);
ctx.arc(400, 400, insideRadius, angle + arc, angle, true);
ctx.stroke();
ctx.fill();
ctx.save();
ctx.shadowOffsetX = -1;
ctx.shadowOffsetY = -1;
ctx.shadowBlur = 0;
ctx.shadowColor = "rgb(220,220,220)";
ctx.fillStyle = "black";
ctx.translate(400 + Math.cos(angle + arc / 2) * textRadius, 400 + Math.sin(angle + arc / 2) * textRadius);
ctx.rotate(angle + arc / 2 + Math.PI / 2);
var text = classes[i];
ctx.fillText(text, -ctx.measureText(text).width / 2, 0);
ctx.restore();
}
//Arrow
ctx.fillStyle = "black";
ctx.beginPath();
ctx.moveTo(400 - 4, 400 - (outsideRadius + 5));
ctx.lineTo(400 + 4, 400 - (outsideRadius + 5));
ctx.lineTo(400 + 4, 400 - (outsideRadius - 5));
ctx.lineTo(400 + 9, 400 - (outsideRadius - 5));
ctx.lineTo(400 + 0, 400 - (outsideRadius - 13));
ctx.lineTo(400 - 9, 400 - (outsideRadius - 5));
ctx.lineTo(400 - 4, 400 - (outsideRadius - 5));
ctx.lineTo(400 - 4, 400 - (outsideRadius + 5));
ctx.fill();
}
}
function spin() {
spinAngleStart = Math.random() * 10 + 10;
spinTime = 0;
spinTimeTotal = Math.random() * 3 + 4 * 1000;
rotateWheel();
}
function rotateWheel() {
spinTime += 30;
if(spinTime >= spinTimeTotal) {
stopRotateWheel();
return;
}
var spinAngle = spinAngleStart - easeOut(spinTime, 0, spinAngleStart, spinTimeTotal);
startAngle += (spinAngle * Math.PI / 180);
drawRouletteWheel();
spinTimeout = setTimeout('rotateWheel()', 30);
}
function stopRotateWheel() {
clearTimeout(spinTimeout);
var degrees = startAngle * 180 / Math.PI + 90;
var arcd = arc * 180 / Math.PI;
var index = Math.floor((360 - degrees % 360) / arcd);
ctx.save();
ctx.font = 'bold 30px sans-serif';
var text = classes[index]
ctx.fillText(text, 400 - ctx.measureText(text).width / 2, 400 + 10);
ctx.restore();
document.getElementById('wheelResult').innerHTML = 'Test' + text;
}
function easeOut(t, b, c, d) {
var ts = (t/=d)*t;
var tc = ts*t;
return b+c*(tc + -3*ts + 3*t);
}
draw();
</script>
<p id="wheelResult"></p>
http://www.ctrc.sk.ca/wheel.html
There are a couple of ways to do it but this is the way I would do it.
You could create a div tag with the css style of display:none and then set it with the info desired and hide and show it as needed.
Example:
<script>
var htmlData = ['<h1>Business</h1><br><span>What is Business?</span><br>...', ...];
....
function spin()
{
//Hide description box.
document.getElementById('idDescriptionBox').style.display = 'none';
spinAngleStart = Math.random() * 10 + 10;
....
}
....
function stopRotateWheel()
{
....
//Set description and display it.
var descriptionBox = document.getElementById('idDescriptionBox');
descriptionBox.innerHTML = htmlData[index];
descriptionBox.style.display = 'block';
}
....
</script>
<div id="idDescriptionBox" style="display:none;">
<!--Description info in here-->
....
</div>

Categories

Resources