nadesiko3
Version:
Japanese Programming Language
590 lines (589 loc) • 18.7 kB
JavaScript
const errMsgCanvasInit = '描画を行うためには、HTML内にcanvasを配置し、idを振って『描画開始』命令に指定します。';
export default {
// @描画
'描画開始': {
type: 'func',
josi: [['の', 'へ', 'で']],
pure: true,
fn: function (cv, sys) {
if (typeof cv === 'string') {
cv = document.querySelector(cv) || document.getElementById(cv);
}
if (!cv) {
throw new Error('『描画開始』でCanvasを取得できませんでした。');
}
sys.__addPropMethod(cv);
sys.__canvas = cv;
sys.__ctx = cv.getContext('2d');
sys.__fillStyle = 'black';
sys.__strokeStyle = 'black';
sys.__setSysVar('描画中キャンバス', cv);
sys.__setSysVar('描画中コンテキスト', sys.__ctx);
},
return_none: true
},
'描画中キャンバス': { type: 'const', value: null }, // @ びょうがちゅうきゃんばす
'描画中コンテキスト': { type: 'const', value: null }, // @ びょうがちゅうこんてきすと
'キャンバス状態保存': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
sys.__ctx.save();
},
return_none: true
},
'キャンバス状態復元': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
sys.__ctx.restore();
},
return_none: true
},
'線色設定': {
type: 'func',
josi: [['に', 'へ']],
pure: true,
fn: function (v, sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
sys.__strokeStyle = v;
if (v !== '') {
sys.__ctx.strokeStyle = v;
}
},
return_none: true
},
'塗色設定': {
type: 'func',
josi: [['に', 'へ']],
pure: true,
fn: function (v, sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
sys.__fillStyle = v;
if (v !== '') {
sys.__ctx.fillStyle = v;
}
},
return_none: true
},
'線描画': {
type: 'func',
josi: [['から'], ['へ', 'まで']],
pure: true,
fn: function (a, b, sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
sys.__ctx.beginPath();
sys.__ctx.moveTo(a[0], a[1]);
sys.__ctx.lineTo(b[0], b[1]);
sys.__ctx.stroke();
},
return_none: true
},
'線太設定': {
type: 'func',
josi: [['に', 'へ']],
pure: true,
fn: function (v, sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
sys.__ctx.lineWidth = v;
},
return_none: true
},
'四角描画': {
type: 'func',
josi: [['の', 'へ', 'に']],
pure: true,
fn: function (b, sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
sys.__ctx.beginPath();
sys.__ctx.rect(b[0], b[1], b[2], b[3]);
if (sys.__fillStyle !== '') {
sys.__ctx.fill();
}
if (sys.__strokeStyle !== '') {
sys.__ctx.stroke();
}
},
return_none: true
},
'全描画クリア': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
sys.__ctx.clearRect(0, 0, sys.__canvas.width, sys.__canvas.height);
},
return_none: true
},
'描画クリア': {
type: 'func',
josi: [['の', 'へ', 'に']],
pure: true,
fn: function (b, sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
if (!(b instanceof Array)) {
b = [];
}
if (b.length === 0) {
b = [0, 0, sys.__canvas.width, sys.__canvas.height];
}
else if (b.length <= 2) {
b.unshift(0);
b.unshift(0);
}
sys.__ctx.clearRect(b[0], b[1], b[2], b[3]);
},
return_none: true
},
'描画クリップ': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
sys.__ctx.clip();
},
return_none: true
},
'円描画': {
type: 'func',
josi: [['へ', 'に'], ['の']],
pure: true,
fn: function (xy, r, sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
sys.__ctx.beginPath();
sys.__ctx.arc(xy[0], xy[1], r, 0, 2 * Math.PI, false);
if (sys.__fillStyle !== '') {
sys.__ctx.fill();
}
if (sys.__strokeStyle !== '') {
sys.__ctx.stroke();
}
},
return_none: true
},
'楕円描画': {
type: 'func',
josi: [['へ', 'に', 'の']],
pure: true,
fn: function (args, sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
if (!args) {
throw new Error('楕円描画の引数配列が無効です');
}
if (args.length < 4) {
throw new Error('楕円描画の引数配列が不足しています');
}
if (args.length < 7) {
if (!args[4]) {
args[4] = 0;
}
if (!args[5]) {
args[5] = 0;
}
if (!args[6]) {
args[6] = Math.PI * 2;
}
if (!args[7]) {
args[7] = true;
}
}
sys.__ctx.beginPath();
sys.__ctx.ellipse(...args);
if (sys.__fillStyle !== '') {
sys.__ctx.fill();
}
if (sys.__strokeStyle !== '') {
sys.__ctx.stroke();
}
},
return_none: true
},
'多角形描画': {
type: 'func',
josi: [['で', 'の', 'を']],
pure: true,
fn: function (a, sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
sys.__ctx.beginPath();
const p = a[0];
sys.__ctx.moveTo(p[0], p[1]);
for (let i = 1; i < a.length; i++) {
const t = a[i];
sys.__ctx.lineTo(t[0], t[1]);
}
sys.__ctx.lineTo(p[0], p[1]);
if (sys.__fillStyle !== '') {
sys.__ctx.fill();
}
if (sys.__strokeStyle !== '') {
sys.__ctx.stroke();
}
},
return_none: true
},
'画像読': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (url, sys) {
const img = new window.Image();
img.src = url;
img.crossOrigin = 'Anonymous';
return img;
}
},
'画像読待': {
type: 'func',
josi: [['の', 'を']],
pure: true,
asyncFn: true,
fn: function (url) {
return new Promise((resolve, reject) => {
const img = new window.Image();
img.src = url;
img.crossOrigin = 'Anonymous';
img.onload = () => { resolve(img); };
img.onerror = () => {
reject(new Error(`『画像読待』で読込みエラー。URL=『${url}』`));
};
});
}
},
'画像逐次読': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (url, sys) {
if (sys.resolve === undefined) {
throw new Error('『画像逐次読』は『逐次実行』構文で使ってください。');
}
sys.resolveCount++;
const img = new window.Image();
img.src = url;
img.crossOrigin = 'Anonymous';
img.onload = () => {
sys.__setSysVar('対象', img);
sys.resolve();
};
img.onerror = () => {
sys.__setSysVar('対象', '');
sys.reject();
};
return img;
}
},
'画像読時': {
type: 'func',
josi: [['で'], ['の', 'を']],
pure: true,
fn: function (f, url, sys) {
// 関数オブジェクトを得る
const func = sys.__findVar(f, null); // 文字列指定なら関数に変換
// 画像を読む
const img = new window.Image();
img.src = url;
img.crossOrigin = 'Anonymous';
img.onload = () => {
sys.__setSysVar('対象', img);
func(sys);
};
img.onerror = () => {
sys.__setSysVar('対象', '');
func(sys);
};
},
return_none: true
},
'画像描画': {
type: 'func',
josi: [['の', 'を'], ['へ', 'に']],
pure: true,
fn: function (img, xy, sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
const drawFunc = (im, ctx) => {
if (xy.length === 2) {
ctx.drawImage(im, xy[0], xy[1]);
}
else if (xy.length === 4) {
ctx.drawImage(im, xy[0], xy[1], xy[2], xy[3]);
}
else if (xy.length === 8) {
ctx.drawImage(im, xy[0], xy[1], xy[2], xy[3], xy[4], xy[5], xy[6], xy[7]);
}
else {
throw new Error('『画像描画』の第二引数の配列要素は2,4,8個のいずれかです。');
}
};
if (typeof img === 'string') {
const image = new window.Image();
image.src = img;
image.crossOrigin = 'Anonymous';
image.onload = () => {
drawFunc(image, sys.__ctx);
};
return image;
}
else {
drawFunc(img, sys.__ctx);
return img;
}
},
return_none: false
},
'画像部分描画': {
type: 'func',
josi: [['の'], ['を', 'から'], ['へ', 'に']],
pure: true,
fn: function (img, sxy, dxy, sys) {
const errArgLen = '『画像部分描画』に使える引数は画像と、描画する座標へ2つか、' +
'描画する座標とその位置の4つか、使用する座標と使用する位置と描画する座標と大きさの8つだけです。';
if (img && sxy) {
if (!Array.isArray(sxy) && Array.isArray(img)) { // 逆になっていれば入れ替える
if (typeof sxy === 'string' || String(sxy.__proto__) === '[object HTMLImageElement]') {
const sw = img;
img = sxy;
sxy = sw;
}
}
}
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
const drawFunc = (im, ctx) => {
if (!dxy) {
if (!sxy) {
ctx.drawImage(im);
}
else if (sxy.length >= 2) { // もしsxyがあるのにdxyがなかったらdxyを代わりにする
dxy = sxy;
sxy = undefined;
}
}
if (dxy.length === 2) {
ctx.drawImage(im, dxy[0], dxy[1]);
}
else if (dxy.length === 4) {
if (!sxy) {
ctx.drawImage(im, dxy[0], dxy[1], dxy[2], dxy[3]);
}
else if (sxy.length === 4) {
ctx.drawImage(im, sxy[0], sxy[1], sxy[2], sxy[3], dxy[0], dxy[1], dxy[2], dxy[3]);
}
else {
throw new Error(errArgLen);
}
}
else {
throw new Error(errArgLen);
}
};
if (typeof img === 'string') {
const image = new window.Image();
image.src = img;
image.crossOrigin = 'Anonymous';
image.onload = () => {
drawFunc(image, sys.__ctx);
};
return image;
}
else {
drawFunc(img, sys.__ctx);
return img;
}
},
return_none: false
},
'描画フォント設定': {
type: 'func',
josi: [['を', 'の', 'で', 'に']],
pure: true,
fn: function (n, sys) {
// 数値だけならフォントサイズのみの指定
if (typeof n === 'number') {
n = n + 'px sans-serif';
}
// ピクセル数のみの指定なら適当にフォントを足す
if (/^[0-9]+(px|em)$/.test(n)) {
n = n + ' sans-serif';
}
sys.__ctx.font = n;
},
return_none: true
},
'文字描画': {
type: 'func',
josi: [['へ', 'に'], ['の', 'を']],
pure: true,
fn: function (xy, s, sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
sys.__ctx.fillText(s, xy[0], xy[1]);
},
return_none: true
},
'文字描画幅取得': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (s, sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
return sys.__ctx.measureText(s);
},
return_none: false
},
'描画起点設定': {
type: 'func',
josi: [['へ', 'に']],
pure: true,
fn: function (xy, sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
sys.__ctx.translate(xy[0], xy[1]);
},
return_none: true
},
'描画回転': {
type: 'func',
josi: [['だけ', 'に', 'へ']],
pure: true,
fn: function (a, sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
sys.__ctx.rotate(a * Math.PI / 180);
},
return_none: true
},
'描画拡大': {
type: 'func',
josi: [['だけ', 'に', 'へ']],
pure: true,
fn: function (xy, sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
sys.__ctx.scale(xy[0], xy[1]);
},
return_none: true
},
'描画変換マトリクス設定': {
type: 'func',
josi: [['だけ', 'に', 'へ']],
pure: true,
fn: function (a, sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
sys.__ctx.setTransform(a[0], a[1], a[2], a[3], a[4], a[5], a[6]);
},
return_none: true
},
'描画変換マトリクス追加': {
type: 'func',
josi: [['だけ', 'に', 'へ']],
pure: true,
fn: function (a, sys) {
if (!sys.__ctx) {
throw new Error(errMsgCanvasInit);
}
sys.__ctx.transform(a[0], a[1], a[2], a[3], a[4], a[5], a[6]);
},
return_none: true
},
'描画データURL変換': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
const cv = sys.__getSysVar('描画中キャンバス');
const url = cv.toDataURL('image/png');
return url;
}
},
'描画データBLOB変換': {
type: 'func',
josi: [],
pure: true,
asyncFn: true,
fn: function (sys) {
return new Promise((resolve, reject) => {
const cv = sys.__getSysVar('描画中キャンバス');
cv.toBlob((result) => { resolve(result); }, 'image/png');
});
}
},
'描画ダウンロードリンク作成': {
type: 'func',
josi: [['へ', 'に']],
pure: true,
fn: function (dom, sys) {
if (typeof dom === 'string') {
dom = document.querySelector(dom);
}
if (!dom) {
throw new Error('『描画ダウンロードリンク作成』でDOMが見当たりません。');
}
const cv = sys.__getSysVar('描画中キャンバス');
if (!cv) {
throw new Error('『描画ダウンロード』で描画中キャンバスが設定されていません。');
}
dom.href = cv.toDataURL('image/png');
dom.download = 'canvas.png';
},
return_none: true
},
'描画ダウンロード': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
const cv = sys.__getSysVar('描画中キャンバス');
if (!cv) {
throw new Error('『描画ダウンロード』で描画中キャンバスが設定されていません。');
}
const a = document.createElement('a');
a.href = cv.toDataURL('image/png');
a.download = 'canvas.png';
a.click();
return true;
}
}
};