I found another stack overflow post on this topic where the answer included using: document.getCSSCanvasContext and WebKit to interact with the canvas serving as the CSS background, but that function is depreciated. How else could you make a CSS background a canvas?
Here's the code from the other answer that doesn't work anymore:
<html>
<head>
<style>
div { background: -webkit-canvas(squares); width:600px; height:600px; border:2px solid black }
</style>
<script type="application/x-javascript">
function draw(w, h) {
var ctx = document.getCSSCanvasContext("2d", "squares", w, h);
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect (10, 10, 55, 50);
ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
ctx.fillRect (30, 30, 55, 50);
}
</script>
</head>
<body onload="draw(300, 300)">
<div></div>
</body>
</html>
There's a new(ish) API called CSS Houdini that allows you to do exactly what you wanted: https://developer.mozilla.org/en-US/docs/Web/API/PaintWorklet. It's browser support is still super minimal (chromium only currently). There is a pollyfill that should help expand support if needed.
Here's an overview of houdini
There's also an answer with this in the previous stack overflow answers: use canvas as a css background. The links from that answer are incredibly helpful. Especially (two links down) https://twitter.com/DasSurma/status/983305990731894785, which gave an example of how to get the API to work without importing a separate file.
if ("paintWorklet" in CSS) {
const src = document.querySelector('script[language$="paint"]').innerHTML;
const blob = new Blob([src], {
type: 'text/javascript'
});
CSS.paintWorklet.addModule(URL.createObjectURL(blob));
}
.squares {
background-image: paint(squares);
width: 200px;
height: 200px;
border: 2px solid black;
}
.checkboxes {
background-image: paint(checkerboard);
width: 200px;
height: 200px;
border: 2px solid black;
--checkerboard-spacing: 10;
--checkerboard-size: 32;
}
<div style="display:flex;">
<div class="squares">
</div>
<div class="checkboxes">
</div>
</div>
<script language="javascript+paint">
class SquaresPainter {
paint(ctx, gemetry, properties) {
ctx.fillStyle = 'rgb(200,0,0)';
ctx.fillRect(10, 10, 55, 50);
ctx.fillStyle = 'rgba(0, 0, 200, 0.5)';
ctx.fillRect(30, 30, 55, 50);
}
}
registerPaint('squares', SquaresPainter);
// checkerboard.js from https://developers.google.com/web/updates/2018/01/paintapi
class CheckerboardPainter {
// inputProperties returns a list of CSS properties that this paint function gets access to
static get inputProperties() {
return ['--checkerboard-spacing', '--checkerboard-size'];
}
paint(ctx, geom, properties) {
// Paint worklet uses CSS Typed OM to model the input values.
// As of now, they are mostly wrappers around strings,
// but will be augmented to hold more accessible data over time.
const size = parseInt(properties.get('--checkerboard-size').toString());
const spacing = parseInt(
properties.get('--checkerboard-spacing').toString()
);
const colors = ['red', 'green', 'blue'];
for (let y = 0; y < geom.height / size; y++) {
for (let x = 0; x < geom.width / size; x++) {
ctx.fillStyle = colors[(x + y) % colors.length];
ctx.beginPath();
ctx.rect(x * (size + spacing), y * (size + spacing), size, size);
ctx.fill();
}
}
}
}
registerPaint('checkerboard', CheckerboardPainter);
</script>
Related
I would like to clip an animated canvas as background to a <h1 />. The requirements are:
Use an actual <h1 /> tag instead of rendered heading in canvas.
Use of images to be rendered with ctx.drawImage().
h1 {
color: transparant;
background-image: <some-canvas>;
background-clip: text;
}
There are several approaches I've tried so far with varying success:
Creating a regular canvas and setting it as background of the <h1 />-tag using -webkit-canvas and -moz-element. This approach ticked all of my requirements but unfortunatly -webkit-canvas was deprecated along with document.getCSSCanvasContext("2d") in Chromium. Safari is the only working browser.
Using the CSS Paint API (Houdini). Using a requestAnimationFrame() to update a css var I can keep ticking the animation and do the animation I would like to implement. However, in Chromium, passing in images has to be done using a workaround (instead of creating a property of type image, images have to be passed in using background-image, making me unable to use the background-image to tell CSS Paint to use my worklet as background. The spec is not entirely implemented.
Creating an inline svg as background-image: url("data:image/svg+xml;utf8,<svg><foreignObject><canvas id='..'/></foreignObject></svg>"); and trying to update that canvas using requestAnimationFrame. Does not work at all.
Are there any other methods I could try?
If it doesn't have to be a background-image, you could put the canvas element inside the h1 element, match the canvas width and height to that of the h1 element, give it a lower z-index than the text in the h1 element so that it appears to be behind the text, acting like a background.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
/*
Set the dimensions of the canvas to
match the parent h1 element
----------------------------------------------------------*/
setCanvasSize();
// (and for demonstrative purposes, scale on window resize)
window.addEventListener('resize', setCanvasSize, false);
function setCanvasSize () {
var _w = canvas.parentNode.clientWidth;
var _h = canvas.parentNode.clientHeight;
canvas.width = _w;
canvas.height = _h;
canvas.style.width = "'" + _w + "px'";
canvas.style.height = "'" + _h + "px'";
}
/*--------------------------------------------------------*/
/*--------------------------------------------------------
All this code below is just a ball animation borrowed from MDN
to illustrate what I'm suggesting.
Source: MDN
https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Advanced_animations
*/
var raf;
var running = false;
var ball = {
x: 100,
y: 100,
vx: 5,
vy: 1,
radius: 50,
color: 'blue',
draw: function() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
}
};
function clear() {
ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
ctx.fillRect(0,0,canvas.width,canvas.height);
}
function draw() {
clear();
ball.draw();
ball.x += ball.vx;
ball.y += ball.vy;
if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
ball.vy = -ball.vy;
}
if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
ball.vx = -ball.vx;
}
raf = window.requestAnimationFrame(draw);
}
if (!running) {
raf = window.requestAnimationFrame(draw);
running = true;
}
ball.draw();
/*--------------------------------------------------------*/
h1 {
/* Important for positioning the span element */
position: relative;
/* Cosmetic/demonstrative */
border: 2px solid red;
height: 100%;
text-align: center;
color: red;
font-size: 32px;
font-family: Roboto,sans-serif;
margin: 0 auto;
}
h1 span {
/* Vertically and horizontally center the text */
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
/*
Text will appear above canvas as long as its
z-index > canvas' z-index
*/
z-index: 2;
}
h1 canvas {
/* this will make the canvas appear behind the text */
position: relative;
z-index: 1;
}
<h1>
<span>Lorem Ipsum etc.</span>
<canvas id="canvas"></canvas>
</h1>
Just a thought anyway, maybe you can try it out and expand on the idea to suit your needs. I'm not 100% sure what you're working on so apologies if it's not helpful.
I have a WEBGL canvas in which I am loading a 3d model. I also have a text in variable font which I create with createP. The problem is that I need the text to be between the background and the 3d model. But I can only have the text in front of the canvas (on top of 3d model). Is there any way I can achieve this?
Ps. Creating the text with text() does not allow me to have variable weight value.
let kalameh;
var cnv;
let img;
function preload(){
img = loadImage('assets/lines.png');
kalameh = loadModel('kalameh.obj');
}
function setup() {
cnv = createCanvas(700, 700, WEBGL);
var x = (windowWidth - width) / 2;
var y = (windowHeight - height) / 2;
cnv.position(x, y);
wordA = createP('my text');
}
function draw() {
background(220, 220, 220);
wordA.style('font-size', '110px');
wordA.style('font-weight', '200');
wordA.style('font-stretch', '200%');
wordA.style('align', 'center');
wordA.position(40,25);
image(img, -1*windowWidth/2, -1*windowHeight/2, windowWidth, windowHeight);
translate (0,0,100);
pointLight(255,255,255, -350,0,400);
pointLight(255,255,255, 350,0,400);
ambientMaterial(255);
noStroke();
scale (0.25);
model(kalameh);
}
You could create two sketches (and thus two canvases) and assign z-index properties of -1 and 1 to make them foreground and background sketches, respectively. You can then sandwich the paragraph element that you created between the two canvases by giving it a z-index of 0. You can then make the foreground sketch transparent by calling clear() at the beginning of the draw loop.
In the code snippet below, the 3D object is in front of the text paragraph, whereas the white square of the "background" is behind the text.
let testP;
new p5(function(p){
p.setup = function() {
const foregroundCanvas = p.createCanvas(400, 400, p.WEBGL);
foregroundCanvas.id("foregroundSketch");
foregroundCanvas.position(0, 0);
p.normalMaterial();
testP = p.createP("In front of background / behind object ")
testP.position(95, 115);
testP.id("sandwichedParagraph")
p.angleMode(p.RADIANS)
}
p.draw = function() {
p.clear();
//drag to move the world.
// p.orbitControl();
p.push();
let rotateAngle = p.sin(p.frameCount/50);
p.rotateX(rotateAngle/2);
p.rotateY(-rotateAngle);
p.rotateZ(rotateAngle);
p.box(200, 100, 40);
p.pop();
}
}, "foregroundSketch");
new p5(function(p){
p.setup = function() {
const backgroundCanvas = p.createCanvas(400, 400);
// backgroundCanvas.parent("wrapper")
backgroundCanvas.position(0, 0);
backgroundCanvas.id("backgroundSketch")
p.noStroke();
}
p.draw = function() {
p.background(200);
let shiftAmount = p.map(p.sin(p.frameCount/60), -1, 1, 80, 310);
p.rect(shiftAmount, 120, 40, 40);
}
}, "backgroundSketch");
html, body {
margin: 0;
padding: 0;
}
/* The sketch with the white square has z-index of -1 (background!) */
#backgroundSketch {
z-index: -1;
position: absolute;
}
/* The <p> has z-index of 0 (sandwiched between both sketches)*/
#sandwichedParagraph {
z-index: 0;
position: absolute;
}
/* The sketch with the object has z-index of 1 (foreground!)*/
#foregroundSketch {
z-index: 1;
position: absolute;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/addons/p5.sound.min.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
I'm working on a website and added a custom HTML block with HTML, CSS and JavaScript. But in the view page it remains behind another content. Don't know why this is happening.
Red arrow is the custom HTML
The custom HTML block inside wordpress
body {
background-color: #eee;
}
#canvas1{
background-color: #fff;
border: 1px solid #ccc;
}
.slider {
width: 400px;
color: #ccc;
}
.wrapper {
position:relative;
}
.wrapper > canvas,
.wrapper > input {
position:absolute;
left:50px;
top:50px;
}
.wrapper > input {
left:150px !important; /* places the slider */
top:450px;
}
<div class="wrapper">
<canvas id = 'canvas1' style="margin:0 auto;display:block;" width="600" height="500"><p>Your browser does not support html5 canvas.</p></canvas>
<input id="volume" class="slider" type=range min=0 max=199 value=0 oninput='realTime(this)'>
</div>
//in this instance, canvas1 is an 800x800 canvas element
var context = document.getElementById('canvas1').getContext('2d');
context.font = '16px Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif';
context.fillStyle = "#4D5C6D";
// a + b = width
var width = 200;
var focal = 0;
var timer = setInterval(function() {
drawEllipse(300, 250)
}, 100);
function realTime(obj) {
clearInterval(timer);
focal = obj.value;
drawEllipse(300, 250);
context.fillStyle = "#BBB";
context.fillRect(18, 145, 160, 20);
context.fillStyle = "#FFF";
context.fillText("Clique para reiniciar", 25, 160);
context.fillStyle = "#4D5C6D";
}
function drawEllipse(centerX, centerY) {
context.clearRect(0, 0, 600, 500);
var height = Math.sqrt((width * width) - (focal * focal));
var eccen = ((focal) / (width));
context.fillText("Excentricidade = " + eccen.toFixed(2), 20, 40);
context.fillText("Largura Focal = " + focal, 20, 70);
context.fillText("Maior Eixo = " + width, 20, 100);
context.fillText("Menor Eixo = " + height.toFixed(2), 20, 130);
context.fillRect(centerX - (focal / 2.0), centerY, 2, 2);
context.fillRect(centerX + (focal / 2.0), centerY, 2, 2);
volume.value = focal;
var a = width / 2.0;
var b = height / 2.0;
for (var t = 0; t < 360; t++) {
var theta = t * Math.PI / 180;
context.fillRect(centerX + a * Math.cos(theta), centerY + b * Math.sin(theta), 2, 2);
}
focal++;
if (focal >= 200) {
clearInterval(timer);
context.fillStyle = "#BBB";
context.fillRect(18, 145, 145, 20);
context.fillStyle = "#FFF";
context.fillText("Clique para repetir", 25, 160);
context.fillStyle = "#4D5C6D";
}
}
document.getElementById('canvas1').addEventListener('click', function() {
clearInterval(timer);
focal = 0;
timer = setInterval(function() {
drawEllipse(300, 250)
}, 50);
});
This HTML contains a simulation of the eccentricity of an ellipse.
I'm not sure what you want to achieve here.
I think if you want to choose which view is upon which view, try adding z-index to css styles. The higher z-index value, the upper the view will be.
Answer was given by Tim Wilson and Jeff Vdovjak. I just changed .wrapper > input to relative.
.wrapper > input {
position:relative;
Their answers:
Tim Wilson: What happens if you change the position of .wrapper > input to relative instead of absolute?
Jeff Vdovjak: Welcome to stackoverflow Felipe. Your .wrapper class has a position: absolute. So it breaks that content out of the page flow and puts it overtop of what is there. Try removing the absolute, and relying on the position: relative.**
Thank you guys!
Whilst learning, i keep going back over what i have done to understand it properly, make changes and improvements. At the moment, i am going over my hide/show function.
I have 3 buttons which controls the visibility of their respective canvases.
My code did look like this:
function toggleRedDot(){
document.getElementById('btnRed').click(); {
if(canvas.style.visibility=='hidden'){
canvas.style.visibility='visible';
btnRed.style.color='Red';
}else{
canvas.style.visibility='hidden';
btnRed.style.color='Black';
}
}
};
Both the Green and Blue toggle functions are identical except for the button color. My project actually has 7 buttons and canvases. I'm trying to put all these functions into 1, and this is now what i have:
function toggle_visibility(id)
{
var ele = document.getElementById(id);
if (ele.style.visibility == 'hidden')
{
ele.style.visibility = 'visible';
}
else
{
ele.style.visibility = 'hidden';
}
}
I have been unable to work out how to now change the corresponding button color attribute. The idea is that the button will look 'on' when canvas is visible and the color reverts to Black when 'off'.
I also need the answer to be in just javascript please, as this is what i am learning.
I am also hoping to do a similar sort of thing to my drawDots function as they also differ in class, and location. Thank you.
I made a snippet:
var canvas = document.getElementById('redDot');
var ctxR = canvas.getContext('2d');
var canvas1 = document.getElementById('greenDot');
var ctxG = canvas1.getContext('2d');
var canvas2 = document.getElementById('blueDot');
var ctxB = canvas2.getContext('2d');
var cw = canvas.width;
var ch = canvas.height;
drawDots();
function toggle_visibility(id) {
var ele = document.getElementById(id);
if (ele.style.visibility == 'hidden') {
ele.style.visibility = 'visible';
} else {
ele.style.visibility = 'hidden';
}
}
function drawDots() {
// Red Dot
ctxR.clearRect(0, 0, cw, ch);
ctxR.save();
ctxR.translate(cw / 2, ch / 2);
ctxR.beginPath();
ctxR.arc(-50, 0, 10, 0, 2 * Math.PI);
ctxR.closePath();
ctxR.fillStyle = 'Red';
ctxR.fill();
ctxR.restore();
// Green Dot
ctxG.clearRect(0, 0, cw, ch);
ctxG.save();
ctxG.translate(cw / 2, ch / 2);
ctxG.beginPath();
ctxG.arc(0, 0, 10, 0, 2 * Math.PI);
ctxG.closePath();
ctxG.fillStyle = 'Green';
ctxG.fill();
ctxG.restore();
// Blue Dot
ctxB.clearRect(0, 0, cw, ch);
ctxB.save();
ctxB.translate(cw / 2, ch / 2);
ctxB.beginPath();
ctxB.arc(50, 0, 10, 0, 2 * Math.PI);
ctxB.closePath();
ctxB.fillStyle = 'Blue';
ctxB.fill();
ctxB.restore();
};
#wrapper {
position: relative;
}
canvas {
position: absolute;
border: 1px solid red;
}
.red {
color: Red;
}
.green {
color: Green;
}
.blue {
color: Blue;
}
<div id="btnWrapper">
<button id="btnRed" class="red" title="Toggle Red Dot" onclick="toggle_visibility('redDot')">☉</button>
<button id="btnGreen" class="green" title="Toggle Green Dot" onclick="toggle_visibility('greenDot')">☉</button>
<button id="btnBlue" class="blue" title="Toggle Blue Dot" onclick="toggle_visibility('blueDot')">☉</button>
</div>
<div id="wrapper">
<canvas id="redDot" width="200" height="100"></canvas>
<canvas id="greenDot" width="200" height="100"></canvas>
<canvas id="blueDot" width="200" height="100"></canvas>
</div>
There are a variety of ways to approach this. The way I chose simply passes the id of the button along with the id of the canvas to toggle_visibility. I also added a small object so that the color for a button can be looked up via a button id.
Things to consider in the future:
Because DOM reads/writes are somewhat expensive, consider reading the DOM once and storing the elements on the JS side
Consider using addEventListener from JS instead of onclick in HTML
Your markup will be cleaner
You won't have to pass parameters like btnRed and redDot because event listeners receive an event which knows which element fired the event
Instead of manipulating the visibility/color directly in the JS, have a CSS class (or classes) that do what you want and just change the class.
Good luck! :)
var canvas = document.getElementById('redDot');
var ctxR = canvas.getContext('2d');
var canvas1 = document.getElementById('greenDot');
var ctxG = canvas1.getContext('2d');
var canvas2 = document.getElementById('blueDot');
var ctxB = canvas2.getContext('2d');
var cw = canvas.width;
var ch = canvas.height;
drawDots();
var buttonIdToColor = {
btnRed: 'red',
btnGreen: 'green',
btnBlue: 'blue'
};
function toggle_visibility(buttonId, dotId) {
var button = document.getElementById(buttonId)
var dot = document.getElementById(dotId);
if (dot.style.visibility == 'hidden') {
dot.style.visibility = 'visible';
button.style.color = buttonIdToColor[buttonId];
} else {
dot.style.visibility = 'hidden';
button.style.color = 'black';
}
}
function drawDots() {
// Red Dot
ctxR.clearRect(0, 0, cw, ch);
ctxR.save();
ctxR.translate(cw / 2, ch / 2);
ctxR.beginPath();
ctxR.arc(-50, 0, 10, 0, 2 * Math.PI);
ctxR.closePath();
ctxR.fillStyle = 'Red';
ctxR.fill();
ctxR.restore();
// Green Dot
ctxG.clearRect(0, 0, cw, ch);
ctxG.save();
ctxG.translate(cw / 2, ch / 2);
ctxG.beginPath();
ctxG.arc(0, 0, 10, 0, 2 * Math.PI);
ctxG.closePath();
ctxG.fillStyle = 'Green';
ctxG.fill();
ctxG.restore();
// Blue Dot
ctxB.clearRect(0, 0, cw, ch);
ctxB.save();
ctxB.translate(cw / 2, ch / 2);
ctxB.beginPath();
ctxB.arc(50, 0, 10, 0, 2 * Math.PI);
ctxB.closePath();
ctxB.fillStyle = 'Blue';
ctxB.fill();
ctxB.restore();
};
#wrapper {
position: relative;
}
canvas {
position: absolute;
border: 1px solid red;
}
.red {
color: Red;
}
.green {
color: Green;
}
.blue {
color: Blue;
}
<div id="btnWrapper">
<button id="btnRed" class="red" title="Toggle Red Dot" onclick="toggle_visibility('btnRed', 'redDot')">☉</button>
<button id="btnGreen" class="green" title="Toggle Green Dot" onclick="toggle_visibility('btnGreen', 'greenDot')">☉</button>
<button id="btnBlue" class="blue" title="Toggle Blue Dot" onclick="toggle_visibility('btnBlue', 'blueDot')">☉</button>
</div>
<div id="wrapper">
<canvas id="redDot" width="200" height="100"></canvas>
<canvas id="greenDot" width="200" height="100"></canvas>
<canvas id="blueDot" width="200" height="100"></canvas>
</div>
As you say there are more than 3 colours I have written an example that will simplify the creation of multiply buttons.
The buttons and canvases are uniquely identified by their colour so I use the colours to query the DOM for references and use a function closure (forEach callback function) to hold the references for when needed.
I would have actually created the buttons and canvas inside that function as well but you may want it in the html so there will still be so tedious markup to create when adding more buttons.
Rather than manipulate the element styles I have add the DOM classes, .black for the button, and .hide and .show for the canvas. So all that is needed is to set the element's class name rather than their styles. Will make it easier if you have a complicated set of styles to switch between.
"Red,Green,Blue".split(",").forEach((col,i)=>{
var col_l = col.toLowerCase();
var ctx = document.getElementById(col_l+ 'Dot').getContext('2d');
var btn = document.getElementById("btn"+col);
btn.title ="Toggle "+col +" Dot" ;
btn.className = col_l ;
ctx.canvas.className = "show";
var cw = ctx.canvas.width;
var ch = ctx.canvas.height;
ctx.clearRect(0, 0, cw, ch);
ctx.fillStyle = col;
ctx.beginPath();
ctx.arc(cw/2 -50 + i * 50, ch/2, 10, 0, 2 * Math.PI);
ctx.fill();
function toggle(){ // this function has closure over col_l ,ctx, and btn
if (ctx.canvas.className == 'hide') {
ctx.canvas.className = "show";
btn.className = col_l ;
}else{
ctx.canvas.className = "hide";
btn.className = "black";
}
}
btn.addEventListener("click",toggle);
});
#wrapper {
position: relative;
}
canvas {
position: absolute;
border: 1px solid red;
}
/* for canvas hide and show */
.hide {
visibility : hidden;
}
.show {
visibility : visible;
}
.red {
color: Red;
}
.green {
color: Green;
}
.blue {
color: Blue;
}
.black { /* "black" colour button */
color: Black;
}
<!-- removed most of the stuff that is better added in code. -->
<div id="btnWrapper">
<button id="btnRed">☉</button>
<button id="btnGreen">☉</button>
<button id="btnBlue">☉</button>
</div>
<div id="wrapper">
<canvas id="redDot" width="200" height="100"></canvas>
<canvas id="greenDot" width="200" height="100"></canvas>
<canvas id="blueDot" width="200" height="100"></canvas>
</div>
I have a canvas script, with a dynamic of data. I want to add a link to share the website to facebook:
https://gyazo.com/c1fd1fe956fddba27b48907dc0e9de0a
The icons are part of the image I have not generated them via canvas, now if I listen for a click for co-ords it won't work because it'll look for clicks on the first canvas part aswell.... How can I go about making those icons part of the image clickable....
Part that makes the menu:
ig.module("game.entities.gameover").requires("impact.entity", "game.entities.button-gameover").defines(function() {
var b = new ig.Timer;
EntityGameover = ig.Entity.extend({
size: {
x: 302,
y: 355
},
type: ig.Entity.TYPE.B,
animSheet: new ig.AnimationSheet("media/graphics/game/gameover.png", 301, 352),
zIndex: 900,
globalAlpha: 0.1,
closeDialogue: !0,
init: function(c, d, g) {
this.parent(c, d, g);
this.addAnim("idle", 1, [0]);
this.currentAnim = this.anims.idle;
this.tween({
pos: {
x: 89,
y: 120
}
}, 0.5, {
easing: ig.Tween.Easing.Back.EaseInOut
}).start();
this.storage = new ig.Storage;
this.storage.initUnset("highscore-CTF", 0);
this.storage.initUnset("highscore-CTF2", 0);
this.storage.initUnset("highscore-CTF3", 0);
ig.global.score > this.storage.get("highscore-CTF") ? (this.storage.set("highscore-CTF3", this.storage.get("highscore-CTF2")), this.storage.set("highscore-CTF2", this.storage.get("highscore-CTF")), this.storage.set("highscore-CTF", ig.global.score), this.storage.initUnset("highscore-CTF2", 0), this.storage.initUnset("highscore-CTF3", 0)) : ig.global.score > this.storage.get("highscore-CTF2") ?
(this.storage.set("highscore-CTF3", this.storage.get("highscore-CTF2")), this.storage.set("highscore-CTF2", ig.global.score), this.storage.initUnset("highscore-CTF2", 0), this.storage.initUnset("highscore-CTF3", 0)) : ig.global.score > this.storage.get("highscore-CTF3") && this.storage.set("highscore-CTF3", ig.global.score);
this.storage.initUnset("total-CTF", 0);
this.storage.set("total-CTF", this.storage.get("total-CTF") + ig.global.score);
ig.game.spawnEntity(EntityButtonGameover, 23, 700, {
buttonID: 1
});
ig.game.spawnEntity(EntityButtonGameover,
220, 700, {
buttonID: 2
});
ig.game.spawnEntity(EntityButtonGameover, 390, 700, {
buttonID: 3
});
b.set(0.3)
},
update: function() {
this.parent()
},
draw: function() {
this.ctx = ig.system.context;
this.closeDialogue ? (this.ctx.save(), this.ctx.fillStyle = "#000000", this.ctx.globalAlpha = this.globalAlpha, this.ctx.fillRect(0, 0, 480, 640), this.ctx.restore(), this.globalAlpha = 0.7 <= this.globalAlpha ? 0.7 : this.globalAlpha + 0.01) : this.closeDialogue || (this.ctx.save(), this.ctx.fillStyle = "#000000", this.ctx.globalAlpha = this.globalAlpha, this.ctx.fillRect(0,
0, 480, 640), this.ctx.restore(), this.globalAlpha = 0.1 >= this.globalAlpha ? 0 : this.globalAlpha - 0.05);
this.parent();
this.ctx.font = "30px happy-hell";
this.ctx.fillStyle = "#5b2a0b";
this.ctx.textAlign = "center";
this.ctx.fillText(_STRINGS.UI.Best, this.pos.x + 70, this.pos.y + 180);
this.ctx.fillText(_STRINGS.UI.Score, this.pos.x + 70, this.pos.y + 260);
//share
this.ctx.font = "30px happy-hell";
this.ctx.fillStyle = "#ffffff";
this.ctx.textAlign = "left";
this.ctx.fillText(this.storage.getInt("highscore-CTF"), this.pos.x + 140, this.pos.y + 180);
this.ctx.fillText(ig.global.score, this.pos.x + 140, this.pos.y + 260)
},
closeDialogueFunc: function() {
this.closeDialogue && (this.tween({
pos: {
x: 89,
y: -600
}
}, 0.5, {
easing: ig.Tween.Easing.Back.EaseInOut
}).start(), this.closeDialogue = !1)
}
})
});
A simple, versatile way to add menus to canvas graphics is to simply overlay an absolutely positioned DOM structure. Your browser has already all event handling build-in, there is no need to reinvent the wheel.
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgb(0, 155, 255)';
ctx.fillRect(0, 0, canvas.width, canvas.height)
#container {
position: relative;
display: inline-block;
}
#menu {
position: absolute;
text-align: center;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
#menu a {
padding: 15px;
font-size: 50px;
line-height: 100px;
color: black;
text-shadow: 2px 2px 5px white;
}
#menu a:hover {
color: white;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" />
<div id='container'>
<canvas id='canvas' width='400' height='100'></canvas>
<div id='menu'>
<a href='http://facebook.com'><i class='fa fa-facebook-official'></i></a>
<a href='http://twitter.com'><i class='fa fa-twitter'></i></a>
<a href='http://whatsapp.com'><i class='fa fa-whatsapp'></i></a>
</div>
</div>
Your browser is capable of rendering such overlay menus very quickly. You should use CSS to style your overlay menu links or buttons.
I have managed to click on a certain element in a canvas.
I have tried to explain with comments what it does.
I have made 3 limits as shown in the image below.
And I'm comparing only with x value, if it's in between these limits. It can be more complex so getCursorPosition() method returns an object with x and y components, just in case if you need to make more comparisons.
https://jsfiddle.net/_jserodio/asa10pye/
var canvas;
var ctx;
// first get your canvas
canvas = document.getElementById('canvas');
canvas.width = 253;
canvas.heigth = 68;
// assign the context
ctx = canvas.getContext("2d");
// asign click event to the canvas
addEventListener("click", listener, false);
function listener(e) {
// if you have 3 buttons
var position = getCursorPosition(e);
var limit1 = canvas.width / 3;
//console.log("limit1: " + limit1);
var limit2 = canvas.width * 2 / 3;
//console.log("limit2: " + limit2);
var limit3 = canvas.width;
//console.log("limit3: " + limit3);
if (position.x < limit1) {
console.log("go to facebook");
//window.open("http://www.facebook.com");
} else if (position.x < limit2) {
console.log("go to twitter");
//window.open("http://www.twitter.com");
} else if (position.x < limit3) {
console.log("go to whatsapp");
//window.open("http://www.whatsapp.com");
}
//console.log("\nx" + position.x);
//console.log("y" + position.y);
}
function getCursorPosition(event) {
var rect = canvas.getBoundingClientRect();
var x = event.clientX - rect.left;
var y = event.clientY - rect.top;
var data = {
x: x,
y: y
};
return data;
}
// load image from data url
var imageObj = new Image();
imageObj.onload = function() {
ctx.drawImage(this, 0, 0);
};
imageObj.src = 'https://justpaste.it/files/justpaste/d307/a11791570/file1.png';
<canvas id='canvas' width="253" height="68">
</canvas>
Bonus!
Here you have a demo I made using this. demo (Draughts/checkers).
You can check the entire code here if you want.
You have several operations in this case.
Option 1:
You'll need to remember the "bounding area" of the three buttons. Anytime the canvas receives a "click", get the click position (How do I get the coordinates of a mouse click on a canvas element?). Once you get the click position. Detect if said click occurs within the bounding area of the button. If it does, use window.open to go there.
Option 2: Similar to Option 1, but instead of remembering a "bounding area", create a separate hidden canvas of the same size as your image with the backgrounds black ('#000000') and the button given distinctive colors (for example, red for Facebook, green for Twitter, and blue for Hangout?).
Then, similar to Option 1, get the click position relative to the canvas. Then use ctx.getImageData(sx, sy, sw, sh) on the context of the hidden canvas layer. If the value you get back is red, then user clicked on Facebook, if green, Twitter, and if blue, Hangout.