I'm a newbie to HTML, CSS and JS. Currently I'm working on JavaScript to create a pie chart. My doubt is how can I include a CSS hover function within a function.
Can anyone help me include CSS hover inside a function in the JavaScript code below?
<script type="text/javascript">
function PieChart(id, o) {
this.includeLabels = true;
if (o.includeLabels == undefined) {
this.includeLabels = false;
}
else {
this.includeLabels = o.includeLabels;
}
this.data = o.data ? o.data : [30, 70, 45, 65, 20, 130];
this.labels = o.labels ? o.labels : ["First", "Second", "Third", "Fourth", "Fifth", "Sixth"];
this.colors = o.colors ? o.colors : [
["#bbddb3", "#1d8e04"], // green
["#e2f5b4", "#9edd08"], // yellow green
["#fdfbb4", "#faf406"], // yellow
["#fbd4b7", "#f2700f"], // orange
["#f8bdb4", "#ea2507"], // red
["#e2bcbd", "#9e2126"] // purple
];
this.canvas = document.getElementById(id);
}
PieChart.prototype = {
select: function(segment) {
var self = this;
var context = this.canvas.getContext("2d");
this.drawSegment(this.canvas, context, segment, this.data[segment], true, this.includeLabels);
},
draw: function() {
var self = this;
var context = this.canvas.getContext("2d");
for (var i = 0; i < this.data.length; i++) {
this.drawSegment(this.canvas, context, i, this.data[i], true, this.includeLabels);
}
},
drawSegment: function(canvas, context, i, size, isSelected, includeLabels) {
var self = this;
context.save();
var centerX = Math.floor(canvas.width / 2);
var centerY = Math.floor(canvas.height / 2);
radius = Math.floor(canvas.width / 2);
var startingAngle = self.degreesToRadians(self.sumTo(self.data, i));
var arcSize = self.degreesToRadians(size);
var endingAngle = startingAngle + arcSize;
context.beginPath();
context.moveTo(centerX, centerY);
context.arc(centerX, centerY, radius, startingAngle, endingAngle, false);
context.closePath();
isSelected ?
context.fillStyle = self.colors[i][1] :
context.fillStyle = self.colors[i][0];
context.fill();
context.restore();
if (includeLabels && (self.labels.length > i)) {
self.drawSegmentLabel(canvas, context, i, isSelected);
}
},
drawSegmentLabel: function(canvas, context, i, isSelected) {
var self = this;
context.save();
var x = Math.floor(canvas.width / 2);
var y = Math.floor(canvas.height / 2);
var angle = self.degreesToRadians(self.sumTo(self.data, i));
context.translate(x, y);
context.rotate(angle);
context.textAlign = 'center';
var fontSize = Math.floor(canvas.height / 25);
context.font = fontSize + "pt Helvetica";
var dx = Math.floor(canvas.width * 0.5) - 100;
var dy = Math.floor(canvas.height * 0.05);
context.fillText(self.labels[i], dx, dy+dy);
alert(self.labels[i]);
context.restore();
},
drawLabel: function(i) {
var self = this;
var context = this.canvas.getContext("2d");
var size = self.data[i];
self.drawSegmentLabel(this.canvas, context, i, size, true);
},
degreesToRadians: function(degrees) {
return (degrees * Math.PI)/180;
},
sumTo: function(a, i) {
var sum = 0;
for (var j = 0; j < i; j++) {
sum += a[j];
}
return sum;
}
}
</script>
create style element and write some style rules.
var styleEl = document.createElement('style');
styleEl.innerHTML = 'body{color:blue; ... other styles}';
document.head.appendChild(styleEl);
set cssText, new rules will rewrite olds;
document.body.style.cssText = 'color:#abcdef;';
set style dierectly
document.body.style.color = 'black';
there may be some other tricks.
I would recommend you start with jQuery as it is much easier to use than plain JavaScript and DOM manipulation.
Take a look at the hover event and the css() function.
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$("p").hover(function(){
$("p").css("color","red");
});
});
</script>
</head>
<body>
<p>This is a paragraph.</p>
</body>
</html>
Related
I have a canvas where I use "fillText" with a string, saying for example "stackoverflow". Then I read the imagedata of the canvas in order to pick out each pixel of that text.
I want to pick the following from the pixel: x position, y position and its color. Then I would like to loop over that array with those pixels so I can draw back the text pixel by pixel so I have full control of each pixel, and can for example animate them.
However, I dont get it as smooth as I want. Look at my attach image, and you see the difference between the top text and then the text I've plotted out using fillRect for each pixel. Any help on how to make the new text look like the "fillText" text does?
Thanks
UPDATE: Added my code
var _particles = [];
var _canvas, _ctx, _width, _height;
(function(){
init();
})();
function init(){
setupParticles(getTextCanvasData());
}
function getTextCanvasData(){
// var w = 300, h = 150, ratio = 2;
_canvas = document.getElementById("textCanvas");
// _canvas.width = w * ratio;
// _canvas.height = h * ratio;
// _canvas.style.width = w + "px";
// _canvas.style.height = h + "px";
_ctx = _canvas.getContext("2d");
_ctx.fillStyle = "rgb(0, 154, 253)";
// _ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
var str = "stackoverflow";
_ctx.font = "32px EB Garamond";
_ctx.fillText(str,0,23);
_width = _canvas.width;
_height = _canvas.height;
var data32 = new Uint32Array(_ctx.getImageData(0, 0, _width, _height).data.buffer);
var positions = [];
for(i = 0; i < data32.length; i++) {
if (data32[i] & 0xffff0000) {
positions.push({
x: (i % _width),
y: ((i / _width)|0),
});
}
}
return positions;
}
function setupParticles(positions){
var i = positions.length;
var particles = [];
while(i--){
var p = new Particle();
p.init(positions[i]);
_particles.push(p);
drawParticle(p);
}
}
function drawParticle(particle){
var x = particle.x;
var y = particle.y;
_ctx.beginPath();
_ctx.fillRect(x, y, 1, 1);
_ctx.fillStyle = 'green';
}
function Particle(){
this.init = function(pos){
this.x = pos.x;
this.y = pos.y + 30;
this.x0 = this.x;
this.y0 = this.y;
this.xDelta = 0;
this.yDelta = 0;
}
}
Here is an update to your code that reuses the alpha component of each pixel. There will still be some detail lost because we do not keep the antialiasing of the pixels (which in effect alters the actual color printed), but for this example the alpha is enough.
var _particles = [];
var _canvas, _ctx, _width, _height;
(function(){
init();
})();
function init(){
setupParticles(getTextCanvasData());
}
function getTextCanvasData(){
// var w = 300, h = 150, ratio = 2;
_canvas = document.getElementById("textCanvas");
// _canvas.width = w * ratio;
// _canvas.height = h * ratio;
// _canvas.style.width = w + "px";
// _canvas.style.height = h + "px";
_ctx = _canvas.getContext("2d");
_ctx.imageSmoothingEnabled= false;
_ctx.fillStyle = "rgb(0, 154, 253)";
// _ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
var str = "stackoverflow";
_ctx.font = "32px EB Garamond";
_ctx.fillText(str,0,23);
_width = _canvas.width;
_height = _canvas.height;
var pixels = _ctx.getImageData(0, 0, _width, _height).data;
var data32 = new Uint32Array(pixels.buffer);
var positions = [];
for(i = 0; i < data32.length; i++) {
if (data32[i] & 0xffff0000) {
positions.push({
x: (i % _width),
y: ((i / _width)|0),
a: pixels[i*4 + 3] / 255
});
}
}
return positions;
}
function setupParticles(positions){
var i = positions.length;
var particles = [];
while(i--){
var p = new Particle();
p.init(positions[i]);
_particles.push(p);
drawParticle(p);
}
}
function drawParticle(particle){
var x = particle.x;
var y = particle.y;
_ctx.beginPath();
_ctx.fillStyle = `rgba(0,128,0,${particle.alpha})`;
_ctx.fillRect(x, y, 1, 1);
}
function Particle(){
this.init = function(pos){
this.x = pos.x;
this.y = pos.y + 30;
this.x0 = this.x;
this.y0 = this.y;
this.xDelta = 0;
this.yDelta = 0;
this.alpha = pos.a;
}
}
<canvas id="textCanvas"></canvas>
I found the codes on codepen and modified as follow:
<canvas id="heatmap" width=300 height=150></canvas>
var canvas;
var context;
var screenH;
var screenW;
var circles = [];
var numcircles = 30;
$('document').ready(function() {
canvas = $('#heatmap');
screenH = canvas.height();
screenW = canvas.width();
canvas.attr('height', screenH);
canvas.attr('width', screenW);
context = canvas[0].getContext('2d');
for(var i = 0; i < numcircles; i++) {
var x = Math.round( Math.random() * screenW);
var y = Math.round( Math.random() * screenH);
var opacity = Math.random();
var circle = new Circle(x, y, opacity);
circles.push(circle);
}
drawCircles();
});
function drawCircles() {
var i = 0, me = this;
if (!circles.length) return;
(function loop() {
var circle = circles[i++];
circle.draw(context);
if (i < circles.length)
setTimeout(loop, 16);
})();
}
function Circle(x, y, opacity) {
this.x = parseInt(x);
this.y = parseInt(y);
this.opacity = opacity;
}
Circle.prototype.draw = function(){
context.save();
context.translate(this.x, this.y);
context.beginPath()
context.arc(0,0,Math.floor(Math.random() * (40 - 10) / 10) * 10 + 10,0,2*Math.PI);
context.closePath();
context.fillStyle = "rgba(25, 35, 50, " + this.opacity + ")";
context.shadowBlur = 5;
context.shadowColor = '#ffffff';
context.fill();
context.restore();
}
So I have 30 cirlces now. I like to have last 5 circles as red color.(25 as blue, 5 red)
context.fillStyle = "rgba(190, 60, 80, " + this.opacity + ")";
What is the best practice to achieve the goal?
There is never a best way to do anything. When you are pushing the circles you can just send in the style there instead just the opacity.
var circle = new Circle(x, y, i + 6 > numcircles ? "rgba(190, 60, 80, " + opacity + ")" : "rgba(25, 35, 50, " + opacity + ")");
var canvas;
var context;
var screenH;
var screenW;
var circles = [];
var numcircles = 30;
$('document').ready(function() {
canvas = $('#heatmap');
screenH = canvas.height();
screenW = canvas.width();
canvas.attr('height', screenH);
canvas.attr('width', screenW);
context = canvas[0].getContext('2d');
for (var i = 0; i < numcircles; i++) {
var x = Math.round(Math.random() * screenW);
var y = Math.round(Math.random() * screenH);
var opacity = Math.random();
var circle = new Circle(x, y, i + 6 > numcircles ? "rgba(190, 60, 80, " + opacity + ")" : "rgba(25, 35, 50, " + opacity + ")");
circles.push(circle);
}
drawCircles();
});
function drawCircles() {
var i = 0,
me = this;
if (!circles.length) return;
(function loop() {
var circle = circles[i++];
circle.draw(context);
if (i < circles.length)
setTimeout(loop, 16);
})();
}
function Circle(x, y, style) {
this.x = parseInt(x);
this.y = parseInt(y);
this.style = style;
}
Circle.prototype.draw = function() {
context.save();
context.translate(this.x, this.y);
context.beginPath()
context.arc(0, 0, Math.floor(Math.random() * (40 - 10) / 10) * 10 + 10, 0, 2 * Math.PI);
context.closePath();
context.fillStyle = this.style;
context.shadowBlur = 5;
context.shadowColor = '#ffffff';
context.fill();
context.restore();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id=heatmap width=300 height=150></canvas>
Start by modifying the Circle method so it accepts a color.
Then use that color, if set, in the draw function.
Now you can do new Circle(x, y, opacity, color); where the last argument is an optional color
var canvas;
var context;
var screenH;
var screenW;
var circles = [];
var numcircles = 30;
$(document).ready(function() {
canvas = $('#heatmap');
screenH = canvas.height();
screenW = canvas.width();
canvas.attr('height', screenH);
canvas.attr('width', screenW);
context = canvas[0].getContext('2d');
for (var i = 0; i < numcircles; i++) {
var x = Math.round(Math.random() * screenW);
var y = Math.round(Math.random() * screenH);
var opacity = Math.random();
var color = i > 24 ? '255,0,0' : null; // CHANGE COLOR AFTER 24 (RGB for red)
var circle = new Circle(x, y, opacity, color);
circles.push(circle);
}
drawCircles();
});
function drawCircles() {
var i = 0,
me = this;
if (!circles.length) return;
(function loop() {
var circle = circles[i++];
circle.draw(context);
if (i < circles.length)
setTimeout(loop, 16);
})();
}
function Circle(x, y, opacity, color) { // add color argument
this.x = parseInt(x);
this.y = parseInt(y);
this.opacity = opacity;
this.color = color; // set color
}
Circle.prototype.draw = function(color) {
context.save();
context.translate(this.x, this.y);
context.beginPath()
context.arc(0, 0, Math.floor(Math.random() * (40 - 10) / 10) * 10 + 10, 0, 2 * Math.PI);
context.closePath();
/* use color, if set*/
context.fillStyle = 'rgba(' + (this.color || '25, 35, 50') + ", " + this.opacity + ")";
context.shadowBlur = 5;
context.shadowColor = '#ffffff';
context.fill();
context.restore();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="heatmap" width="600" height="400"></canvas>
I am making a reproduction function to my game test. Inside my newly created function contains the new wolf function and subtracts the x value of the object then draws it to the canvas. The only problem is the page remains static and nothing moves. I used MDN for my research on creating new functions. Any help or feedback would be much appreciated! Heres my code
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var body = document.getElementById("body");
var wolfPop = 2;
var bornWolves = 0;
var wolves = {
};
var funs = {
};
var name;
var fname;
function setupWolf(x, y, w, h){
context.fillStyle = "blue";
context.fillRect(wolves[name].x, wolves[name].y, wolves[name].w, wolves[name].h);
context.fill();
console.log("alive wolves: " + bornWolves);
}
body.style.overflow = "hidden";
body.style.margin = "0px";
canvas.style.backgroundColor = "black";
setInterval(function(){
if(wolfPop != bornWolves){
spawnWolf();
bornWolves++;
}
}, 1);
function spawnWolf(){
name = "w" + bornWolves;
rand = Math.floor(Math.random() * 100) + 1;
wolves[name] = Object.create({}, {x: {value: Math.floor(Math.random() * 450) + 1}, y: {value: Math.floor(Math.random() * 450) + 1}, h: {value: 10}, w: {value: 10}});
setupWolf();
var f1 = createWolfMove();
f1();
}
function createWolfMove(){
console.log("called");
return new Function('var k = wolves[name]; setInterval(function(){ k.x -= 1; context.fillStyle = "cornflowerblue"; context.fillRect(k.x, k.y, k.w, k.h); context.fill();}, 100);');
}
<body id="body">
<canvas id="canvas" height="500px" width="500px"></canvas>
</body>
Youre probably looking for inheritance :
You could create new wolves that inherit from a wolf class:
//setup canvas
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var body = document.getElementById("body");
body.style.overflow = "hidden";
body.style.margin = "0px";
canvas.style.backgroundColor = "black";
var wolfPop = 2;
var bornWolves = 0;
var wolves = [];
function rand(a,b=1){return Math.floor(Math.random() * a) + b;}
//constructor
function Wolf(name,x,y,w,h){
//setup
this.name=name||" w"+bornWolves;
this.x=x||rand(450);
this.y=y||rand(450);
this.w=w||10;
this.h=h||10;
//update globals
wolves.push(this);
bornWolves++;
}
Wolf.prototype={
update:function(){
context.fillStyle = "blue";
context.fillRect(this.x, this.y, this.w, this.h);
},
moving:false,
move:function(){
this.x+=rand(100,-50);//move between 50 and -50
this.y+=rand(100,-50);/
}
};
setInterval(function(){
//clear
context.clearRect(0, 0, canvas.width, canvas.height);
//update all wolves
wolves.forEach(function(wolf){
if(wolf.moving) wolf.move();
wolf.update();
}
if(wolfPop != bornWolves){
new Wolf();
}
}, 1);
//add a new wolf
var first=new Wolf(false,false,20,20);// a bit fater
first.moving=true;
I'm trying to set up a background in canvas and have some small circles just flow throughout the background, eventually I'll change the shapes and add more details in, but I'm just having trouble with the set up.
I know my code is janky, but are there any suggestions to the structure of the code?
var dx = 1;
var dy = 2;
var circle=new Circle(400,30,10);
var timer;
function Circle(x,y,r){
this.x=x;
this.y=y;
this.r=r;
}
function init() {
// Get the canvas element.
canvas = document.getElementById("canvas");
if (canvas.getContext) {
ctx = canvas.getContext("2d");
ctx.fillStyle = "black";
}
timer=setInterval(draw, 10);
return timer;
}
function gradient (){
var my_gradient=ctx.createLinearGradient(0,0,1000,0);
my_gradient.addColorStop(0,"black");
my_gradient.addColorStop(1,"white");
ctx.fillStyle=my_gradient;
ctx.fillRect(0,0,1000,1000);
ctx.rect(0, 0, 1000, 1000);
stars();
}
function stars(){
for (i = 0; i <= 50; i++) {
// Get random positions for stars
var x = Math.floor(Math.random() * 1000)
var y = Math.floor(Math.random() * 1000)
ctx.fillStyle = "yellow";
//if (x < 30 || y < 30) ctx.fillStyle = "black";
ctx.beginPath();
ctx.arc(x, y, 3, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
}
}
function move(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = gradient.my_gradient;
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = "#003300";
drawBall(circle);
if (circle.x +dx > canvas.width || circle.x +dx < 0)
dx=-dx;
if(circle.y+dy>bar.y && circle.x>bar.x && circle.x<bar.x+barImg.width)
dy=-dy;
if (circle.y +dy > canvas.height || circle.y +dy < 0)
dy=-dy;
circle.x += dx;
circle.y += dy;
}
I tried to code a working exemple. Here stars are popping up continuously.
HTML
<!DOCTYPE html>
<html>
<head>
<title>Exemple</title>
</head>
<body>
<canvas id="viewport"></canvas>
<script src='test.js'></script>
</body>
</html>
JS
var doc = document;
var canvas = doc.getElementById('viewport');
var ctx = canvas.getContext('2d');
var settings = {
area : {
height : 100,
width : 100
}
};
canvas.width = settings.area.width;
canvas.height = settings.area.height;
function draw() {
for (var i = 10; i--;) {
var x = Math.floor(Math.random() * 1000)
var y = Math.floor(Math.random() * 1000)
ctx.beginPath();
ctx.arc(x, y, 3, 0, Math.PI * 2, true);
ctx.fillStyle = "yellow";
ctx.closePath();
ctx.fill();
}
}
function gameLoop (render, element) {
var running, lastFrame = +new Date;
function loop( now ) {
// stop the loop if render returned false
if ( running !== false ) {
requestAnimationFrame( loop, element );
running = render( now - lastFrame );
lastFrame = now;
}
}
loop( lastFrame );
}
gameLoop (function (deltaT) {
draw();
}, canvas );
Here is the fiddle : https://jsfiddle.net/q4q0uLht/
----- EDIT -----
/*
Basic config
*/
var doc = document,
canvas = doc.getElementById('viewport'),
ctx = canvas.getContext('2d');
var settings = {
canvas: {
height: 200,
width: 300
}
}
canvas.height = settings.canvas.height;
canvas.width = settings.canvas.width;
canvas.style.border = '1px #000 solid';
/*
easy gets a random number, inside a range of [0, x);
*/
function getRandomNumber(x) {
return parseInt(Math.random() * x, 10);
}
/*
Checks if the obj passed in argument is still in the canvas limits
*/
function incorrectPosition(obj) {
return obj.x < 0 || obj.y < 0 || obj.x > settings.canvas.width || obj.y > settings.canvas.height;
}
/*
stars array and Star object.
*/
var stars = [];
function Star(r) {
this.x = getRandomNumber(canvas.width);
this.y = getRandomNumber(canvas.height);
this.r = r || 10;
this.move = function(dx, dy) {
this.x += dx;
this.y += dy;
};
}
/*
This function adds new stars,
calculates new coordinates of each star,
and removes them from the stars array
when they are out of the canvas limits.
*/
function update() {
var len = stars.length;
if (len < 10) {
stars.push(new Star());
}
for (var i = len; i--;) {
var star = stars[i];
star.move(1, 2);
if (incorrectPosition(star)) {
stars.splice(i, 1);
}
}
}
/*
This function clears the canvas each turn and
draws each star which is stored inside the stores array.
*/
function draw() {
ctx.clearRect(0, 0, settings.canvas.width, settings.canvas.height);
var len = stars.length;
for (var i = len; i--;) {
var star = stars[i];
ctx.beginPath();
ctx.arc(star.x, star.y, 3, 0, Math.PI * 2, true);
ctx.fillStyle = "yellow";
ctx.closePath();
ctx.fill();
}
}
// Here is the loop inside which are called functions
setInterval(loop, 33);
function loop() {
update(); // update first
draw(); // then draw
}
<!DOCTYPE html>
<html>
<head>
<title>Exemple</title>
</head>
<body>
<canvas id="viewport"></canvas>
<script src='test.js'></script>
</body>
</html>
I made this (run snippet below)
var Canvas = document.getElementById('c');
var ctx = Canvas.getContext('2d');
var resize = function() {
Canvas.width = Canvas.clientWidth;
Canvas.height = Canvas.clientHeight;
};
window.addEventListener('resize', resize);
resize();
var elements = [];
var presets = {};
presets.shard = function (x, y, s, random, color) {
return {
x: x,
y: y,
draw: function(ctx, t) {
this.x += 0;
this.y += 0;
var posX = this.x + + Math.sin((50 + x + (t / 10)) / 100) * 5;
var posy = this.y + + Math.sin((55 + x + (t / 10)) / 100) * 7;
ctx.beginPath();
ctx.fillStyle = color;
ctx.moveTo(posX, posy);
ctx.lineTo(posX+random,posy+random);
ctx.lineTo(posX+random,posy+random);
ctx.lineTo(posX+0,posy+50);
ctx.closePath();
ctx.fill();
}
}
};
for(var x = 0; x < Canvas.width; x++) {
for(var y = 0; y < Canvas.height; y++) {
if(Math.round(Math.random() * 60000) == 1) {
var s = ((Math.random() * 5) + 1) / 10;
if(Math.round(Math.random()) == 1){
var random = Math.floor(Math.random() * 100) + 10;
var colorRanges = ['#8c8886', '#9c9995'];
var color = colorRanges[Math.floor(Math.random() * colorRanges.length)];
elements.push(presets.shard(x, y, s, random, color));
}
}
}
}
setInterval(function() {
ctx.clearRect(0, 0, Canvas.width, Canvas.height);
var time = new Date().getTime();
for (var e in elements)
elements[e].draw(ctx, time);
}, 10);
<canvas id="c" width="1000" height="1000"\>
I just need to add one feature to be able to use it on the site I'm building it for. Some of the floating shards need to be blurred to give a sense of depth.
Can Canvas do this, and if so, how?
context.filter = 'blur(10px)';
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/filter
I used this few months ago, maybe it could work for you as well :
var canvas = document.getElementById("heroCanvas");
var canvasContext = canvas.getContext("2d");
var canvasBackground = new Image();
canvasBackground.src = "image.jpg";
var drawBlur = function() {
// Store the width and height of the canvas for below
var w = canvas.width;
var h = canvas.height;
// This draws the image we just loaded to our canvas
canvasContext.drawImage(canvasBackground, 0, 0, w, h);
// This blurs the contents of the entire canvas
stackBlurCanvasRGBA("heroCanvas", 0, 0, w, h, 100);
}
canvasBackground.onload = function() {
drawBlur();
}
Here the source : http://zurb.com/playground/image-blur-texture