Created
July 20, 2023 10:11
-
-
Save Alikberov/0424b72e5c149bce3f8d3f4094648d23 to your computer and use it in GitHub Desktop.
Fantaseur - Quick Comic Generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<meta http-equiv='refresh' content='50'> | |
<title>Fantaseur</title> | |
<script> | |
class FANTASEUR extends HTMLCanvasElement { | |
constructor() { | |
super(); | |
var i; | |
this.fantaSeur = "v0.23.07.20"; | |
this.playing = false; | |
this.hour = 10; | |
this.month = 6; | |
this.bright = 100; | |
this.windy = -1; | |
this.actors = []; | |
this.replics = []; | |
this.clouds = []; | |
this.trees = []; | |
this.firstTime = new Date(); | |
this.ambient = 1; | |
this.speed = 5; | |
this.animate(); | |
} | |
addClouds(n) { | |
for(var i = 0; i < n; ++ i) | |
this.clouds.push(this.createCloud(Math.random() * 20, 1)); | |
} | |
addActors(n) { | |
for(var i = 0; i < n; ++ i) | |
this.actors.push(this.createActor()); | |
} | |
addTrees(n) { | |
for(var i = 0; i < n; ++ i) { | |
var tree = this.createCloud(15, 1); | |
tree.y = this.height * .25; | |
tree.curls += 5; | |
this.trees.push(tree); | |
} | |
} | |
animate() { | |
if(this.playing) { | |
this.drawSky(); | |
var blobs = []; | |
for(var cloud of this.clouds) | |
this.drawCloud(cloud, blobs); | |
for(var tree of this.trees) { | |
this.drawTree(tree); | |
this.drawBranch(this.height/2, 1, 6, tree.x, this.height-.99, tree.mask); | |
} | |
this.replics = []; | |
for(var actor of this.actors) | |
this.stickMan(actor, this.replics); | |
for(var cloud of this.replics) | |
this.drawCloud(cloud, blobs); | |
this.drawGrass(1); | |
this.hour = ((new Date() - this.firstTime) / (this.speed * 80)) % 24; | |
} | |
window.requestAnimationFrame(this.animate.bind(this)); | |
} | |
play(speed) { | |
this.playing = true; | |
if(speed && isFinite(speed)) | |
this.speed = Number(speed); | |
} | |
stop() { | |
this.playing = false; | |
} | |
createCloud(rainy, lighting, text) { | |
return { | |
x :Math.random() * this.width, | |
y :Math.random() * this.height / 10, | |
z :Math.random() * 0+1, | |
sailing :1, | |
leaving :1 / 100, | |
obese :(Math.random() + 1) * this.width / 12, | |
curls :Math.floor(Math.random() * 5) + 7, | |
stormy :rainy, | |
lighting:lighting, | |
tender :5, | |
dimple :10, | |
bubble :20, | |
mask :Math.floor(Math.random() * 65536) + 0x5AE9, | |
text :text || ""//"\tСегодня утром идёт дождь\tи дети прыгают по лужам" | |
}; | |
}; | |
drawSky() { | |
const ctx = this.getContext("2d"); | |
const hour = this.hour; | |
const month = this.month; | |
const bright = this.bright; | |
function gradient(from, last, seek) { | |
return { | |
r :from.r + (last.r - from.r) * seek, | |
g :from.g + (last.g - from.g) * seek, | |
b :from.b + (last.b - from.b) * seek | |
} | |
} | |
var seasons = [ | |
{ sky:{ day:{ r:224, g:240, b:255 }, night:{ r:32, g:48, b:128 }, morning:{ r:176, g:192, b:192 }, evening:{ r:192, g:160, b:128 } } } // winter | |
, { sky:{ day:{ r:240, g:248, b:248 }, night:{ r:48, g:64, b:128 }, morning:{ r:184, g:184, b:192 }, evening:{ r:160, g:192, b:128 } } } // spring | |
, { sky:{ day:{ r:255, g:255, b:224 }, night:{ r:64, g:96, b:128 }, morning:{ r:192, g:176, b:160 }, evening:{ r:192, g:160, b:128 } } } // summer | |
, { sky:{ day:{ r:248, g:255, b:240 }, night:{ r:48, g:64, b:128 }, morning:{ r:184, g:184, b:192 }, evening:{ r:192, g:128, b:96 } } } // autumn | |
]; | |
var sunrise = Math.sin((month + 2) * Math.PI / 12) * 2 + 4; | |
var sunset = Math.sin((month + 2) * Math.PI / 12) * 2 + 18; | |
var quarter = Math.floor((month + 11) % 12 / 3); | |
var quartnext = Math.floor(month % 12 / 3); | |
var zenith = (Math.sin((month - 1) * Math.PI / 12) + 1) * (this.height * 3 / 8); // Высота солнца в зените сезона | |
var sun_x = (Math.sin(hour * Math.PI / 12) + 1) * this.width / 2; | |
var sun_y = Math.cos(hour * Math.PI / 12) * zenith + this.height * 2 / 3; | |
var moon_x = (-Math.sin(hour * Math.PI / 12) + 1) * this.width / 2; | |
var moon_y = (-Math.cos(hour * Math.PI / 12) + 7 / 5) * this.width / 2; | |
var rgb, morning, day, evening, night, text, width; | |
var season = seasons[quarter]; | |
var seasonext = seasons[quartnext]; | |
morning = gradient(season.sky.morning, seasonext.sky.morning, (month + 11) % 3 / 3); | |
day = gradient(season.sky.day, seasonext.sky.day, (month + 11) % 3 / 3); | |
evening = gradient(season.sky.evening, seasonext.sky.evening, (month + 11) % 3 / 3); | |
night = gradient(season.sky.night, seasonext.sky.night, (month + 11) % 3 / 3); | |
if(hour > sunset || hour < sunrise) | |
rgb = night; | |
else { | |
rgb = day; | |
if(hour < sunrise + 2) // Два часа до утра | |
if(hour < sunrise + 1) // За час до рассвета | |
rgb = gradient(night, morning, (hour - sunrise)); | |
else // Утро переходит в день | |
rgb = gradient(morning, rgb, (hour - sunrise - 1)); | |
if(hour > sunset - 2) // Два часа до вечера | |
if(hour > sunset - 1) // Вечер переходит в ночь | |
rgb = gradient(evening, night, (hour - (sunset - 1))); | |
else // За час до заката | |
rgb = gradient(rgb, evening, (hour - (sunset - 2))); | |
} | |
//bright = 95; | |
rgb = gradient(night, rgb, bright / 100); | |
ctx.beginPath(); | |
ctx.fillStyle = "rgba("+[Math.floor(rgb.r), Math.floor(rgb.g), Math.floor(rgb.b)].join()+",100)"; | |
ctx.fillRect(0, 0, this.width, this.height); | |
this.ambient = Math.max(rgb.r, rgb.g, rgb.b) / 255; | |
ctx.closePath(); | |
ctx.beginPath(); | |
ctx.fillStyle = "white"; | |
ctx.ellipse(moon_x, moon_y, ctx.canvas.height / 16, ctx.canvas.height / 16, 0, Math.PI * 2, 0, false); | |
ctx.closePath(); | |
ctx.fill(); | |
ctx.beginPath(); | |
//ctx.strokeStyle = sun_y > 0 ? "rgba(64,64,"+Math.floor(92+bright)+",100)" : "rgba("+[r,g,b].join()+",100)"; | |
ctx.fillStyle = "rgba(" + [Math.floor(255*bright/100),Math.floor(255*bright/100),0*192*bright/100].join() + ",1)"; | |
ctx.ellipse(sun_x, sun_y, zenith / 6, zenith / 6, 0, Math.PI * 2, 0, false); | |
text = "" + (Math.floor(hour) % 24) + ":" + ("0" + (Math.floor(hour * 60) % 60)).substr(-2); | |
width = ctx.measureText(text); | |
ctx.textAlign = "center"; | |
if(hour < 5 || hour > 19) | |
ctx.strokeText(text, moon_x + width.width * Math.sin(hour * Math.PI / 12), moon_y); | |
else | |
ctx.strokeText(text, sun_x - width.width * Math.sin(hour * Math.PI / 12), sun_y + zenith / 5); | |
ctx.closePath(); | |
ctx.stroke(); | |
ctx.fill(); | |
return this; | |
} | |
drawCloud(cloud, blobs) { | |
var width, height, curls, faraway; | |
var font, rows, size, tail, text, author; | |
var tender, dimple, bubble; | |
var angle, turning, sprain; | |
var knot, knots = []; | |
var cx, cy, ascend; | |
var x1, y1; | |
var i, n; | |
var tmp; | |
var ctx = this.getContext("2d"); | |
faraway = 1; | |
text = cloud.text.length > 0 ? cloud.text.split(/\t+/) : []; | |
tail = 0; | |
ctx.save(); | |
if(text.length > 0) { | |
author = text.shift().replace(/((?:\s*)[A-ZА-ЯЁ])/g, " $1").trim(); | |
text = text.join("\t"); | |
while(text.match(/(\(.*\))/)) | |
text = text.substr(1, text.length - 1), | |
tail ++; | |
text = text.split(/\t/); | |
font = ctx.font; | |
width = 0; | |
for(rows = 0; rows < text.length; ++ rows) { | |
size = ctx.measureText(text[rows]).width; | |
if(width < size) | |
width = size; | |
} | |
size = parseInt(font, 10); | |
height = rows * size; | |
angle = Math.PI / 4; | |
width /= Math.sin(angle) * 2; | |
height /= Math.cos(angle) * 2; | |
curls = Math.floor(Math.sqrt(width + height)); | |
tender = 5, | |
dimple = 10, | |
bubble = 20; | |
/* if(cloud.x < width / 2) | |
cloud.x = width / 2, | |
cloud.sailing = Math.abs(cloud.sailing); | |
else | |
if(cloud.x > this.canvas.width - width / 2) | |
cloud.x = this.canvas.width - width / 2, | |
cloud.sailing = -Math.abs(cloud.sailing);*/ | |
cx = cloud.x, cy = cloud.y; | |
if(cloud.x - width < 0) | |
cx = width, | |
cloud.sailing = Math.abs(cloud.sailing); | |
else | |
if(cloud.x + width > this.width) | |
cx = this.width - width, | |
cloud.sailing = -Math.abs(cloud.sailing); | |
var b, bw = width + bubble, bh = height + bubble; | |
var dx, dy, dr, dr1, dr2; | |
if(blobs.length > 0) | |
for(tmp in blobs) { | |
b = blobs[tmp]; | |
dx = cx - b.x, dy = cy - b.y; | |
dr = Math.sqrt(dx * dx + dy * dy); | |
dr1 = Math.sqrt(b.w * b.w + b.h * b.h); | |
dr2 = Math.sqrt(bw * bw + bh * bh); | |
if(dr < (dr1 + dr2)) | |
cy += ((dr1 + dr2) - dr) * 4 / 9 * (Math.abs(dy) / dy); | |
} | |
blobs.push({x: cx, y: cy, w: width, h: height}); | |
} else | |
faraway += Math.log(1 + Math.abs(cloud.z)), | |
width = cloud.obese / faraway, | |
height = this.height / 48 / faraway, | |
curls = cloud.curls, | |
tender = cloud.tender / faraway, | |
dimple = cloud.dimple / faraway, | |
bubble = cloud.bubble / faraway, | |
cx = cloud.x, cy = cloud.y; | |
turning = 2 * Math.PI / curls; | |
sprain = turning / 3; | |
angle = -turning; | |
for(i = 0; i < curls; ++ i) { | |
angle += turning + (Math.random() * 2 - 1) * sprain / curls; | |
tmp = (angle * 180 / Math.PI + 360 + 60) % 360 > 90 ? 1 : 2 / 3; | |
knots.push({ | |
x1: Math.sin(angle + sprain) * (width + bubble * tmp + Math.random()), | |
y1: Math.cos(angle + sprain) * (height + bubble * tmp + Math.random()), | |
x2: Math.sin(angle + sprain*2) * (width + bubble * tmp + Math.random()), | |
y2: Math.cos(angle + sprain*2) * (height + bubble * tmp + Math.random()), | |
x3: Math.sin(angle + sprain*3) * (width + dimple + Math.random()), | |
y3: Math.cos(angle + sprain*3) * (height + dimple + Math.random()) | |
}); | |
} | |
ctx.beginPath(); | |
if(text.length > 0 && author != "") { | |
ctx.fillStyle = "rgba("+[Math.floor(255/(cloud.stormy/5+1)),Math.floor(255/(cloud.stormy/4+1)),255].join(",")+",1)"; | |
ctx.strokeStyle = "blue"; | |
ctx.lineWidth = 3 / faraway; | |
y1 = cy + knots[knots.length - 1].y2 + (cloud.z - cy) / 2; | |
x1 = knots[0].x1; | |
if(tail > 0) { | |
ascend = (cloud.z - cy + height) / tail, | |
cy += ascend * (tail - 1); | |
ctx.moveTo(cx + knots[knots.length - 1].x3 / tail, cy + knots[knots.length - 1].y3 / tail); | |
} else { | |
ctx.moveTo(cloud.x, cloud.z); | |
ascend = 0; | |
} | |
n = 1 + tail; | |
} else { | |
ctx.fillStyle = "rgba("+[Math.floor(255/(cloud.stormy/5+1)),Math.floor(255/(cloud.stormy/4+1)),255].join(",")+",1)"; | |
ctx.strokeStyle = "blue"; | |
ctx.lineWidth = 3 / faraway; | |
ctx.moveTo(cx + knots[i - 1].x3, cy + knots[i - 1].y3); | |
n = 1; ascend = 0; | |
} | |
while(n > 0) { | |
for(i = 0; i < knots.length; ++ i) { | |
knot = knots[i]; | |
ctx.bezierCurveTo(cx + knot.x1 / n, cy + knot.y1 / n, cx + knot.x2 / n, cy + knot.y2 / n, cx + knot.x3 / n, cy + knot.y3 / n); | |
} | |
ctx.closePath(); | |
if(n > 1) | |
ctx.fillStyle = "rgba(255,255,255," + (2 / n) + ")"; | |
ctx.fill(); | |
if(-- n > 0) { | |
cy -= ascend; | |
ctx.beginPath(); | |
ctx.moveTo(cx + knot.x3 / n, cy + knot.y3 / n); | |
} | |
} | |
ctx.stroke(); | |
if(cloud.stormy > 10) { // Rain | |
ctx.strokeStyle = "rgba(64,160,255," + Math.abs(cloud.stormy/100) + ")"; | |
ctx.lineWidth = 2 / faraway; | |
for(i = -5; i < 5; ++ i) { | |
ctx.setLineDash([Math.floor(Math.random() * 10), Math.floor(Math.random() * 10) | |
// , Math.floor(Math.random() * 10), Math.floor(Math.random() * 10) | |
// , Math.floor(Math.random() * 10), Math.floor(Math.random() * 10) | |
, Math.floor(Math.random() * 10), Math.floor(Math.random() * 10)]); | |
x1 = Math.random() + cx + width * i / 5; | |
ctx.beginPath(); | |
ctx.moveTo(x1, cy + height + Math.random() * height), | |
ctx.lineTo(x1 - 5 * cloud.sailing, this.height); | |
ctx.stroke(); | |
} | |
} else | |
if(cloud.stormy < 0) { // Snow | |
ctx.strokeStyle = "rgba(255,255,255," + Math.abs(cloud.stormy/100) + ")"; | |
ctx.lineWidth = 20 / faraway; | |
for(i = -5; i < 5; ++ i) { | |
ctx.setLineDash([Math.floor(Math.random() * 10), 5 + Math.floor(Math.random() * 10) | |
// , Math.floor(Math.random() * 10), 5 + Math.floor(Math.random() * 10) | |
// , Math.floor(Math.random() * 10), 5 + Math.floor(Math.random() * 10) | |
, Math.floor(Math.random() * 10), 5 + Math.floor(Math.random() * 10)]); | |
x1 = Math.random() + cx + width * i / 5; | |
ctx.beginPath(); | |
ctx.moveTo(x1, cy + height + Math.random() * height), | |
ctx.lineTo(x1 - 5 * cloud.sailing, this.height); | |
ctx.stroke(); | |
} | |
} | |
if(text.length > 0) { | |
if(author) | |
text.unshift(author), | |
ctx.font = "bold " + font; | |
else | |
ctx.font = "italic " + font; | |
cy -= (text.length - 1) * size / 2; | |
for(i = 0; i < text.length; ++ i) { | |
ctx.fillStyle = !i && author ? "magenta" : "black"; | |
ctx.beginPath(); | |
ctx.fillText(text[i], cx - ctx.measureText(text[i]).width / 2, cy); | |
cy += size; | |
if(author) | |
ctx.font = font; | |
ctx.stroke(); | |
} | |
ctx.font = font; | |
cy = cloud.z > 0 ? size * text.length * 10 : -size * text.length * 5; | |
if(!author) { | |
cloud.x += cloud.sailing; | |
cloud.y += (cy - cloud.y) / (cy > 0 ? 25 : 29); | |
if(cloud.z > 0 && (cy - cloud.y) < 10) | |
cloud.z = -cloud.z; | |
if(cloud.z < 0) | |
cloud.z ++; | |
} | |
} else | |
cloud.x += cloud.sailing / faraway, | |
cloud.z += cloud.leaving; | |
ctx.restore(); | |
} | |
drawGrass(rows) { | |
var x; | |
var ctx = this.getContext("2d"); | |
ctx.save(); | |
ctx.beginPath(); | |
while(rows -- > 0) { | |
ctx.moveTo(0, this.height - rows * 20); | |
for(x = 0; x <= this.width; x += 19) { | |
var x1 = x + 12 - 8 * Math.random(); | |
var x2 = x + 20 - 8 * Math.random(); | |
var x3 = x + 18 - 8 * Math.random(); | |
ctx.bezierCurveTo(x, this.height - rows * 20, x1, this.height - rows * 20, x2, this.height - 24 - rows * 20, x3, this.height - 24 - rows * 20); | |
ctx.bezierCurveTo(x3, this.height - 24 - rows * 20, x2, this.height - 16 - rows * 20, x1, this.height - rows * 20, x + 9, this.height - rows * 20); | |
} | |
ctx.fillStyle = "#8F8"; | |
ctx.strokeStyle = "#4C4"; | |
ctx.fill(); | |
ctx.stroke(); | |
} | |
ctx.restore(); | |
} | |
drawBranch(radius, fan, reps, x, y, mask) { | |
var turn = Math.PI / 3 / fan; | |
var ctx = this.getContext("2d"); | |
if(reps > 0 && isFinite(x)) { | |
this.drawBranch.path1 = mask || 65535 * Math.random() *1+0x5AE9; | |
this.drawBranch.path2 = ~this.drawBranch.path1 | 1; | |
ctx.save(); | |
ctx.translate(x, y); | |
ctx.beginPath(); | |
ctx.rotate(Math.PI); | |
ctx.moveTo(radius*2/3/16, 0); | |
this.drawBranch(radius*2/3, fan, -reps + 1-2); | |
ctx.lineTo(-radius*2/3/8, 0); | |
ctx.stroke(); | |
ctx.fillStyle = "rgba(" + Math.floor(this.ambient * 160) + ",0,0)"; | |
ctx.fill(); | |
ctx.restore(); | |
} else { | |
var flag; | |
ctx.save(); | |
if(++ reps < 0) { | |
ctx.translate(0, radius * (0.69 + Math.random() * 0.006)); | |
flag = this.drawBranch.path1 & 1; | |
this.drawBranch.path1 >>= 1; | |
if(flag) { | |
turn = -Math.PI / 180 * (50 + 2 * Math.random() / reps); | |
ctx.rotate(turn); | |
ctx.lineTo(radius / 8, 0); | |
this.drawBranch(radius / 2, fan, reps); | |
ctx.rotate(-turn); | |
} | |
ctx.translate(0, radius * (0.25 + Math.random() * 0.006)); | |
ctx.rotate(Math.PI / 180 * (50 + 2 * Math.random() / reps)); | |
flag = this.drawBranch.path2 & 1; | |
this.drawBranch.path2 >>= 1; | |
if(flag) { | |
if(reps < -2) | |
ctx.lineTo(radius / 16, 0); | |
this.drawBranch(radius / 2, fan, reps); | |
} | |
} | |
ctx.restore(); | |
//if(reps < -1) | |
ctx.lineTo(-radius / 8, radius / 4); | |
} | |
} | |
drawTree(props) { | |
var x = props.x + 0 * this.width * (0.5 + Math.cos(Math.PI * props.x / 180)); | |
var width, height, curls, faraway; | |
var font, rows, size, tail, text, author; | |
var tender, dimple, bubble; | |
var angle, turning, sprain; | |
var knot, knots = []; | |
var cx, cy, ascend; | |
var x1, y1; | |
var i, n; | |
var tmp; | |
var ctx = this.getContext("2d"); | |
ctx.save(); | |
faraway = 1; | |
n = 1; | |
tail = 0; | |
//faraway += Math.log(1 + Math.abs(props.z)), | |
props.obese = 112; | |
width = props.obese / faraway, | |
height = props.obese / faraway * 8 / 13, | |
curls = props.curls, | |
tender = props.tender / faraway, | |
dimple = props.dimple / faraway, | |
bubble = props.bubble / faraway*0+32, | |
cx = props.x+0*this.width / 2, cy = props.y + 160; | |
turning = 2 * Math.PI / curls; | |
sprain = turning / 3; | |
angle = -turning; | |
for(i = 0; i < curls; ++ i) { | |
angle += turning + (Math.random() * 2 - 1) * sprain / curls; | |
knots.push({ | |
x1: Math.sin(angle + sprain) * (width + bubble + Math.random()), | |
y1: Math.cos(angle + sprain) * (height + bubble + Math.random()), | |
x2: Math.sin(angle + sprain*2) * (width + bubble + Math.random()), | |
y2: Math.cos(angle + sprain*2) * (height + bubble + Math.random()), | |
x3: Math.sin(angle + sprain*3) * (width + dimple + Math.random()), | |
y3: Math.cos(angle + sprain*3) * (height + dimple + Math.random()) | |
}); | |
} | |
ctx.lineWidth = 5; | |
ctx.beginPath(); | |
while(n > 0) { | |
ctx.moveTo(cx + knots[0].x1, cy + knots[0].y1); | |
for(i = 0; i < knots.length; ++ i) { | |
knot = knots[i]; | |
ctx.bezierCurveTo(cx + knot.x1 / n, cy + knot.y1 / n, cx + knot.x2 / n, cy + knot.y2 / n, cx + knot.x3 / n, cy + knot.y3 / n); | |
} | |
ctx.closePath(); | |
if(n > 0) | |
ctx.fillStyle = "rgba(0," + Math.floor(this.ambient * 160) + ",0," + (2 / n) + ")", | |
ctx.strokeStyle = "rgba(0,64,0)"; | |
ctx.fill(); | |
if(-- n > 0) { | |
cy -= ascend; | |
ctx.beginPath(); | |
ctx.moveTo(cx + knot.x3 / n, cy + knot.y3 / n); | |
} | |
} | |
ctx.stroke(); | |
ctx.restore(); | |
} | |
drawFace(x, y, width, height, rotation, emoji, eyes) { | |
var ctx = this.getContext("2d"); | |
var tmp; | |
ctx.beginPath(); | |
ctx.save(); ctx.translate(x, y); ctx.rotate(rotation); ctx.scale(width, height); | |
ctx.arc(0, 0, 1, 0, Math.PI * 2, false); ctx.restore(); | |
ctx.stroke(); ctx.fill(); | |
if(emoji) { | |
tmp = Math.random() * 100 > 95 ? 0.125 : 1; | |
ctx.save(); ctx.translate(x, y); ctx.rotate(rotation); | |
ctx.lineWidth = 6 / 5; | |
ctx.strokeStyle = "white", ctx.fillStyle = eyes; | |
ctx.beginPath(); // Draw the left eye | |
ctx.ellipse(-width * 3 / 7, -height / 3, emoji.lRadius * 3 / 2, emoji.lHeight * tmp * 3 / 2, 0, emoji.lStart * Math.PI / 180, emoji.lFinal * Math.PI / 180, true); | |
ctx.closePath(); ctx.stroke(); ctx.fill(); ctx.beginPath(); // Draw the right eye | |
ctx.ellipse(+width * 3 / 7, -height / 3, emoji.rRadius * 3 / 2, emoji.rHeight * tmp * 3 / 2, 0, emoji.rStart * Math.PI / 180, emoji.rFinal * Math.PI / 180, true); | |
ctx.closePath(); ctx.stroke(); ctx.fill(); ctx.beginPath(); // Draw the mouth | |
ctx.ellipse(0, height * 5 / 9, emoji.mRadius * 1, emoji.mHeight, 0, emoji.mStart * Math.PI / 180, emoji.mFinal * Math.PI / 180, true); | |
ctx.closePath(); | |
ctx.strokeStyle = "red", ctx.fillStyle = "red"; | |
ctx.stroke(); | |
ctx.restore(); | |
} | |
} | |
drawKinematicLine(x1, y1, x3, y3, limit, vx, vy) { | |
var ctx = this.getContext("2d"); | |
var dx = x3 - x1, dy = y3 - y1; | |
var len = Math.max(Math.abs(dx), Math.abs(dy)), rad; | |
if(len >= 2 * limit) { | |
ctx.lineTo(x1 + 2 * dx / len * limit, y1 + 2 * dy / len * limit); | |
return {x:x1 + 2 * dx / len * limit, y:y1 + 2 * dy / len * limit}; | |
} | |
var x2 = x1 + dx / 2, y2 = y1 + dy / 2; | |
rad = Math.sqrt(dx * dx + dy * dy) / 2; | |
rad = Math.sqrt(limit * limit - rad * rad); | |
x2 += vx * dy / len * rad, y2 += vy * dx / len * rad; | |
ctx.lineTo(x2, y2); ctx.lineTo(x3, y3); | |
return {x:x3, y:y3}; | |
} | |
createActor() { | |
return { | |
position:{ | |
x :Math.random() * this.width - this.width / 2, // Позиция относительно центра | |
y :0, | |
z :Math.random(), // Расстояние от центра | |
j :125.009+Math.random()*5 // Jumping amplitude | |
}, | |
members:{ | |
lHandX :-10, // Left Hand X | |
lHandY :10, // Left Hand Y | |
rHandX :10, | |
rHandY :20, | |
lFootX :0, | |
lFootY :0, | |
rFootX :0, | |
rFootY :0, | |
}, | |
colours:{ | |
head :"grey", | |
face :"yellow", | |
body :"magenta", | |
eyes :"darkcyan" | |
}, | |
path:{ | |
points :[], | |
seek :10 | |
}, | |
chatArea :null, | |
playing :null, | |
// is speaking? | |
"говорит?":function() { return this.text.join("").length > 2; }, | |
// is quiet? | |
"молчит?":function() { return this.text.join("").length <= 2; }, | |
// is jumping? | |
"прыгает?":function() { return this.j > 0; }, | |
// is jumped? | |
"прыгнул?":function() { return this.j > 0 && this.phase < (this.step + (this.step > 180 ? -180 : this.step > -180 ? +180 : +540)) % 360; }, | |
// is steping? | |
"шагает?":function() { return this.step < -180 || this.step > 180; }, | |
// is stepped? | |
"шагнул?":function() { return (this.step < -180 || this.step > 180) && this.phase < (this.step + (this.step > 180 ? -180 : this.step > -180 ? +180 : +540)) % 360; }, | |
// let stay | |
"стоит":function() { return (this.step = 0, this.position.j = 0) && false; }, | |
// let jumping | |
"прыгает":function() { (this.position.j = 125.0009); return false; }, | |
// let walking | |
"шагает":function() { return (this.step = 30) && false; }, | |
// let running | |
"бежит":function() { return (this.step = 60) && false; }, | |
// to back | |
"обратно":function() { return (this.step = -this.step) && false; }, | |
// let moving | |
"движется":function() { return (this.step += 180) && false; }, | |
// quickly | |
"быстрее":function() { return (this.step += this.step > 0 ? 10 : -10) && false; }, | |
// catching | |
"ловит":function(target) { if(!target) return; | |
this.members.lHandX = target.position.x; | |
this.members.lHandY = target.position.y; | |
this.members.rHandX = target.position.x; | |
this.members.rHandY = target.position.y; | |
return false; | |
}, | |
// overtaking | |
"догоняет":function(target) { if(!target) return; | |
var dist = target.position.x - this.position.x; | |
if(Math.abs(dist) > 64) | |
this.step = dist < 0 ? -200 : +200; | |
else | |
this.step = 0; | |
}, | |
// escaping | |
"избегает":function(target) { if(!target) return; | |
var dist = target.position.x - this.position.x; | |
if(Math.abs(dist) < 500) | |
this.step = dist < 0 ? +200 : -200; | |
else | |
this.step = 0; | |
}, | |
// waiting | |
"ждет":function(target) { return (target.text.length == 0) || (target.text[0] == ""); }, | |
// listing | |
"слушает":function(target) { return (target.text.length > 1); }, | |
novel :[], // Текущая роль / Current actions | |
text :[[":-D",":)",":(",":o"][Math.floor(Math.random() * 4)]],//,"StickMan#"+Math.floor(Math.random()*100),(Math.random()*16777216).toString(36)], // Реплика / Remark | |
age :16, // Возраст персонажа | |
fat :100.0, // Упитанность | |
weight :100.0, // Вес | |
suit :"red", // Цвет костюма | |
// step :+20,// Right | |
// step :-20,// Left | |
// step :+200,// Forward | |
// step :-200,// Backward | |
step :1, // Текущая фаза шага: >540 - вперёд, <-540 - назад | |
phase :0 | |
}; | |
}; | |
////////////////////////////////////////////////////////////////////////////// | |
// | |
parse_emotion(emotion, size) { | |
var face_parts = "lStart lFinal lRadius lHeight rStart rFinal rRadius rHeight mStart mFinal mRadius mHeight".split(/[\s\t]+/); | |
var emotions = { | |
":)": "0 360 1/7 1/9 0 360 1/7 1/9 180 360 1/5 1/9" | |
, ":-D": "0 180 1/7 1/9 0 180 1/7 1/9 180 360 1/5 1/6" | |
, ":(": "0 360 1/7 1/9 0 360 1/7 1/9 0 180 1/5 1/9" | |
, ":o": "0 360 1/6 1/8 0 360 1/6 1/8 0 360 1/5 1/6" | |
}; | |
var members, id, data; | |
var result = {}; | |
if(emotion in emotions) { | |
members = emotions[emotion].split(/[\s\t]+/); | |
for(id in face_parts) | |
data = members.shift().split(/\//), | |
result[face_parts[id]] = data.length > 1 ? size * +data[0] / +data[1] : +data[0]; | |
return result; | |
} | |
return null; | |
}; | |
////////////////////////////////////////////////////////////////////////////// | |
// | |
stickMan(man, clouds) { | |
var ctx = this.getContext("2d"); | |
var far = Math.log((man.position.z + 1) / 2*2); // Дальность | |
var fat = man.fat / 100; // Упитанность | |
var stature = this.height / (man.age < 16 ? 8 - man.age / 3 : 3) / ((far / 4) + 1); // Рост | |
var center = this.width / 2 + man.position.x; // Центр оси | |
var jumphase = man.position.j * Math.PI * 2; // Фаза прыжка | |
var jump = man.position.j > 0 ? | |
(Math.abs(Math.sin(jumphase) * 2) - 1) * man.position.j * stature / 600 | |
: man.position.j * stature / 600; | |
var jumping = stature + jump; | |
var foot = this.height - man.position.y - far * jumping / 1.875; // Позиция ступ / Foots position | |
var width = fat * stature / 5; // Ширина головы / Head width | |
var head_x = center, head_y = foot - jumping * man.fat / man.weight + width / 2; // Позиция головы / Head position | |
var head_width = width / 2, head_height = width / 2; // Ширина/высота головы / Head width and height | |
var left_hand = center + fat * width / (man.step >= 180 ? 3 : 3 / 2); // Позиция левой руки / Left hand position | |
var right_hand = center - fat * width / (man.step < -180 ? 3 : 3 / 2); // Позиция правой руки / Right hand position | |
var hand_y = (foot - jumping * man.fat / man.weight) + width + jumping / 12; // Позиция плеч / Shoulders position | |
var body_y = head_y + head_height + jumping / 3; // Позиция тела / Body position | |
var emotion, offset, tmp, flag; | |
var a = man.step < -180 ? Math.PI / 9 : man.step > 180 ? -Math.PI / 9 : 0, b, c, dx, dy; | |
var text = [].concat(man.text); | |
var sine, cose; | |
var left, rift; | |
ctx.save(); | |
for(tmp = 0; tmp < text.length; ++ tmp) | |
if(emotion = this.parse_emotion(text[tmp], width)) | |
text.splice(tmp, 1); | |
else | |
continue; | |
// Рисуем лицо / Draw the face | |
ctx.save(); ctx.translate(head_x, head_y); ctx.scale(head_width, head_height); | |
ctx.beginPath(); ctx.arc(0, 0, 1, 0, Math.PI * 2, false); ctx.closePath(); ctx.restore(); | |
ctx.strokeStyle = man.colours.head; ctx.fillStyle = man.colours.face; | |
ctx.stroke(); ctx.fill(); | |
this.drawFace(head_x, head_y, head_width, head_height, a, emotion, man.colours.eyes); | |
// Рисуем левый контур тела / Draw the left side of body | |
ctx.beginPath(); ctx.lineWidth = (man.step >= 180 ? 1 : 2); | |
ctx.moveTo(head_x, head_y + head_height); ctx.lineTo(left_hand, hand_y); ctx.lineTo(head_x, body_y); | |
ctx.stroke(); | |
// Рисуем правый контур тела / Draw the right side of body | |
ctx.beginPath(); ctx.lineWidth = (man.step < -180 ? 1 : 2); | |
ctx.moveTo(head_x, head_y + head_height); ctx.lineTo(right_hand, hand_y); ctx.lineTo(head_x, body_y); | |
ctx.stroke(); | |
// Закрашиваем тело / Painting the body | |
ctx.beginPath(); ctx.fillStyle = man.colours.body; | |
ctx.moveTo(head_x, head_y + head_height); ctx.lineTo(left_hand, hand_y); | |
ctx.lineTo(head_x, body_y); ctx.lineTo(right_hand, hand_y); ctx.closePath(); ctx.fill(); | |
// Рисуем левую руку / Draw the left hand | |
ctx.beginPath(); ctx.moveTo(left_hand, hand_y); | |
this.drawKinematicLine(left_hand, hand_y, man.members.lHandX, man.members.lHandY, stature / 8, -1, +1); | |
ctx.lineWidth = (man.step >= 180 ? 1 : 3); ctx.closePath(); ctx.stroke(); | |
// Рисуем правую руку / Draw the right hand | |
ctx.beginPath(); ctx.moveTo(right_hand, hand_y); | |
this.drawKinematicLine(right_hand, hand_y, man.members.rHandX, man.members.rHandY, stature / 8, +1, -1); | |
ctx.lineWidth = (man.step < -180 ? 1 : 3); ctx.closePath(); ctx.fill(); ctx.stroke(); | |
// Рисуем левую ногу / Draw the left leg | |
ctx.beginPath(); ctx.moveTo(center, body_y); | |
if(man.step < -180) { // When walking back | |
ctx.lineWidth = 3, // Когда шагает назад | |
offset = -width / 2, | |
flag = +1; | |
} else { | |
if(man.step <= 180) // When just walking | |
offset = width * 3 / 4, // Когда просто шагает | |
ctx.lineWidth = 3; | |
else // When walking forward | |
offset = width / 2, // Когда шагает вперёд | |
ctx.lineWidth = 1; | |
flag = -1; | |
} | |
tmp = this.drawKinematicLine(center, body_y, man.members.lFootX + offset, man.members.lFootY, width, -flag, +flag); | |
ctx.ellipse(tmp.x, tmp.y, width / 3, width / 5, (flag + 1) * Math.PI / 2, 0, Math.PI, flag > 0); | |
ctx.stroke(); | |
// Рисуем правую ногу / Draw the right leg | |
ctx.beginPath(); ctx.moveTo(center, body_y); | |
if(man.step >= 180) { // When walking forward | |
ctx.lineWidth = 3, // Когда шагает вперёд | |
offset = width / 2, | |
flag = -1; | |
} else { | |
if(man.step > -180) // When just walking | |
offset = -width * 3 / 4,// Когда просто шагает | |
ctx.lineWidth = 3; | |
else // When walking back | |
offset = -width / 2, // Когда шагает назад | |
ctx.lineWidth = 1; | |
flag = +1; | |
} | |
tmp = this.drawKinematicLine(center, body_y, man.members.rFootX + offset, man.members.rFootY, width, -flag, +flag); | |
ctx.ellipse(tmp.x, tmp.y, width / 3, width / 5, (flag + 1) * Math.PI / 2, 0, Math.PI, flag > 0); | |
ctx.stroke(); | |
// Двигаем всего персонажа / Moving this personage | |
if(man.path.seek >= 0 && man.path.seek < man.path.points.length) { | |
a = Math.floor(man.path.seek); | |
b = man.path.points[a]; | |
man.position.x = b.x - this.width / 2; | |
man.position.z = b.y / 72; | |
if(man.step < -180 || man.step > 180) | |
do { | |
a += man.step < -180 ? -1 : +1; | |
tmp = a >= 0 && a < man.path.points.length; | |
if(tmp) { | |
c = man.path.points[Math.floor(a)]; | |
dx = c.x - b.x, dy = c.y - b.y; | |
c = (man.step < -180 ? man.step + 180 : man.step - 180) % 360; | |
tmp = Math.sqrt(dx * dx + dy * dy) < c / 8; | |
} | |
} while(tmp && false); | |
man.path.seek = a; | |
} else { | |
man.position.x = man.step < -180 ? man.position.x + (man.step + 180) % 360 / 8 : man.step >= 180 ? man.position.x + (man.step - 180) % 360 / 8 : man.position.x; | |
} | |
left = man.step >= 540 ? man.phase + 180 : man.phase - 540; | |
rift = man.step >= 540 ? man.phase + 180 + 180 : man.phase - 540 - 180; | |
if(man.step > 180) | |
man.phase = (man.phase + man.step - 180) % 360; | |
else | |
if(man.step < -180) | |
man.phase = (man.phase + man.step + 180) % 360; | |
else | |
man.phase = (man.phase + man.step + 360) % 360; | |
a = (left % 360 + 360) % 360; | |
sine = a < 180 ? Math.sin(a * Math.PI / 180) : 0; | |
cose = Math.cos(a * Math.PI / 180); | |
man.members.lFootX = center - width / 3 * cose, man.members.lFootY = foot - width / 2 * sine; | |
a = (rift % 360 + 360) % 360; | |
sine = a < 180 ? Math.sin(a * Math.PI / 180) : 0; | |
cose = Math.cos(a * Math.PI / 180); | |
man.members.rFootX = center - width / 3 * cose, man.members.rFootY = foot - width / 2 * sine; | |
man.members.lFootX = man.step < -180 ? man.members.lFootX + width / 3 : man.step >= 180 ? man.members.lFootX - width / 3 : man.members.lFootX; | |
man.members.lFootY = man.members.lFootY - width / 6; | |
man.members.rFootX = man.step < -180 ? man.members.rFootX + width / 3 : man.step >= 180 ? man.members.rFootX - width / 3 : man.members.rFootX; | |
man.members.rFootY = man.members.rFootY - width / 6; | |
a = Math.floor(man.position.j); | |
b = Math.floor(man.position.j * 100); | |
c = Math.floor(man.position.j * 10000); | |
//man.position.j = a + Math.floor((man.position.j + man.position.j * 100) * 100) % 100 / 100 + c % 100 / 10000; | |
man.position.j = a + (b + c) % 100 / 100 + c % 100 / 10000; | |
if(text.length > 1) { | |
//this.cloud([],0,0,0, [].concat(text), center, head_y - head_height * 2, 100, blobs); | |
tmp = this.createCloud(0, 0); | |
tmp.x = center, | |
tmp.y = 100, | |
tmp.z = head_y - head_height * 2, | |
tmp.text = text.join("\t"); | |
clouds.push(tmp); | |
} | |
ctx.restore(); | |
} | |
} | |
customElements.define("fanta-seur", FANTASEUR, { extends: "canvas" }); | |
CanvasRenderingContext2D.prototype.sky = | |
function(hour, month, bright) { | |
function gradient(from, last, seek) { | |
return { | |
r :from.r + (last.r - from.r) * seek, | |
g :from.g + (last.g - from.g) * seek, | |
b :from.b + (last.b - from.b) * seek | |
} | |
} | |
var seasons = [ | |
{ sky:{ day:{ r:224, g:240, b:255 }, night:{ r:32, g:48, b:128 }, morning:{ r:176, g:192, b:192 }, evening:{ r:192, g:160, b:128 } } } // winter | |
, { sky:{ day:{ r:240, g:248, b:248 }, night:{ r:48, g:64, b:128 }, morning:{ r:184, g:184, b:192 }, evening:{ r:160, g:192, b:128 } } } // spring | |
, { sky:{ day:{ r:255, g:255, b:224 }, night:{ r:64, g:96, b:128 }, morning:{ r:192, g:176, b:160 }, evening:{ r:192, g:160, b:128 } } } // summer | |
, { sky:{ day:{ r:248, g:255, b:240 }, night:{ r:48, g:64, b:128 }, morning:{ r:184, g:184, b:192 }, evening:{ r:192, g:128, b:96 } } } // autumn | |
]; | |
var sunrise = Math.sin((month + 2) * Math.PI / 12) * 2 + 4; | |
var sunset = Math.sin((month + 2) * Math.PI / 12) * 2 + 18; | |
var quarter = Math.floor((month + 11) % 12 / 3); | |
var quartnext = Math.floor(month % 12 / 3); | |
var zenith = (Math.sin((month - 1) * Math.PI / 12) + 1) * (this.canvas.height * 3 / 8); // Высота солнца в зените сезона | |
var sun_x = (Math.sin(hour * Math.PI / 12) + 1) * this.canvas.width / 2; | |
var sun_y = Math.cos(hour * Math.PI / 12) * zenith + this.canvas.height * 2 / 3; | |
var moon_x = (-Math.sin(hour * Math.PI / 12) + 1) * this.canvas.width / 2; | |
var moon_y = (-Math.cos(hour * Math.PI / 12) + 7 / 5) * this.canvas.width / 2; | |
var rgb, morning, day, evening, night, text, width; | |
var season = seasons[quarter]; | |
var seasonext = seasons[quartnext]; | |
morning = gradient(season.sky.morning, seasonext.sky.morning, (month + 11) % 3 / 3); | |
day = gradient(season.sky.day, seasonext.sky.day, (month + 11) % 3 / 3); | |
evening = gradient(season.sky.evening, seasonext.sky.evening, (month + 11) % 3 / 3); | |
night = gradient(season.sky.night, seasonext.sky.night, (month + 11) % 3 / 3); | |
if(hour > sunset || hour < sunrise) | |
rgb = night; | |
else { | |
rgb = day; | |
if(hour < sunrise + 2) // Два часа до утра | |
if(hour < sunrise + 1) // За час до рассвета | |
rgb = gradient(night, morning, (hour - sunrise)); | |
else // Утро переходит в день | |
rgb = gradient(morning, rgb, (hour - sunrise - 1)); | |
if(hour > sunset - 2) // Два часа до вечера | |
if(hour > sunset - 1) // Вечер переходит в ночь | |
rgb = gradient(evening, night, (hour - (sunset - 1))); | |
else // За час до заката | |
rgb = gradient(rgb, evening, (hour - (sunset - 2))); | |
} | |
bright = 95; | |
rgb = gradient(night, rgb, bright / 100); | |
this.beginPath(); | |
this.fillStyle = "rgba("+[Math.floor(rgb.r), Math.floor(rgb.g), Math.floor(rgb.b)].join()+",100)"; | |
this.fillRect(0, 0, this.canvas.width, this.canvas.height); | |
this.closePath(); | |
this.beginPath(); | |
//ctx.strokeStyle = sun_y > 0 ? "rgba(64,64,"+Math.floor(92+bright)+",100)" : "rgba("+[r,g,b].join()+",100)"; | |
this.fillStyle = "rgba(" + [Math.floor(255*bright/100),Math.floor(255*bright/100),0*192*bright/100].join() + ",1)"; | |
this.ellipse(sun_x, sun_y, zenith / 6, zenith / 6, 0, Math.PI * 2, 0, false); | |
text = "" + (Math.floor(hour) % 24) + ":" + ("0" + (Math.floor(hour * 60) % 60)).substr(-2); | |
width = this.measureText(text); | |
this.strokeText(text, (sun_x < this.canvas.width / 2 ? sun_x : sun_x - width.width), sun_y + zenith / 5); | |
this.closePath(); | |
this.stroke(); | |
this.fill(); | |
this.beginPath(); | |
this.fillStyle = "white"; | |
this.ellipse(moon_x, moon_y, this.canvas.height / 16, this.canvas.height / 16, 0, Math.PI * 2, 0, false); | |
this.closePath(); | |
this.fill(); | |
/* Environment["Солнце"] = { | |
position :{ | |
x :sun_x, | |
y :sun_y | |
} | |
}; | |
Environment["Луна"] = { | |
position :{ | |
x :moon_x, | |
y :moon_y | |
} | |
}; | |
//man.members.lHandX = sun_x, man.members.lHandY = sun_y, | |
//man.members.rHandX = sun_x, man.members.rHandY = sun_y; | |
/* if(man.position.x -164 > sun_x) | |
man.step = -180 -20; | |
else | |
if(man.position.x +164 < sun_x) | |
man.step = +180 +20; | |
else | |
man.step += man.step > 180 ? -360 : man.step < -180 ? +360 : 0; | |
*/} | |
// Рисуем облако: контекст, облако, позиция, ветер, капли | |
function actor_cloud(cnv, ctx, cloud, x0, windy, d, text, xm, ym, yy) { | |
var x, y, z, w, h, n, d, r1, r2, r3; | |
var i, a, x1, y1, x2, y2, x3, y3, r, r0, tmp; | |
var a1, a2, arr = []; | |
var tx, ty, tw = 0, th, tl = 0; | |
if(text) { | |
th = parseInt(ctx.font, 10); | |
for(tmp in text) { | |
w = ctx.measureText(text[tmp]).width; | |
if(tw < w) | |
tw = w; | |
if(tl < text[tmp].length) | |
tl = text[tmp].length; | |
} | |
cloud.x = xm, | |
cloud.y = yy, | |
cloud.z = 0; | |
cloud.w = tw * 0.75, | |
cloud.h = (th * text.length) / 3; | |
cloud.r1 = 2, | |
cloud.r2 = 10, | |
cloud.r3 = 20; | |
cloud.n = Math.floor(tl); | |
cloud.x1 = 0, | |
cloud.y1 = 0; | |
} | |
cloud.x1 += Math.random() * windy / 10 + windy / 5; | |
cloud.y1 += Math.random() * windy / 10 + windy / 5; | |
cloud.x1 = cloud.x1 % (windy / 5 + 1), cloud.y1 = cloud.y1 % (windy / 5 + 1); | |
x = cloud.x + cloud.x1, y = cloud.y + cloud.y1, z = 1 + Math.log(cloud.z + 1); | |
w = cloud.w / z, h = cloud.h / z, n = cloud.n; | |
r1 = cloud.r1 / z, r2 = cloud.r2 / z, r3 = cloud.r3 / z; | |
cloud.x -= windy / z; | |
x += x0; | |
n *= 3; a1 = 2 * Math.PI / n / n; | |
a2 = Math.PI / 3; | |
for(i = 0; i < n; ++ i) { | |
a = 2 * Math.PI * i / n + Math.random() * a1 + a2; | |
r = [r3, r3, r2][i % 3] + Math.random() * r1; | |
x1 = Math.cos(a) * (w + r), y1 = Math.sin(a) * (h + r); | |
arr.push({x: x1, y: y1}); | |
} | |
ctx.beginPath(); | |
ctx.fillStyle = "white"; | |
ctx.strokeStyle = "white"; | |
ctx.closePath(); | |
ctx.stroke(); | |
ctx.beginPath(); | |
tmp = arr.length - 1; | |
if(text) { | |
ctx.setLineDash([4,1]); | |
ctx.moveTo(xm, ym); | |
} else | |
ctx.moveTo(x+arr[tmp].x, y+arr[tmp].y); | |
while(arr.length) { | |
tmp = arr.shift(); | |
x1 = tmp.x, y1 = tmp.y; | |
tmp = arr.shift(); | |
x2 = tmp.x, y2 = tmp.y; | |
tmp = arr.shift(); | |
x3 = tmp.x, y3 = tmp.y; | |
ctx.bezierCurveTo(x + x1, y + y1, x + x2, y + y2, x + x3, y + y3); | |
} | |
ctx.closePath(); | |
ctx.lineWidth = 3 / z; | |
ctx.fillStyle = "rgba("+[Math.floor(255/(d/5+1)),Math.floor(255/(d/4+1)),255].join(",")+",1)"; | |
ctx.fill(); | |
ctx.strokeStyle = '#0000ff'; | |
ctx.stroke(); | |
ctx.beginPath(); | |
ctx.strokeStyle = "rgba(64,160,255," + (d/100) + ")"; | |
ctx.lineWidth = 2 / z; | |
if(d > 10) { | |
for(i = 0; i < 10; ++ i) { | |
ctx.setLineDash([Math.floor(Math.random() * 10), Math.floor(Math.random() * 10)]); | |
x1 = Math.random() + x + w * i / 10; | |
//if(Math.random() * d > i / 2) | |
ctx.moveTo(x1, y + h + Math.random() * h), | |
ctx.lineTo(x1 + 1 * windy, cnv.height); | |
} | |
} | |
ctx.stroke(); | |
ctx.setLineDash([]); | |
if(text) { | |
ctx.fillStyle = "black"; | |
tx = xm, ty = cloud.y - text.length * th / 2 + th / 2; | |
tmp = ctx.font; | |
ctx.font = "bold " + tmp; | |
for(i = 0; i < text.length; ++ i) { | |
ctx.fillText(text[i], tx - ctx.measureText(text[i]).width / 2, ty); | |
ty += th + Math.random() * 2; | |
tx += 2 - Math.random() * 3; | |
ctx.font = tmp; | |
} | |
ctx.stroke(); | |
return (i + 2.5) * th; | |
} | |
} | |
function main() { | |
canvas = document.querySelector("canvas"); | |
if("fantaSeur" in canvas) { | |
var clouds = window.location.href.match(/clouds=(?<clouds>\d+)/i); | |
var trees = window.location.href.match(/trees=(?<trees>\d+)/i); | |
var speed = window.location.href.match(/speed=(?<speed>\d+)/i); | |
var actors = window.location.href.match(/actors=(?<actors>\d+)/i); | |
if(clouds) | |
canvas.addClouds(clouds.groups.clouds); | |
if(trees) | |
canvas.addTrees(trees.groups.trees); | |
if(actors) | |
canvas.addActors(actors.groups.actors); | |
if(speed) | |
canvas.play(speed.groups.speed); | |
else | |
canvas.play(); | |
} | |
} | |
</script> | |
</head> | |
<body> | |
<canvas is='fanta-seur' width=640 height=480></canvas> | |
<script>setTimeout(main, 10);</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment