javascript - 无法使用 paper.js 为“组”使用“符号”
问题描述
我想做一个反应扩散系统的动画paper.js
。
这是一个只生成一个图像的代码:
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.2/paper-full.min.js"></script>
<style>
canvas {
width: 400px;
height: 400px;
border: black 3px solid;
}
</style>
</head>
<body>
<script>
function subm_index(M, x){
if (x<0)
return x+M;
if(x >= M)
return x-M;
return x;
}
function update_concentrations(X, L, DA, DB, f, k){
var sum_a, sum_b, x1, y1, t;
var m = X.A.length;
var n = X.A[0].length;
var A = new Array(m);
var B = new Array(m);
for(var i = 0; i < m; i++){
A[i] = new Array(n);
B[i] = new Array(n);
}
for(var x = 0; x < m; x++) {
for(var y = 0; y < n; y++){
sum_a = 0.0;
sum_b = 0.0;
for(var i = -1; i <= 1; i++){
for(var j = -1; j <= 1; j++){
x1 = subm_index(m, x - i);
y1 = subm_index(n, y - j);
sum_a = sum_a + L[i+1][j+1] * X.A[x1][y1];
sum_b = sum_b + L[i+1][j+1] * X.B[x1][y1];
}
}
t = X.A[x][y]*X.B[x][y]*X.B[x][y];
A[x][y] = X.A[x][y] + DA*sum_a - t + f*(1-X.A[x][y]);
B[x][y] = X.B[x][y] + DB*sum_b + t - (k+f)*X.B[x][y];
}
}
return {A: A, B: B};
}
function iterate_Gray_Scott(X, L, DA, DB, f, k, n){
for(var i = 0; i < n; i++){
X = update_concentrations(X, L, DA, DB, f, k);
}
return X;
}
var L = [[0.05, 0.2, 0.05], [0.2, -1, 0.2], [0.05, 0.2, 0.05]];
var DA = 1;
var DB = 0.5;
var f = 0.0545;
var k = 0.062;
</script>
<script type="text/paperscript" canvas="quad">
var pixels = 200;
var gridSize = 2;
var rectSize = 2;
var A = new Array(pixels);
var B = new Array(pixels);
for(var i = 0; i < pixels; i++){
A[i] = new Array(pixels);
B[i] = new Array(pixels);
for(var j = 0; j < pixels; j++){
A[i][j] = 1;
B[i][j] = Math.random() < 0.98 ? 0 : 1;
}
}
var X = {A: A, B: B};
X = iterate_Gray_Scott(X, L, DA, DB, f, k, 1000);
for(var y = 0; y < pixels; y++){
for(var x = 0; x < pixels; x++){
var color = {
hue: X.B[x][y] * 360,
saturation: 1,
brightness: 1
};
var path = new Path.Rectangle(new Point(x, y) * gridSize, new Size(rectSize, rectSize));
path.fillColor = color;
}
}
project.activeLayer.position = view.center;
</script>
<canvas id="quad" resize></canvas>
</body>
</html>
现在,这是一个生成动画的代码:
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.2/paper-full.min.js"></script>
<style>
canvas {
width: 400px;
height: 400px;
border: black 3px solid;
}
</style>
</head>
<body>
<script>
function subm_index(M, x){
if (x<0)
return x+M;
if(x >= M)
return x-M;
return x;
}
function update_concentrations(X, L, DA, DB, f, k){
var sum_a, sum_b, x1, y1, t;
var m = X.A.length;
var n = X.A[0].length;
var A = new Array(m);
var B = new Array(m);
for(var i = 0; i < m; i++){
A[i] = new Array(n);
B[i] = new Array(n);
}
for(var x = 0; x < m; x++) {
for(var y = 0; y < n; y++){
sum_a = 0.0;
sum_b = 0.0;
for(var i = -1; i <= 1; i++){
for(var j = -1; j <= 1; j++){
x1 = subm_index(m, x - i);
y1 = subm_index(n, y - j);
sum_a = sum_a + L[i+1][j+1] * X.A[x1][y1];
sum_b = sum_b + L[i+1][j+1] * X.B[x1][y1];
}
}
t = X.A[x][y]*X.B[x][y]*X.B[x][y];
A[x][y] = X.A[x][y] + DA*sum_a - t + f*(1-X.A[x][y]);
B[x][y] = X.B[x][y] + DB*sum_b + t - (k+f)*X.B[x][y];
}
}
return {A: A, B: B};
}
function iterate_Gray_Scott(X, L, DA, DB, f, k, n){
for(var i = 0; i < n; i++){
X = update_concentrations(X, L, DA, DB, f, k);
}
return X;
}
var L = [[0.05, 0.2, 0.05], [0.2, -1, 0.2], [0.05, 0.2, 0.05]];
var DA = 1;
var DB = 0.5;
var f = 0.0545;
var k = 0.062;
</script>
<script type="text/paperscript" canvas="quad">
var pixels = 200;
var gridSize = 2;
var rectSize = 2;
var A = new Array(pixels);
var B = new Array(pixels);
var Paths = new Array(pixels);
for(var i = 0; i < pixels; i++){
A[i] = new Array(pixels);
B[i] = new Array(pixels);
Paths[i] = new Array(pixels);
for(var j = 0; j < pixels; j++){
A[i][j] = 1;
B[i][j] = Math.random() < 0.99 ? 0 : 1;
}
}
var X = {A: A, B: B};
for(var y = 0; y < pixels; y++){
for(var x = 0; x < pixels; x++){
var color = {
hue: X.B[x][y] * 360,
saturation: 1,
brightness: 1
};
Paths[x][y] = new Path.Rectangle(new Point(x, y) * gridSize, new Size(rectSize, rectSize));
Paths[x][y].fillColor = color;
}
}
var nframes = 100;
var XX = new Array(nframes);
XX[0] = X;
for(var frm = 1; frm < nframes; frm++){
XX[frm] = iterate_Gray_Scott(XX[frm-1], L, DA, DB, f, k, frm);
}
project.activeLayer.position = view.center;
function onFrame(event){
console.log(event.count);
if(event.count < nframes){
for(var y = 0; y < pixels; y++){
for(var x = 0; x < pixels; x++){
var color = {
hue: XX[event.count].B[x][y] * 360,
saturation: 1,
brightness: 1
};
Paths[x][y].fillColor = color;
}
}
}
}
</script>
<canvas id="quad" resize></canvas>
</body>
</html>
它可以工作,但动画不够流畅。这是由于 in 中的双循环onFrame
,这会消耗一些时间。
所以我首先尝试创建一个包含nframes
Group
元素的数组,每个组都包含pixels*pixels
Rectangle
元素。但这产生了内存不足。
所以我尝试使用 aSymbol
来节省一些内存。代码在下面,但它不起作用,没有出现单个图像。
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.2/paper-full.min.js"></script>
<style>
canvas {
width: 400px;
height: 400px;
border: black 3px solid;
}
</style>
</head>
<body>
<script>
function subm_index(M, x){
if (x<0)
return x+M;
if(x >= M)
return x-M;
return x;
}
function update_concentrations(X, L, DA, DB, f, k){
var sum_a, sum_b, x1, y1, t;
var m = X.A.length;
var n = X.A[0].length;
var A = new Array(m);
var B = new Array(m);
for(var i = 0; i < m; i++){
A[i] = new Array(n);
B[i] = new Array(n);
}
for(var x = 0; x < m; x++) {
for(var y = 0; y < n; y++){
sum_a = 0.0;
sum_b = 0.0;
for(var i = -1; i <= 1; i++){
for(var j = -1; j <= 1; j++){
x1 = subm_index(m, x - i);
y1 = subm_index(n, y - j);
sum_a = sum_a + L[i+1][j+1] * X.A[x1][y1];
sum_b = sum_b + L[i+1][j+1] * X.B[x1][y1];
}
}
t = X.A[x][y]*X.B[x][y]*X.B[x][y];
A[x][y] = X.A[x][y] + DA*sum_a - t + f*(1-X.A[x][y]);
B[x][y] = X.B[x][y] + DB*sum_b + t - (k+f)*X.B[x][y];
}
}
return {A: A, B: B};
}
function iterate_Gray_Scott(X, L, DA, DB, f, k, n){
for(var i = 0; i < n; i++){
X = update_concentrations(X, L, DA, DB, f, k);
}
return X;
}
var L = [[0.05, 0.2, 0.05], [0.2, -1, 0.2], [0.05, 0.2, 0.05]];
var DA = 1;
var DB = 0.5;
var f = 0.0545;
var k = 0.062;
</script>
<script type="text/paperscript" canvas="quad">
var pixels = 50;
var gridSize = 2;
var rectSize = 2;
var A = new Array(pixels);
var B = new Array(pixels);
var Paths = new Array(pixels);
for(var i = 0; i < pixels; i++){
A[i] = new Array(pixels);
B[i] = new Array(pixels);
Paths[i] = new Array(pixels);
for(var j = 0; j < pixels; j++){
A[i][j] = 1;
B[i][j] = Math.random() < 0.99 ? 0 : 1;
}
}
var X = {A: A, B: B};
var nframes = 50;
var XX = new Array(nframes);
XX[0] = X;
for(var frm = 1; frm < nframes; frm++){
XX[frm] = iterate_Gray_Scott(XX[frm-1], L, DA, DB, f, k, frm);
}
var Rects = [];
for(var x = 0; x < pixels; x++){
for(var y = 0; y < pixels; y++){
var rect = new Path.Rectangle(new Point(x, y) * gridSize, new Size(rectSize, rectSize));
var color = {
hue: 1,
saturation: 1,
brightness: 1
};
rect.fillColor = color;
rect.visible = false;
Rects.push(rect);
}
}
group = new Group(Rects);
symbolGroup = new Symbol(group);
var Groups = new Array(nframes);
for(var frm = 0; frm < nframes; frm++){
Groups[frm] = symbolGroup.place(view.center);
var k = 0;
for(var x = 0; x < pixels; x++){
for(var y = 0; y < pixels; y++){
Groups[frm].definition.definition.children[k].fillColor = {
hue: XX[frm].B[x][y] * 360,
saturation: 1,
brightness: 1
};
k = k+1;
}
}
XX[frm] = null; // to free some memory
}
project.activeLayer.position = view.center;
function onFrame(event){
if(event.count < nframes){
console.log(event.count);
Groups[event.count].visible = true;
if(event.count > 0){
Groups[event.count-1].visible = false; // to free some memory
}
}
}
</script>
<canvas id="quad" resize></canvas>
</body>
</html>
你能帮我修复这个最后的代码吗?
解决方案
如果您的目标是性能,我认为在这种情况下,您应该摆脱 Paper.js,这会增加渲染部分的开销。
作为替代,您可以直接使用 Canvas API 来渲染您的绘图。
这是一个基于您的代码的快速示例,展示了如何使用它。
<html>
<head>
<style>
canvas {
width : 400px;
height : 400px;
}
</style>
</head>
<body>
<canvas></canvas>
<script>
function subm_index(M, x) {
if (x < 0) {
return x + M;
}
if (x >= M) {
return x - M;
}
return x;
}
function update_concentrations(X, L, DA, DB, f, k) {
var sum_a, sum_b, x1, y1, t;
var m = X.A.length;
var n = X.A[0].length;
var A = new Array(m);
var B = new Array(m);
for (var i = 0; i < m; i++) {
A[i] = new Array(n);
B[i] = new Array(n);
}
for (var x = 0; x < m; x++) {
for (var y = 0; y < n; y++) {
sum_a = 0.0;
sum_b = 0.0;
for (var i = -1; i <= 1; i++) {
for (var j = -1; j <= 1; j++) {
x1 = subm_index(m, x - i);
y1 = subm_index(n, y - j);
sum_a = sum_a + L[i + 1][j + 1] * X.A[x1][y1];
sum_b = sum_b + L[i + 1][j + 1] * X.B[x1][y1];
}
}
t = X.A[x][y] * X.B[x][y] * X.B[x][y];
A[x][y] = X.A[x][y] + DA * sum_a - t + f * (1 - X.A[x][y]);
B[x][y] = X.B[x][y] + DB * sum_b + t - (k + f) * X.B[x][y];
}
}
return { A: A, B: B };
}
function iterate_Gray_Scott(X, L, DA, DB, f, k, n) {
for (var i = 0; i < n; i++) {
X = update_concentrations(X, L, DA, DB, f, k);
}
return X;
}
var L = [[0.05, 0.2, 0.05], [0.2, -1, 0.2], [0.05, 0.2, 0.05]];
var DA = 1;
var DB = 0.5;
var f = 0.0545;
var k = 0.062;
var pixels = 200;
var gridSize = 2;
var rectSize = 2;
var A = new Array(pixels);
var B = new Array(pixels);
var Paths = new Array(pixels);
for (var i = 0; i < pixels; i++) {
A[i] = new Array(pixels);
B[i] = new Array(pixels);
Paths[i] = new Array(pixels);
for (var j = 0; j < pixels; j++) {
A[i][j] = 1;
B[i][j] = Math.random() < 0.99 ? 0 : 1;
}
}
var X = { A: A, B: B };
var nframes = 50;
var XX = new Array(nframes);
XX[0] = X;
for (var frm = 1; frm < nframes; frm++) {
XX[frm] = iterate_Gray_Scott(XX[frm - 1], L, DA, DB, f, k, frm);
}
//
// New code
//
// Get a reference to the canvas element.
const canvas = document.querySelector('canvas');
// Make sure that canvas internal size fits its display size.
canvas.width = 400;
canvas.height = 400;
// Get canvas context to be able to draw directly on it.
const ctx = canvas.getContext('2d');
// Counter used to swicth between frames.
let currentFrame = 0;
// Launch the animation.
animate();
function animate() {
// Draw current frame.
draw();
// Update frame counter (make it loop after last frame).
currentFrame = currentFrame < nframes - 1 ? currentFrame + 1 : 0;
// Do a recursive call to render next frame.
requestAnimationFrame(animate);
}
function draw() {
// For each pixel...
for (var y = 0; y < pixels; y++) {
for (var x = 0; x < pixels; x++) {
// ...get the color...
const hue = Math.round(XX[currentFrame].B[x][y] * 360);
const color = `hsl(${hue}, 100%, 50%)`;
// ...use it as canvas fill color...
ctx.fillStyle = color;
// ...and draw a scaled rectangle.
ctx.fillRect(x * gridSize, y * gridSize, gridSize, gridSize);
}
}
}
</script>
</body>
</html>
另一个改进想法可能是将当前数据源映射到准备好的ImageData数组,稍后将其加载到画布中,而不是循环遍历像素。
推荐阅读
- java - 如何让按钮暂停记住 MediaPlayer 停止的位置?
- python - 我想使用 XAMPP 在 Web 浏览器中显示 PYTHON 图
- python - Python - 为什么字节对象包含条目:'/ty"'
- kotlin - 为什么两个短裤之间的加号运算符返回一个 Int
- loops - 执行snakemake进行迭代映射
- php - html表单使用onsubmit=""的Ajax Query函数并使用php连接Ajax Query进行邮件投递
- typescript - 输入字符串 | 即使在 if-checks 和 null 断言之后 null “可能为 null”
- amazon-web-services - 在 Amazon Linux 2 上为 Docker 配置静态文件设置以错误结束
- compiler-errors - Solidity 智能合约代码中的预期未知错误 - Remix
- git - 查找 git 分支的提交,这些提交不是樱桃挑选到另一个分支