1. Canvas-1 (Lab_Canvas > Lab_Canvas > Lab_Canvas.html)
画画
http://www.effectgames.com/demos/canvascycle/
https://www.w3schools.com/graphics/canvas_coordinates.asp
https://www.w3schools.com/graphics/game_sound.asp
刷上蓝色渐层背景增添质感
以下这段程式,若非不是一开始就画出,就必须设定
globalCompositeOperation,否则,预设会盖掉先前的内容
https://www.w3schools.com/tags/playcanvas.asp?filename=playcanvas_globalcompop&preval=source-over
ctx.globalCompositeOperation = "destination-over"; var grd = ctx.createLinearGradient(0, 0, 0, 50); grd.addColorStop(0, "white"); grd.addColorStop(1, "#0000EE"); ctx.fillStyle = grd; ctx.fillRect(0, 0, 200, 50);
画线
var canvas = document.getElementById("myCanvas2"); var ctx = canvas.getContext("2d"); ctx.moveTo(0, 0); ctx.lineTo(100, 50); ctx.moveTo(100, 50); ctx.lineTo(200, 0); ctx.stroke(); //定案
涂满
var canvas = document.getElementById("myCanvas3"); var ctx = canvas.getContext("2d"); ctx.moveTo(0, 0); ctx.lineTo(100, 50); ctx.lineTo(200, 0); ctx.fill();
划十字
// width="400px" height="300px" ctx.moveTo(0, 150); ctx.lineTo(400, 150); ctx.stroke(); ctx.moveTo(200, 0); ctx.lineTo(200, 300); ctx.stroke();
用来对齐文字(自己的口绝:起始点在中间 => 相反)
ctx.font = "64px Arial"; ctx.textBaseline = "top"; //top ,middle ,botton ctx.textAlign = "left"; //对齐起点 ; left, center, right ctx.fillText("hello", 200, 150);
还原 让后面的设计不受此处影响
let bakFillStyle = ctx.fillStyle; ctx.font = "8px Arial italic"; ctx.textBaseline = "top"; ctx.textAlign = "center"; ctx.fillStyle = "#FFFFFF"; ctx.fillText("Powered by HTML5", 100, 35); ctx.fillStyle = bakFillStyle; //
2. Canvas-2 (Lab_Canvas > Lab_Canvas_Part2 > Lab_Image.html)
arc画圆圈圈
arc(120, 100, 80, 0, 2 * Math.PI [0~2PI] ,true[是否逆时针:预设False])
ctx.arc(120, 100, 80, 0, 2 * Math.PI, true); ctx.stroke(); //1.输出 // ctx.fill(); //2.填满 ctx.clip(); //3.裁切画布 ctx.drawImage(imgRabbit, 0, 0); //3.放图片
做一个重複的
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage
var ctxSmall = canvasSmall.getContext("2d"); // (canvasLab, 来源[0, 0, 240, 200], 目的[0, 0, 120, 100]) ctxSmall.drawImage(canvasLab, 0, 0, 240, 200, 0, 0, 120, 100);
图片灰阶
原理:红绿蓝相同,为灰色(数字大小只差在深浅)
把红绿蓝抓出来,取得平均数,作为灰阶的渐层
var imgData = ctxSmall.getImageData(0, 0, 120, 100); console.log(imgData); var data = imgData.data; //data.length 48000 ; 一个画素4位元 ; 0, 4, ,8 ,12 for (var i = 0; i < data.length; i += 4) { var avg = (data[i] + data[i + 1] + data[i + 2]) / 3; data[i] = avg; // red ; 4 data[i + 1] = avg; // green ; 5 data[i + 2] = avg; // blue ; 6 } ctxSmall.putImageData(imgData, 0, 0);
画布转图片 toDataURL
如同 img src="data:image/png;base64,iVBORw0KGgoAAAANSUhE............."
imgView.src = canvasSmall.toDataURL("image/png");
3. Canvas-3 (Lab_Canvas > Demo > demo.html)
撞球
var canvas = document.getElementById("surface"); var ctx = canvas.getContext("2d"); setInterval(function () { //撞到墙壁反弹 //下 if (ball.y + ball.r >= surface.height) { ball.vy = Math.abs(ball.vy) * -1; } //上 if (ball.y + ball.r <= 0) { ball.vy = Math.abs(ball.vy); } //右 if (ball.x + ball.r >= surface.width) { ball.vx = Math.abs(ball.vx) * -1; } //左 if (ball.x + ball.r <= 0) { ball.vx = Math.abs(ball.vx); } //擦掉 ctx.fillStyle = "white"; ctx.fillRect(0, 0, surface.width, surface.height); //球移动 20 22 24 26 28... ball.x += ball.vx; ball.y += ball.vy; //不会重複画 (重新计算路径) ctx.beginPath(); ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2); //画球 ctx.stroke(); }, 1000 / 70);
下堂课接续
(2)启用keyboard事件
var key_flag = "none"; document.onkeydown = function (e) { console.log(e); console.log(e.keyCode); //37左 38上 39右 40下 switch (e.keyCode) { case 37: // 按左 提早转向(*-1) // abs回传一个数字的绝对值 // ball.vx = Math.abs(ball.vx) * -1; // 虽然可以执行但是难维护 //维护用 key_flag = "left"; break; case 38: key_flag = "up"; break; case 39: key_flag = "right"; break; case 40: key_flag = "down"; break; } };
(3)撞到方向(上),按下按钮要反弹(相反:下)
if (ball.y + ball.r >= surface.height || key_flag == "up") { ball.vy = Math.abs(ball.vy) * -1; } // 上 if (ball.y + ball.r <= 0 || key_flag == "down") { ball.vy = Math.abs(ball.vy); } // 右 // if (ball.x + ball.r >= surface.width) { // ball.vx = Math.abs(ball.vx) * -1; // } if (ball.x + ball.r >= surface.width || key_flag == "left") { ball.vx = Math.abs(ball.vx) * -1; } // 左 if (ball.x + ball.r <= 0 || key_flag == "right") { ball.vx = Math.abs(ball.vx); }
(4)按完恢复原状
key_flag = "none";
4.canvas 对 focus 无效 所以 无反应
键盘按下时 事件
canvas 对 focus 无效 所以 无反应
<canvas id="surface" height="400" width="600" style="border: 1px solid gray"> </canvas> surface.onkeydown = function (e) { console.log(e); };
修改为document
document.onkeydown = function (e) { console.log(e); };
5.不要用setinterval侦测是否按下按键,请使用事件onkeydown
不管设定多少时间侦测一次,都会有遗漏
setInterval(function () { }, 1000); 1s document.onkeydown = function (e) { console.log(e); console.log(e.keyCode); //37左 38上 39右 40下 switch (e.keyCode) { case 37: key_flag = "left"; break; case 38: key_flag = "up"; break; case 39: key_flag = "right"; break; case 40: key_flag = "down"; break; } };
6.关于圆周率、sin、cos...三角函数 详见JS_API影片03(死亡)
7.ChartJS - 直线图 (Lab_ChartJS_01 > lab.html)
https://www.chartjs.org/
(1)安装 / 引用 Chart.js
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css" /> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0/dist/Chart.min.js"></script>
(2)建立画布、画笔
<canvas id="chartCanvas"></canvas> var cityPopulationList = [3800, 2570, 2374, 2106, 1859]; var cityPopulationList2030 = [3719, 3606, 3075, 2344, 1988]; var cityNameList = ["Tokyo", "Delhi", "Shanghai", "Sao Paulo", "New York"];
(3)画画
https://www.chartjs.org/docs/latest/api/interfaces/ChartTypeRegistry.html
var populationChart = new Chart(ctx, { type: "bar", //"bar"物件 data: { labels: cityNameList, // X 轴项目清单 //datasets 阵列 datasets: [ { label: "population", data: cityPopulationList, //阵列 // 着色: backgroundColor: "rgba(14,72,100,0.2)", borderColor: "rgba(14,72,100,1.0)", borderWidth: 1, }, { label: "population", data: cityPopulationList, //阵列 // 着色: backgroundColor: "rgba(14,72,100,0.5)", borderColor: "rgba(14,72,100,0.5)", borderWidth: 10, }, ], }, });
7.ChartJS - 直线图 (Lab_ChartJS_02 > lab.html)
type: "line"
8.ChartJS - pie圆饼 + doughnut甜甜圈 (Lab_ChartJS_03 > lab.html)
type: "doughnut" var pieChart = new Chart(ctx, { type: "doughnut", //"pie" data: { labels: cityNameList, datasets: [ { data: cityPopulationList, backgroundColor: ["#3e95cd", "#8e5ea2", "#3cba9f", "#e8c3b9", "#c45850"], }, //第二圈 { data: cityPopulationList2030, backgroundColor: ["#3e95cd", "#8e5ea2", "#3cba9f", "#e8c3b9", "#c45850"], }, ], }, options: { title: { display: true, text: "Population", }, cutoutPercentage: 30, //粗细 }, });
9.ChartJS - scatter散布图 + bubble气泡图 (Lab_ChartJS_04 > lab.html)
var dataList = []; for (let i = 1; i <= 10; i++) { let dataItem = { x: Math.floor(Math.random() * 100), y: Math.floor(Math.random() * 100), r: Math.floor(Math.random() * 20), //半径 }; dataList.push(dataItem); } // console.log(JSON.stringify(dataList)); var ctx = document.getElementById("chartCanvas"); var labChart = new Chart(ctx, { type: "bubble", // bubble使用到r ; scatter data: { datasets: [ { label: "random X-Y", data: dataList, backgroundColor: "rgba(14,72,100,0.2)", borderColor: "rgba(14,72,100,1.0)", borderWidth: 1, }, ], }, });
10.three.js (Lab_Three.js > lab.html)
https://threejs.org/
(1)引用
<script src="js/three.min.js"></script>
(2)製作画布
<div id="cinema"></div>
(3)画布 加入 canvas 元素
const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.getElementById("cinema").appendChild(renderer.domElement);
(4)建立 Scene (场景)
var scene = new THREE.Scene(); scene.background = new THREE.Color(0x000000);
(5)建立 Camera (照相机)
相机参数
https://www.script-tutorials.com/webgl-with-three-js-lesson-9/
const camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 0.1, 10000); camera.position.set(0, 0, 500); scene.add(camera);
(6)拍照
https://www.script-tutorials.com/webgl-with-three-js-lesson-9/
const camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 0.1, 10000); camera.position.set(0, 0, 500); //距离远近 scene.add(camera); var sphere = new THREE.SphereGeometry(200, 50, 50); var material = new THREE.MeshNormalMaterial(); var mesh = new THREE.Mesh(sphere, material); mesh.position.z = -300; scene.add(mesh);
(7)照片放到画布上
Render(输出/算图/描绘/渲染) 影像,呼叫 Renderer 描绘出作品:
renderer.render(scene, camera);
(8)包地球外皮,材质下载
var loader = new THREE.TextureLoader(); loader.load("images/earth.jpg", function (texture) { mesh.material = new THREE.MeshBasicMaterial({ map: texture, overdraw: 0.5 }); renderer.render(scene, camera); });
(9)转动
自己转转 似setInterval/setTimeout每秒动
requestAnimationFrame(doRender); function doRender() { try { mesh.rotation.y += 0.01; } catch (e) {} renderer.render(scene, camera); requestAnimationFrame(doRender); }
键盘转转
document.onkeydown = function (e) { switch (event.keyCode) { case 38: // up mesh.rotation.x -= 0.2; break; case 40: // down mesh.rotation.x += 0.2; break; case 37: // left mesh.rotation.y -= 0.2; break; case 39: // right mesh.rotation.y += 0.2; break; } event.preventDefault(); };
滑鼠转转
var lastMove = { x: window.innerWidth / 2, y: window.innerHeight / 2, }; var isMouseDown = false; document.onmousedown = function () { isMouseDown = true; lastMove.x = event.clientX; lastMove.y = event.clientY; }; document.onmouseup = function () { isMouseDown = false; }; document.onmousemove = function () { if (isMouseDown == false) { return; } var moveX = event.clientX - lastMove.x; var moveY = event.clientY - lastMove.y; mesh.rotation.y += moveX * 0.0002; mesh.rotation.x += moveY * 0.0002; lastMove.x = e.clientX; lastMove.y = e.clientY; };
11.WebCam - 拍照 (WebCam > lab.html)
(1)引用webcam
<script src="webcam.min.js"></script>
(2)WebCam 启动程式
Webcam.set({ width: 320, height: 240, image_format: 'jpeg', jpeg_quality: 90 }); Webcam.attach('#cameraDiv');
(3)照片怎么存
//製作画布 var viewContext = viewPort.getContext('2d') Webcam.snap(function (snappedImage) { // console.log(snappedImage); let bufferImage = new Image(); bufferImage.src = snappedImage; bufferImage.onload = function () { viewContext.drawImage(bufferImage, 0, 0, 320, 240); } }); // End of Webcam.snap