Add paint function for fast CSS painting API expriment

This commit is contained in:
yuanchuan 2021-11-28 16:21:24 +08:00
parent 5c7b9fd7b7
commit 2dd12aa6f8
4 changed files with 78 additions and 7 deletions

View File

@ -326,6 +326,10 @@ function get_exposed(random) {
return value => value;
},
paint() {
return value => value;
},
path() {
return value => value;
},

View File

@ -38,6 +38,7 @@ class Rules {
this.coords = [];
this.doodles = {};
this.canvas = {};
this.paint = {};
this.shaders = {};
this.paths = {};
this.reset();
@ -58,6 +59,7 @@ class Rules {
this.coords = [];
this.doodles = {};
this.canvas = {};
this.paint = {};
this.shaders = {};
for (let key in this.rules) {
if (key.startsWith('#c')) {
@ -112,7 +114,7 @@ class Rules {
}
is_composable(name) {
return ['doodle', 'shaders', 'canvas'].includes(name);
return ['doodle', 'shaders', 'canvas', 'paint'].includes(name);
}
compose_argument(argument, coords, extra = []) {
@ -138,6 +140,8 @@ class Rules {
return this.compose_shaders(value, coords);
case 'canvas':
return this.compose_canvas(value, coords);
case 'paint':
return this.compose_paint(value, arg.arguments.slice(1));
}
}
}
@ -187,6 +191,17 @@ class Rules {
return '${' + id + '}';
}
compose_paint(code, rest = []) {
let commands = code;
let result = rest.map(group => get_value(group[0])).join(',');
if (result.length) {
commands = code + ',' + result;
}
let id = this.unique_id('paint');
this.paint[id] = { code: commands };
return '${' + id + '}';
}
compose_path(commands) {
let id = this.unique_id('path');
this.paths[id] = {
@ -223,6 +238,8 @@ class Rules {
result += this.compose_shaders(value, coords); break;
case 'canvas':
result += this.compose_canvas(value, coords); break;
case 'paint':
result += this.compose_paint(value, val.arguments.slice(1)); break;
}
}
} else {
@ -316,7 +333,7 @@ class Rules {
}
}
if (prop === 'background' && (value.includes('shader') || value.includes('canvas'))) {
if (prop === 'background' && (value.includes('shader') || value.includes('canvas') || value.includes('paint'))) {
rule += 'background-size: 100% 100%;';
}
@ -544,6 +561,7 @@ class Rules {
shaders: this.shaders,
paths: this.paths,
canvas: this.canvas,
paint: this.paint,
definitions: definitions,
uniforms: this.uniforms
}

View File

@ -6,6 +6,7 @@ import seedrandom from './lib/seedrandom';
import { svg_to_png } from './svg';
import { draw_shader } from './shader.js';
import { draw_canvas } from './canvas.js';
import { make_paint } from './paint.js';
import { uniform_time } from './uniform';
import get_props from './utils/get-props';
@ -239,6 +240,10 @@ class Doodle extends HTMLElement {
draw_canvas(code, width, height, this.random).then(fn);
}
paint_to_image({ code, cell }, fn) {
make_paint(code, this.random).then(fn);
}
shader_to_image({ shader, cell }, fn) {
let parsed = parse_shaders(shader);
let element = this.doodle.getElementById(cell);
@ -287,16 +292,16 @@ class Doodle extends HTMLElement {
this.build_grid(compiled, this.grid_size);
}
replace({ doodles, shaders, paths, canvas }) {
replace({ doodles, shaders, paths, canvas, paint }) {
let doodle_ids = Object.keys(doodles);
let shader_ids = Object.keys(shaders);
let path_ids = Object.keys(paths);
let canvas_ids = Object.keys(canvas);
let paint_ids = Object.keys(paint);
return input => {
if (!doodle_ids.length && !shader_ids.length && !path_ids.length && !canvas_ids.length) {
if (!doodle_ids.length && !shader_ids.length && !path_ids.length && !canvas_ids.length && !paint_ids.length) {
return Promise.resolve(input);
}
let mappings = [].concat(
doodle_ids.map(id => {
if (input.includes(id)) {
@ -325,6 +330,15 @@ class Doodle extends HTMLElement {
return Promise.resolve('');
}
}),
paint_ids.map(id => {
if (input.includes(id)) {
return new Promise(resolve => {
this.paint_to_image(paint[id], value => resolve({ id, value }));
});
} else {
return Promise.resolve('');
}
}),
path_ids.map(id => {
if (input.includes(id)) {
return Promise.resolve({ id, value: '#' + id });
@ -337,11 +351,17 @@ class Doodle extends HTMLElement {
return Promise.all(mappings).then(mapping => {
if (input.replaceAll) {
mapping.forEach(({ id, value }) => {
input = input.replaceAll('${' + id + '}', `url(${value})`);
input = input.replaceAll(
'${' + id + '}',
/^paint/.test(id) ? value : `url(${value})`
);
});
} else {
mapping.forEach(({ id, value }) => {
input = input.replace('${' + id + '}', `url(${value})`);
input = input.replace(
'${' + id + '}',
/^paint/.test(id) ? value : `url(${value})`
)
});
}
return input;

29
src/paint.js Normal file
View File

@ -0,0 +1,29 @@
import { un_entity } from './utils/index';
let counter = 1;
let cache = {};
function make_paint(code, random) {
if (cache[code]) {
return Promise.resolve(cache[code]);
}
let name = 'css-doodle-paint-' + counter++;
let wrapped = `
registerPaint('${name}', class {
${ un_entity(code) }
})
`;
let blob = new Blob([wrapped], { type: 'text/javascript' });
try {
if (CSS.paintWorklet) {
CSS.paintWorklet.addModule(URL.createObjectURL(blob));
}
} catch(e) {}
return Promise.resolve(cache[code] = `paint(${name})`);
}
export {
make_paint
}