Skip to content

Instantly share code, notes, and snippets.

@john4
Last active November 12, 2015 20:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save john4/a94884f618a8813d414c to your computer and use it in GitHub Desktop.
Save john4/a94884f618a8813d414c to your computer and use it in GitHub Desktop.
MiMedia.com Bubble Canvas
import ViewModel from "../core/view-model";
import Circle from "../core/circle";
export default class Canvas extends ViewModel {
constructor() {
super();
const desktopData = [
{size: 20, fx: "left", x: 250, fy: "top", y: 240, color: "rgba(105, 201, 193, .5)"},
{size: 70, fx: "left", x: 200, fy: "top", y: 120, color: "rgba(30, 129, 127, .5)"},
{size: 130, fx: "left", x: 70, fy: "top", y: 40, color: "rgba(60, 181, 144, .5)"},
{size: 50, fx: "left", x: 70, fy: "top", y: 170, color: "rgba(192, 220, 104, .5)"},
{size: 90, fx: "left", x: -15, fy: "top", y: 170, color: "rgba(142, 195, 112, .5)"},
{size: 10, fx: "left", x: 30, fy: "top", y: 270, color: "rgba(217, 183, 75, .5)"},
{size: 190, fx: "right", x: 150, fy: "top", y: 130, color: "rgba(107, 212, 194, .5)"},
{size: 14, fx: "right", x: -150, fy: "top", y: 290, color: "rgba(192, 220, 104, .5)"},
{size: 14, fx: "left", x: 110, fy: "top", y: 900, color: "rgba(60, 181, 144, .5)"},
{size: 70, fx: "left", x: 15, fy: "top", y: 1100, color: "rgba(192, 220, 104, .5)"},
{size: 30, fx: "left", x: 65, fy: "top", y: 1050, color: "rgba(217, 183, 75, .5)"},
{size: 55, fx: "right", x: -15, fy: "top", y: 1300, color: "rgba(192, 231, 109, .5)"},
{size: 240, fx: "left", x: 220, fy: "bottom", y: -320, color: "rgba(107, 212, 194, .5)"},
{size: 180, fx: "left", x: 100, fy: "bottom", y: -340, color: "rgba(42, 148, 132, .5)"},
{size: 160, fx: "left", x: 260, fy: "bottom", y: -180, color: "rgba(192, 220, 104, .5)"},
{size: 110, fx: "left", x: 430, fy: "bottom", y: -320, color: "rgba(217, 183, 75, .5)"},
{size: 50, fx: "left", x: 580, fy: "bottom", y: -500, color: "rgba(192, 231, 109, .5)"},
{size: 15, fx: "left", x: 40, fy: "bottom", y: -620, color: "rgba(217, 183, 75, .5)"},
{size: 110, fx: "right", x: -600, fy: "bottom", y: -310, color: "rgba(105, 201, 193, .5)"},
{size: 20, fx: "right", x: -630, fy: "bottom", y: -540, color: "rgba(60, 181, 144, .5)"},
{size: 22, fx: "right", x: -500, fy: "bottom", y: -480, color: "rgba(192, 231, 109, .5)"},
{size: 22, fx: "right", x: -340, fy: "bottom", y: -700, color: "rgba(192, 231, 109, .5)"},
{size: 180, fx: "right", x: 0, fy: "bottom", y: -330, color: "rgba(107, 212, 194, .5)"},
{size: 110, fx: "right", x: 85, fy: "bottom", y: -300, color: "rgba(42, 148, 132, .5)"},
{size: 120, fx: "right", x: -15, fy: "bottom", y: -470, color: "rgba(192, 220, 104, .5)"},
{size: 90, fx: "right", x: -150, fy: "bottom", y: -400, color: "rgba(217, 183, 75, .5)"}
];
const mobileData = [
{size: 20, fx: "right", x: -40, fy: "top", y: 690, color: "rgba(30, 129, 127, .5)"},
{size: 130, fx: "right", x: -50, fy: "top", y: 470, color: "rgba(60, 181, 144, .5)"},
{size: 50, fx: "right", x: -70, fy: "top", y: 360, color: "rgba(192, 220, 104, .5)"},
{size: 90, fx: "right", x: 15, fy: "top", y: 370, color: "rgba(142, 195, 112, .5)"},
{size: 180, fx: "left", x: 0, fy: "bottom", y: -330, color: "rgba(107, 212, 194, .5)"},
{size: 110, fx: "left", x: -85, fy: "bottom", y: -300, color: "rgba(42, 148, 132, .5)"},
{size: 120, fx: "left", x: 15, fy: "bottom", y: -470, color: "rgba(192, 220, 104, .5)"},
{size: 90, fx: "left", x: 150, fy: "bottom", y: -400, color: "rgba(217, 183, 75, .5)"},
{size: 170, fx: "right", x: 20, fy: "bottom", y: -60, color: "rgba(105, 201, 193, .5)"},
{size: 50, fx: "right", x: -20, fy: "bottom", y: -600, color: "rgba(192, 231, 109, .5)"},
{size: 20, fx: "right", x: -80, fy: "bottom", y: -650, color: "rgba(60, 181, 144, .5)"},
{size: 90, fx: "right", x: -150, fy: "bottom", y: -70, color: "rgba(217, 183, 75, .5)"},
{size: 110, fx: "right", x: -70, fy: "bottom", y: -200, color: "rgba(192, 220, 104, .5)"}
];
const ctx = this.instantiateCanvas();
let circles = [];
if (this.isMobile()) {
circles = this.instantiateCircles(mobileData);
} else {
circles = this.instantiateCircles(desktopData);
}
window.addEventListener("resize", () => {
this.resizeCanvas(ctx);
this.step(circles, ctx);
});
this.resizeCanvas(ctx);
// TweenLite.ticker.addEventListener("tick", this.draw(circles, ctx));
TweenLite.ticker.addEventListener("tick", () => { this.draw(circles, ctx); });
this.step(circles, ctx);
}
instantiateCanvas() {
const ctx = document.getElementById("canvas").getContext("2d");
ctx.globalCompositeOperation = "destination-over";
return ctx;
}
instantiateCircles(data) {
const circles = [];
// Instantiate circles
for (let i = 0; i < data.length; i++) {
const newCircle = new Circle();
newCircle.color = data[i].color;
newCircle.radius = data[i].size;
newCircle.fixedX = data[i].fx;
newCircle.fixedY = data[i].fy;
newCircle.scale = 1.0;
newCircle.setOriginalPosition(data[i].x, data[i].y);
circles.push(newCircle);
}
return circles;
}
step(circles, ctx) {
// Wiggle circles
for (const i in circles) {
this.wiggleCircle(circles[i], ctx);
}
}
wiggleCircle(circle) {
if (circle.isWiggling) {
const tweenProperties = [
{
name: "scale",
min: 0.93,
max: 1
}, {
name: "x",
min: circle.x - 12,
max: circle.x + 12
}, {
name: "y",
min: circle.y - 12,
max: circle.y + 12
}];
this.wiggleProperties(circle, tweenProperties);
}
}
wiggleProperties(obj, properties) {
const duration = Math.random() * 4 + 1.5;
const tweenOptions = {
ease: Power1.easeInOut,
onComplete: () => { this.wiggleProperties(obj, properties); }
};
for (const i in properties) {
const property = properties[i];
tweenOptions[property.name] = Math.random() * (property.max - property.min) + property.min;
}
TweenLite.to(obj, duration, tweenOptions);
}
draw(circles, ctx) {
const canvasEl = ctx.canvas;
// Clear canvas
ctx.clearRect(0, 0, canvasEl.clientWidth, canvasEl.clientHeight);
// Draw circles
for (const i in circles) {
this.drawCircle(circles[i], ctx);
}
}
drawCircle(circle, ctx) {
const rad = circle.calculateRadius();
const pos = circle.calculateRelativePosition(ctx);
ctx.beginPath();
ctx.arc(pos.x, pos.y, rad, 0, 2 * Math.PI, false);
ctx.fillStyle = circle.color;
ctx.fill();
}
resizeCanvas(ctx) {
const wrapperEl = document.getElementById("canvas__wrapper");
ctx.canvas.height = wrapperEl.clientHeight;
ctx.canvas.width = wrapperEl.clientWidth;
}
destroy() {
super.destroy();
}
}
export default class circle {
constructor(color, radius) {
this.color = color;
this.radius = radius;
this.fixedX = "left";
this.fixedY = "top";
this.scale = 1;
this.isWiggling = true;
}
setOriginalPosition(x, y) {
// Origin coordinates should be set as pixels
// These coordinates will be intreprested through the lens of where this
// object is fixed.
this.origin = {x, y};
this.x = x;
this.y = y;
}
calculateRelativePosition(ctx) {
// This will return the calculated position of this object within the
// given canvas context based on where this object is fixed.
const height = ctx.canvas.height;
const width = ctx.canvas.width;
const pos = {
x: this.x,
y: this.y
};
if (this.fixedX === "right") {
pos.x += width;
}
if (this.fixedY === "bottom") {
pos.y += height;
}
return pos;
}
calculateRadius() {
return this.radius * this.scale;
}
}
@john4
Copy link
Author

john4 commented Nov 12, 2015

This is stripped directly out of our environment for the site, and so will be missing plenty of dependencies such as our ViewModel that Canvas extends. Use this as guidance or inspiration.

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