How to fill a shape gradually? - animation

I am looking for a feasible solution for this easeljs application of mine I've created. I want to fill color gradually(dynamically) in the parts of this shape with the help of easeljs only so that it will look like I'm filling the fuel tank.
function tankInit() {
var x = 100;
var y = 20;
var width = 120;
var height = 210;
var stage = new createjs.Stage("fuelTank");
stage.scaleX = 1.2;
stage.scaleY = 1.2;
var rectangle1 = new createjs.Shape();
rectangle1.graphics.beginLinearGradientFill(["#00abe5","#005f7f"], [0.2, 0.8], x/8, y/2, x, y/2).drawRect(x, 210 , -height, 15);
stage.addChild(rectangle1);
var ellipse1 = new createjs.Shape();
// ellipse1.graphics.beginStroke("#C0C0C0");
ellipse1.graphics.beginLinearGradientFill(["#939393","#d3d3d3"], [0.8, 0.2], 7*x/4, x, x, x).drawEllipse(x, 55, width, 2*height / 24);
// ellipse1.graphics.endStroke();
stage.addChild(ellipse1);
ellipse1.graphics.moveTo(x, y + height / 8);
ellipse1.graphics.lineTo(x, y + 7 * height / 8);
ellipse1.graphics.moveTo(x, y + height / 8);
ellipse1.graphics.lineTo(x, y + 7 * height / 8);
var ellipse2 = new createjs.Shape();
ellipse2.graphics.beginLinearGradientFill(["#0098cc","#005f7f"], [0.2, 0.8], 7*x/5, y, 7*x/10, x).drawEllipse(x, 210, width, 2*height / 11);
stage.addChild(ellipse2);
var rectangle2 = new createjs.Shape();
rectangle2.graphics.beginLinearGradientFill(["#bdbdbd","#939393"], [0.7, 0.3], 2*x, x, y, 2*y).drawRect(x, 66, width, height / 6);
stage.addChild(rectangle2);
var rectangle3 = new createjs.Shape();
rectangle3.graphics.beginLinearGradientFill(["#005f7f","#0098cc"], [0.7, 0.3], 2*x, 2*y, y, 2*y).drawRect(x, 100, width, 130);
stage.addChild(rectangle3);
var rectangle4 = new createjs.Shape();
/*rectangle4.graphics.beginLinearGradientFill(["#0098cc","#00abe5"], [0.7, 0.3], x/2, y/4, x/4, y/6)*/
/*rectangle4.graphics.beginLinearGradientFill(["#FFFFFF", "#0098cc", "#FFFFFF"], [0.2, 0.6, 0.2], [0, 127, 255], 120 , y, x, y).drawRect(x+width, 95, 122, 15);*/
rectangle4.graphics.beginLinearGradientFill(["rgba(255,255,255,0)", "rgba(0,133,178,1)","rgba(255,198,255,0)"], [0.1,0.7, 0.3], 0, 50, 0, 130).drawRect(x+width, 95, 122, 15);
stage.addChild(rectangle4);
stage.update();
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script src="https://code.createjs.com/easeljs-0.8.1.min.js"></script>
<title>Fuel Tank HTML5 Canvas</title>
<head>
<body onload="tankInit();">
<canvas id="fuelTank" width="1000" height="1000" ></canvas>

You can do this by simply animating the height of your "fluid" over time. The easiest way would be by using TweenJS to tween the scaleY property. See this demo for an implementation example:
http://jsfiddle.net/sud05dp5/

Related

why doesn't d3-geo-zoom pan correctly for more then 1 canvas elements on the page?

When panning in the first canvas, things work like expected. When panning in the second canvas, it doesn't work like expected. I expected both to work the same. The second globe spins rapidly after a little bit of panning, the first globe keeps the cursor on the same coordinates.
https://codepen.io/tonytrupe/pen/jOqjGvE
class UI {
constructor(canvas) {
var width = canvas.width,
height = canvas.height;
//set projection type here, geoOrthographic, geoWinkel3
var projection = d3
.geoWinkel3()
//.scale((Math.min(width, height)) / 2)
.translate([width / 2, height / 2])
//.rotate([0,0,0])
.fitExtent(
[
[6, 6],
[width - 6, height - 6]
],
{
type: "Sphere"
}
);
draw();
//this.addZoomPan = function () {
d3
.geoZoom()
.northUp(true)
.projection(projection)
.onMove(draw)(canvas);
//};
function draw() {
var ctx = canvas.getContext("2d");
var path = d3.geoPath().context(ctx).projection(projection);
// Store the current transformation matrix
ctx.save();
// Use the identity matrix while clearing the canvas
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Restore the transform
ctx.restore();
var border = {
type: "Sphere"
};
ctx.beginPath();
path(border);
ctx.strokeStyle = "#000";
ctx.stroke();
var lat = 45;
var lon = 45;
var graticule = d3.geoGraticule().step([lat, lon]);
ctx.beginPath();
path(graticule());
ctx.strokeStyle = "#000";
ctx.stroke();
}
}
}
//var one = new UI(document.getElementById("one"));
//var two = new UI(document.getElementById("two"));
var three = new UI(document.getElementById("three"));
html
<html>
<script src="//d3js.org/d3.v6.js"></script>
<script src="//d3js.org/d3-geo.v2.min.js"></script>
<script src="//d3js.org/d3-geo-projection.v3.min.js"></script>
<script src="//unpkg.com/d3-geo-zoom"></script>
<!--removing all but the last canvas element makes things work as expected-->
<canvas id="one" class="canvas" width="320" height="200"></canvas>
<canvas id="two" class="canvas" width="320" height="200"></canvas>
<canvas id="three" class="canvas" width="320" height="200"></canvas>
</html>
https://github.com/vasturiano/d3-geo-zoom/issues/12
It previously wasn't getting pointer location relative to the node element. Now it is.
const pointers = d3Pointers(zoomEv, nodeEl);
https://github.com/vasturiano/d3-geo-zoom/blob/86da0d98f267a838a4715abec60e4a278ace2121/src/geoZoom.js#L59

In WebGL, can I use a matrix to draw an object offset in screen space?

I have a simple object that draws a 3d gizmo at 0, 0, 0. If the camera is centered on 0, 0, 0, then it draws the gizmo at the center of the screen.
I would like to "lift" this gizmo and render it at the bottom right of the screen in screen coordinates, without rotating it. Basically, I want the gizmo to show the rotation of the center of the screen without blocking the view and without having to focus on a specific point. So I want to do away with the model matrix, or something.
I got the following to work by translating the projection matrix:
this.gl.uniformMatrix4fv(this.modelMatrixUniform, false, modelMatrix);
this.gl.uniformMatrix4fv(this.viewMatrixUniform, false, viewMatrix);
const bottomRightMat = mat4.create();
mat4.translate(bottomRightMat, projectionMatrix, [5, -3, 0]);
this.gl.uniformMatrix4fv(this.projectionMatrixUniform, false, bottomRightMat);
this.gl.drawElements(this.gl.LINES, this.indexBuffer.getLength(), this.gl.UNSIGNED_SHORT, 0);
But the gizmo has been rotated into its new position. The red line should still point down and to the left, since that's the direction of the positive X axis at the center of the screen. Also, the numbers 5 and 3 are arbitrary, and I don't think they would work at different zooms or camera locations.
Is there a way to specify a matrix transform that takes the center of the screen and translates it in screen space?
One way would be to change the viewport when rendering that object.
// size of area in bottom right
const miniWidth = 150;
const miniHeight = 100;
gl.viewport(gl.canvas.width - miniWidth, gl.canvas.height - miniHeight, miniWidth, miniHeight);
// now draw. you'll need to zoom in, like set the camera closer
// or move the object closer or add a scale matrix after the projection
// matrix as in projection * scale * view * ...
you'll need a projection matrix that matches the aspect ratio of the new viewport and you'll either need to scale the object, put the camera closer, or add a 2D scale between the projection and view matrices.
Remember to put the viewport back to the full canvas to render the rest of the scene.
const vs = `
attribute vec4 position;
uniform mat4 u_worldViewProjection;
void main() {
gl_Position = u_worldViewProjection * position;
}
`;
const fs = `
precision mediump float;
void main() {
gl_FragColor = vec4(vec3(0), 1);
}
`
const gl = document.querySelector("canvas").getContext("webgl");
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
position: [
-1, -1, -1,
1, -1, -1,
1, 1, -1,
-1, 1, -1,
-1, -1, 1,
1, -1, 1,
1, 1, 1,
-1, 1, 1,
],
indices: {
numComponents: 2,
data: [
0, 1,
1, 2,
2, 3,
3, 0,
4, 5,
5, 6,
6, 7,
7, 4,
0, 4,
1, 5,
2, 6,
3, 7,
],
},
});
function render(time) {
time *= 0.001;
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
const fov = 90 * Math.PI / 180;
const zNear = 0.5;
const zFar = 100;
const projection = mat4.perspective(mat4.create(),
fov, gl.canvas.clientWidth / gl.canvas.clientHeight, zNear, zFar);
const eye = [0, 0, 10];
const target = [0, 0, 0];
const up = [0, 1, 0];
const view = mat4.lookAt(mat4.create(), eye, target, up);
drawCube([-8, 0, 0], projection, view);
drawCube([-4, 0, 0], projection, view);
drawCube([ 0, 0, 0], projection, view);
drawCube([ 4, 0, 0], projection, view);
drawCube([ 8, 0, 0], projection, view);
const iconAreaWidth = 100;
const iconAreaHeight = 75;
gl.viewport(
gl.canvas.width - iconAreaWidth, 0,
iconAreaWidth, iconAreaHeight);
const iconProjection = mat4.perspective(mat4.create(),
fov, iconAreaWidth / iconAreaHeight, zNear, zFar);
// compute the zoom size need to make things the sngs
const scale = gl.canvas.clientHeight / iconAreaHeight;
mat4.scale(iconProjection, iconProjection, [scale, scale, 1]);
drawCube([ 0, 0, 0], iconProjection, view);
function drawCube(translation, projection, view) {
const viewProjection = mat4.multiply(mat4.create(), projection, view);
const world = mat4.multiply(
mat4.create(),
mat4.fromTranslation(mat4.create(), translation),
mat4.fromRotation(mat4.create(), time, [0.42, 0.56, 0.70]));
const worldViewProjection = mat4.multiply(mat4.create(), viewProjection, world);
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, {
u_worldViewProjection: worldViewProjection,
});
twgl.drawBufferInfo(gl, bufferInfo, gl.LINES);
}
requestAnimationFrame(render);
}
requestAnimationFrame(render);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; background: #CDE; }
<canvas></canvas>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix.js"></script>
Another is to compute an off center frustum projection matrix. Instead of mat4.perspective use mat4.frustum
function perspectiveWithCenter(
fieldOfView, width, height, near, far, centerX = 0, centerY = 0) {
const aspect = width / height;
// compute the top and bottom of the near plane of the view frustum
const top = Math.tan(fieldOfView * 0.5) * near;
const bottom = -top;
// compute the left and right of the near plane of the view frustum
const left = aspect * bottom;
const right = aspect * top;
// compute width and height of the near plane of the view frustum
const nearWidth = right - left;
const nearHeight = top - bottom;
// convert the offset from canvas units to near plane units
const offX = centerX * nearWidth / width;
const offY = centerY * nearHeight / height;
const m = mat4.create();
mat4.frustum(
m,
left + offX,
right + offX,
bottom + offY,
top + offY,
near,
far);
return m;
}
So to draw your gizmo set call something like
const gizmoCenterX = -gl.canvas.clientWidth / 2 + 50;
const gizmoCenterY = gl.canvas.clientHeight / 2 - 50;
const offsetProjection = perspectiveWithCenter(
fov, gl.canvas.clientWidth, gl.canvas.clientHeight, zNear, zFar,
gizmoCenterX, gizmoCenterY);
const vs = `
attribute vec4 position;
uniform mat4 u_worldViewProjection;
void main() {
gl_Position = u_worldViewProjection * position;
}
`;
const fs = `
precision mediump float;
void main() {
gl_FragColor = vec4(vec3(0), 1);
}
`
const gl = document.querySelector("canvas").getContext("webgl");
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
position: [
-1, -1, -1,
1, -1, -1,
1, 1, -1,
-1, 1, -1,
-1, -1, 1,
1, -1, 1,
1, 1, 1,
-1, 1, 1,
],
indices: {
numComponents: 2,
data: [
0, 1,
1, 2,
2, 3,
3, 0,
4, 5,
5, 6,
6, 7,
7, 4,
0, 4,
1, 5,
2, 6,
3, 7,
],
},
});
function perspectiveWithCenter(
fieldOfView, width, height, near, far, centerX = 0, centerY = 0) {
const aspect = width / height;
// compute the top and bottom of the near plane of the view frustum
const top = Math.tan(fieldOfView * 0.5) * near;
const bottom = -top;
// compute the left and right of the near plane of the view frustum
const left = aspect * bottom;
const right = aspect * top;
// compute width and height of the near plane of the view frustum
const nearWidth = right - left;
const nearHeight = top - bottom;
// convert the offset from canvas units to near plane units
const offX = centerX * nearWidth / width;
const offY = centerY * nearHeight / height;
const m = mat4.create();
mat4.frustum(
m,
left + offX,
right + offX,
bottom + offY,
top + offY,
near,
far);
return m;
}
function render(time) {
time *= 0.001;
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
const fov = 90 * Math.PI / 180;
const zNear = 0.5;
const zFar = 100;
const projection = perspectiveWithCenter(
fov, gl.canvas.clientWidth, gl.canvas.clientHeight, zNear, zFar);
const eye = [0, 0, 10];
const target = [0, 0, 0];
const up = [0, 1, 0];
const view = mat4.lookAt(mat4.create(), eye, target, up);
drawCube([-8, 0, 0], projection, view);
drawCube([-4, 0, 0], projection, view);
drawCube([ 0, 0, 0], projection, view);
drawCube([ 4, 0, 0], projection, view);
drawCube([ 8, 0, 0], projection, view);
const gizmoCenterX = -gl.canvas.clientWidth / 2 + 50;
const gizmoCenterY = gl.canvas.clientHeight / 2 - 50;
const offsetProjection = perspectiveWithCenter(
fov, gl.canvas.clientWidth, gl.canvas.clientHeight, zNear, zFar,
gizmoCenterX, gizmoCenterY);
drawCube([ 0, 0, 0], offsetProjection, view);
function drawCube(translation, projection, view) {
const viewProjection = mat4.multiply(mat4.create(), projection, view);
const world = mat4.multiply(
mat4.create(),
mat4.fromTranslation(mat4.create(), translation),
mat4.fromRotation(mat4.create(), time, [0.42, 0.56, 0.70]));
const worldViewProjection = mat4.multiply(mat4.create(), viewProjection, world);
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, {
u_worldViewProjection: worldViewProjection,
});
twgl.drawBufferInfo(gl, bufferInfo, gl.LINES);
}
requestAnimationFrame(render);
}
requestAnimationFrame(render);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; background: #CDE; }
<canvas></canvas>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix.js"></script>

How to draw this in html5 canvas?

How do I draw this in html5 canvas?
I can only do the rectangle with round corners part.
<canvas id="myCanvas" width="578" height="200"></canvas>
<script type="text/javascript">
function roundRect(x, y, w, h, radius)
{
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var r = x + w;
var b = y + h;
context.beginPath();
context.strokeStyle="green";
context.lineWidth="4";
context.moveTo(x+radius, y);
context.lineTo(r-radius, y);
context.quadraticCurveTo(r, y, r, y+radius);
context.lineTo(r, y+h-radius);
context.quadraticCurveTo(r, b, r-radius, b);
context.lineTo(x+radius, b);
context.quadraticCurveTo(x, b, x, b-radius);
context.lineTo(x, y+radius);
context.quadraticCurveTo(x, y, x+radius, y);
context.stroke();
}
roundRect(10, 10, 200, 100, 20);
</script>
If you prefer rounded corners there is a easier way: you may use the context method arcTo()For example to draw a rectangle with rounded corners you can write:
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
function roundRect(x, y, w, h, r){
var x0 = x, y0 = y;
var x1 = x0+w, y1 = y0;
var x2 = x1, y2 = y0+h;
var x3 = x, y3 = y2;
ctx.strokeStyle = "green";
ctx.lineWidth=4;
ctx.beginPath();
ctx.moveTo(x3,y3-r);
ctx.arcTo(x0,y0,x1,y1,r);
ctx.arcTo(x1,y1,x2,y2,r);
ctx.arcTo(x2,y2,x3,y3,r);
ctx.arcTo(x3,y3,x0,y0,r);
ctx.stroke();
}
roundRect(10, 10, 200, 100, 10);
<canvas id="myCanvas" width="578" height="200"></canvas>
However the image of the 2 rectangles may be done using 2 simple canvas rectangles and an SVG filter like this:
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(10, 10, 100, 100)
ctx.fillRect(100, 100, 30, 30)
canvas{filter: url(#goo);}
<svg width="1" height="1">
<defs>
<filter id="goo">
<feGaussianBlur in="SourceGraphic" stdDeviation="4" result="blur" />
<feColorMatrix in="blur" mode="matrix"
values="1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 40 -28" result="goo" />
</filter>
</defs>
</svg>
<canvas id="c" width="578" height="200"></canvas>
If you are not familiar with The Gooey Effect you may read this article: https://css-tricks.com/gooey-effect/
I hope this helps

How to set Text position steady?

With the help of TextGeometry, I am drawing text around meshes. PerspectiveCamera is in steady mode, My cube is moving itself in the scene. How can text take a look to the object rotation?
Check this I want to do like this same.
var storeCamera = new THREE.PerspectiveCamera(75, $domElement.innerWidth() / $domElement.innerHeight(), 1, 10000);
dist = (largestSide - 0) / 2 + (largestSide - 0) / (2 * Math.tan(storeCamera.fov * Math.PI / 360));
storeCamera.position.z = dist;
var axisHelperScene = new THREE.Scene();
var axisHelperCamera = new THREE.PerspectiveCamera(75, $domElement.find('.axis-helper').innerWidth() / $domElement.find('.axis-helper').innerHeight(), 1, 10000);
axisHelperCamera.position.z = 350;
var axisHelperRenderer = new THREE.WebGLRenderer({
antialias: true, alpha: true
});
axisHelperRenderer.setSize($domElement.find('.axis-helper').innerWidth(), $domElement.find('.axis-helper').innerHeight());
$domElement.find('.axis-helper').append(axisHelperRenderer.domElement);
var directionX = new THREE.Vector3(1, 0, 0);
var directionY = new THREE.Vector3(0, 0, -1);
var directionZ = new THREE.Vector3(0, 1, 0);
var origin = new THREE.Vector3(0, 0, 0);
var length = 150;
var color = 0x4a4f65;
var headLength = 45;
var headWidth = 30;
// creating axes
var arrowHelperX = new THREE.ArrowHelper(directionX, origin, length, color, headLength, headWidth);
arrowHelperX.line.material.linewidth = 4;
var arrowHelperY = new THREE.ArrowHelper(directionY, origin, length, color, headLength, headWidth);
arrowHelperX.line.material.linewidth = 4;
var arrowHelperZ = new THREE.ArrowHelper(directionZ, origin, length, color, headLength, headWidth);
arrowHelperX.line.material.linewidth = 4;
// origin sphere
var axisSphere = new THREE.Mesh(new THREE.SphereGeometry(15, 40, 40, 40),
new THREE.MeshLambertMaterial({ color: 0x4a4f65 }));
var axisGroup = new THREE.Group();
axisGroup.add(arrowHelperX);
axisGroup.add(arrowHelperY);
axisGroup.add(arrowHelperZ);
axisGroup.add(axisSphere);
axisGroup.rotation.x = 0.60;
axisGroup.rotation.y = -0.50;
// #region Adding axis labels
var fontLoader = new THREE.FontLoader();
var jsonFont = String.format("{0}Scripts/threejs/json/helvetiker_regular.typeface.json", GetResourceFromClient("RootUrl"));
fontLoader.load(jsonFont, function (theFont) {
var xLabel = new THREE.TextGeometry("X", {
font: theFont,
size: 35,
height: 10,
curveSegments: 12,
bevelThickness: 1,
bevelSize: 1,
bevelEnabled: true
});
var yLabel = new THREE.TextGeometry("Y", {
font: theFont,
size: 35,
height: 10,
curveSegments: 12,
bevelThickness: 1,
bevelSize: 1,
bevelEnabled: true
});
var zLabel = new THREE.TextGeometry("Z", {
font: theFont,
size: 35,
height: 10,
curveSegments: 12,
bevelThickness: 1,
bevelSize: 1,
bevelEnabled: true
});
var textMaterial = new THREE.MeshLambertMaterial({
color: 0x4a4f65
});
var xMesh = new THREE.Mesh(xLabel, textMaterial);
xMesh.position.x = 160;
xMesh.position.y = -10;
axisGroup.add(xMesh);
var yMesh = new THREE.Mesh(yLabel, textMaterial);
yMesh.position.x = -10;
yMesh.position.z = -160;
axisGroup.add(yMesh);
var zMesh = new THREE.Mesh(zLabel, textMaterial);
zMesh.position.x = -10;
zMesh.position.y = 160;
axisGroup.add(zMesh);
});
// #endregion Adding axis labels
function render() {
storeRenderer.render(storeScene, storeCamera);
axisHelperRenderer.render(axisHelperScene, axisHelperCamera);
requestAnimFrame(render);
}
Instead of using a TextGeometry for the axis labels a sprite could be an option
var xLabel = makeTextSprite(" X ", { fontsize: 100, borderColor: { r: 0, g: 0, b: 0, a: 1.0 }, backgroundColor: { r: 255, g: 255, b: 255, a: 0.8 } , borderThickness: 5});
xLabel.position.set(150, 0, 0);
axisGroup.add(xLabel);
// creates a THREE.Sprite object with the given text and parameters
function makeTextSprite(theMessage, theParameters) {
if (theParameters === undefined) theParameters = {
};
var fontface = theParameters.hasOwnProperty("fontface") ?
theParameters["fontface"] : "Arial";
var fontsize = theParameters.hasOwnProperty("fontsize") ?
theParameters["fontsize"] : 18;
var borderThickness = theParameters.hasOwnProperty("borderThickness") ?
theParameters["borderThickness"] : 4;
var borderColor = theParameters.hasOwnProperty("borderColor") ?
theParameters["borderColor"] : {
r: 0, g: 0, b: 0, a: 1.0
};
var backgroundColor = theParameters.hasOwnProperty("backgroundColor") ?
theParameters["backgroundColor"] : {
r: 255, g: 255, b: 255, a: 1.0
};
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.font = "Bold " + fontsize + "px " + fontface;
// get size data (height depends only on font size)
var metrics = context.measureText(theMessage);
var textWidth = metrics.width;
// background color
context.fillStyle = "rgba(" + backgroundColor.r + "," + backgroundColor.g + ","
+ backgroundColor.b + "," + backgroundColor.a + ")";
// border color
context.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + ","
+ borderColor.b + "," + borderColor.a + ")";
context.lineWidth = borderThickness;
roundRect(context, borderThickness / 2, borderThickness / 2, textWidth + borderThickness, fontsize * 1.4 + borderThickness, 6);
// 1.4 is extra height factor for text below baseline: g,j,p,q.
// text color
context.fillStyle = "rgba(0, 0, 0, 1.0)";
context.fillText(theMessage, borderThickness, fontsize + borderThickness);
// canvas contents will be used for a texture
var texture = new THREE.Texture(canvas)
texture.needsUpdate = true;
var spriteMaterial = new THREE.SpriteMaterial(
{
map: texture, useScreenCoordinates: false
});
var sprite = new THREE.Sprite(spriteMaterial);
sprite.scale.set(100, 50, 1.0);
return sprite;
}
// function for drawing rounded rectangles
function roundRect(ctx, x, y, w, h, r) {
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.lineTo(x + w - r, y);
ctx.quadraticCurveTo(x + w, y, x + w, y + r);
ctx.lineTo(x + w, y + h - r);
ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
ctx.lineTo(x + r, y + h);
ctx.quadraticCurveTo(x, y + h, x, y + h - r);
ctx.lineTo(x, y + r);
ctx.quadraticCurveTo(x, y, x + r, y);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
}

Animate (Oscillation) custom drawn shape on Canvas

Good day.
I am looking for abit of advice. Before judging, please take note I am new to coding, with only a few weeks of experience.
I am trying to make the cloud shape I have draw onto the canvas, animated, using JavaScript. (Please see link below to the type of animation I am looking to achieve.) I have searched everywhere for how to achieve this, but it seems all the links either deal with an actual image, or a rectangle, and not a custom drawn shape. So my question is this, is it possible to do such an animation on a custom shape, and, if not, what is the best way to go about it to achieve said desired effect.
<!DOCTYPE HTML>
<HTML>
<head>
<style>
body {
margin: 100px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="Canvas" width="700" height="600" style="border:1px solid #005BAB;"></canvas>
<script>
var canvas = document.getElementById('Canvas');
var context = canvas.getContext('2d');
// gradients
var grd = context.createRadialGradient(550, 150, 25, 500, 200, 400);
grd.addColorStop (0, '#0586f8');
grd.addColorStop (1, '#015baa');
// blue block shadow
context.shadowColor = '#999';
context.shadowBlur = 35;
context.shadowOffsetX = 8;
context.shadowOffsetY = 8;
context.globalCompositeOperation = 'source-over';
context.beginPath();
context.fill();
// blue block
context.beginPath();
context.moveTo(50, 35);
context.lineTo(50, 525);
context.lineTo(550, 525);
context.lineTo(550, 35);
context.closePath();
context.lineWidth = 0;
context.strokeStyle = '#999';
context.fillStyle = grd;
context.fill();
// cloud shadow
context.shadowColor = '#232323';
context.shadowBlur = 20;
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
context.beginPath();
context.globalAlpha = 0.9;
context.fill();
// cloud drawing
context.beginPath();
context.moveTo(172, 180);
context.bezierCurveTo(145, 180, 120, 234, 185, 240);
context.lineTo(375, 240);
context.bezierCurveTo(495, 234, 405, 110, 382, 168);
context.bezierCurveTo(440, 85, 280, 60, 325, 120);
context.bezierCurveTo(320, 42, 190, 60, 200, 120);
context.bezierCurveTo(120, 100, 140, 200, 170, 180);
context.lineWidth = 1;
context.fillStyle = 'white';
context.fill();
context.strokeStyle();
context.lineCap = 'round';
context.lineJoin = 'round';
context.stroke();
</script>
</body>
</HTML>
http://www.html5canvastutorials.com/advanced/html5-canvas-oscillation-animation/
You could create another canvas with javascript:
var cloud = document.createElement('canvas');
cloud.width = <width of the cloud>;
cloud.height = <height of the cloud>;
Then draw your cloud onto that canvas. You should adjust your coordinates so that the top left of the cloud's bounding box is at point (0, 0). This way the cloud canvas is only as big as it needs to be.
Then you can treat your cloud just like you would an image.
context.drawImage(cloud, 0, 0);

Resources