canvas のツール 網目がうまく描けない(未完成)
<!DOCTYPE html> <meta charset="UTF-8"> <title>HTML Canvas Library</title> <style> canvas { border: 2px gray ridge; } </style> <body> <canvas width="500" height="250"></canvas> <canvas width="500" height="250"></canvas> <canvas width="500" height="250"></canvas> <canvas width="500" height="250"></canvas> <canvas width="500" height="250"></canvas> <script> class Canvas { #col = 'black'; #view = [ ]; constructor (canvas, option) { this.canvas = canvas; this.option = Object.assign ({ }, this.constructor.defOption, option); this.ctx = canvas.getContext ('2d'); } cls () { this.canvas.width = this.canvas.clientWidth; this.viewport (...this.#view); return this; } line (x, y, x1, y1) { let { ctx } = this; ctx.beginPath (); ctx.moveTo (x, y); ctx.lineTo (x1, y1); ctx.closePath (); ctx.stroke (); return this; } viewport (maxX = this.canvas.clientWidth, maxY = this.canvas.clientHeight, minX = 0, minY = 0, deg = 0) { const { canvas, ctx, option } = this, { sin, cos, trunc: int, abs, log10, PI: pi } = Math, digitNum = n=> int (log10 (n) + 1);//桁数を求める let w = canvas.clientWidth, h = canvas.clientHeight, dx = maxX - minX, dy = maxY - minY, uw = w / dx, uh = h / dy, ur = deg * (pi / 180); ctx.setTransform ( uw * cos (ur), -sin (ur) * uh, -sin (ur) * uw , -uh * cos (ur), -minX * uw, maxY * uh, ); ctx.lineWidth = 1 / (uw + uh) * 1.;//線の太さは、縦横軸の平均から算出 if (option.grid) { ctx.save (); //グリッドの間隔を2点の距離から算出する let mx = 10 ** (digitNum (uw)), my = 10 ** (digitNum (uh)), nx = mx / 10, ny = my / 10, sx = int ((minX - abs (dx)) / nx) * nx, ex = int ((maxX + abs (dx)) / nx) * nx, sy = int ((minY - abs (dy)) / ny) * ny, ey = int ((maxY + abs (dy)) / ny) * ny; console.log(uw, uh,mx,my, sx,ex,sy,ey); this.color = 'silver'; // for (let p = sx; p < ex; p += nx / 100) this.line (p, sy, p, ey); // for (let p = sy; p < ey; p += nx / 100) this.line (sx, p, ex, p); this.color = 'silver'; // for (let p = sx; p < ex; p += nx / 10) this.line (p, sy, p, ey); // for (let p = sy; p < ey; p += nx / 10) this.line (sx, p, ex, p); this.color = 'gray'; for (let p = sx; p < ex; p += nx) this.line (p, sy, p, ey); for (let p = sy; p < ey; p += ny) this.line (sx, p, ex, p); this.color = 'black'; this.line (0, sy, 0, ey); this.line (sx, 0, ex, 0); ctx.restore (); } this.#view = [maxX, maxY, minX, minY, deg]; return this; } set color (arg) {this.ctx.strokeStyle = this.#col = arg; } get color () { return this.#col; } static defOption = { grid: true, } static create (canvas = document.querySelector ('canvas'), option = { }) { return new this (canvas, option); } } </script>
JavaScript Tips
いつか使ってみよう!
const func = ((cbFunc = arg=> { ; }) => cbFunc)() const ary = ((c=d=>'function'==typeof d?d(b):(b.push(d),c),b=[])=>c)();
ギアにペンを差し込んでグルグルまわるやつ
'''
'''
<!DOCTYPE html> <meta charset="UTF-8"> <title>HTML canvas </title> <style> ol li label { display: inline-block; width: 10em; padding: 0 1ex; } ol li { margin: 2px; list-style: none; } ol li label, ol li input { border: 2px silver ridge; border-radius: 5px; } </style> <body> <form id="STATE"> <ol> <li> <label>Aria</label> <input type="number" value="1200" step="50" min="50" max="10000"> <li> <label>B:radius</label> <input type="number" value="352" min="0" max="5000"> <li> <label>B:offset</label> <input type="number" value="0.52" min="0.01" max="1" step=".01"> <li> <label>Line color</label> <select> <option value="rgba(0,0,0,.3)">Gray</option> <option value="rgba(255,0,0,.2)">Red</option> <option value="rgba(0,128,0,.2)">Green</option> <option value="rgba(0,0,255,.2)">Blue</option> <option value="rgba(128,0,255,.2)" selected>Violet</option> </select> <li> <label>Line speed</label> <select> <option value="1">Slow</option> <option value="5">Normal</option> <option value="25" selected>Early</option> <option value="100">High speed</option> </select> </li> <li>-------- Option --------- </li> <li> <label>C:radius</label> <input type="number" value="1" min="1" max="20"> <li> <label>C:offset</label> <input type="number" value="0" min="0" max="1" step=".03" max="1"> </ol> </form> <canvas width="1200" height="1200"></canvas> <script> //----------------------------------------------- class Canvas { constructor (e, area, color = 'rgba(0,0,0,.5)') { this.canvas = e; this.ctx = e.getContext ('2d'); this.color = color; this.area = area; this.m = null; } cls () { let { ctx, canvas } = this; ctx.clearRect (0, 0, canvas.width, canvas.height); return this; } set area (p) { if (p) { let { ctx, canvas } = this; [canvas.width, canvas.height] = p.value; this.m = null; ctx.translate (canvas.offsetWidth / 2, canvas.offsetHeight / 2); } } set color (rgba) { this.ctx.strokeStyle = rgba; } line (p) { let {ctx, m} = this; if (null === m) { ctx.moveTo (...p.value); } else { ctx.beginPath (); ctx.moveTo (...m.value); ctx.lineTo (...p.value); ctx.stroke (); } this.m = p; return this; } } //----------------------------------------------- class P { #p = [ ]; constructor (a) { this.#p = a; } add (q) { return new this.constructor (q.value.map ((a,i)=> this.#p[i]+a)) } sub (q) { return new this.constructor (q.value.map ((a,i)=> this.#p[i]-a)) } get value () { return this.#p } set value (p) { this.#p = p } } //----------------------------------------------- class Circle { #rad = null; //ラジアン #c = null; //円周 constructor (radius = 1, offset = 1/* (%) */, rad = 0) { this.radius = radius; this.offset = offset; this.#rad = rad; this.#c = 2 * Math.PI * radius; } rotation (n) { this.#rad += n / this.#c; return this.position; } get position () { let r = this.radius * this.offset; let rad = this.#rad; return new P ([Math.sin (rad) * r, Math.cos (rad) * r]); } } //----------------------------------------------- let CG = new Canvas (document.querySelector ('canvas')), C0 = null, C1 = null, C2 = null, ANIME_ID = null, PM = [...document.querySelectorAll ('form input[type="number"], form select')], STEP = 25, SPEED = null; function draw () { for (let i = SPEED; i--; ) CG.line (C0.rotation (STEP).add (C1.rotation (-STEP)).add(C2.rotation(-STEP))); requestAnimationFrame (draw); } //----------------------------------------------- function demo () { if (ANIME_ID) cancelAnimationFrame (ANIME_ID); let [a, r, offset, col, sp, gr, go] = PM.map (e=> 'valueAsNumber' in e ? e.valueAsNumber: e.value); let r0 = a/2*.95 - ( r * offset); CG.area = new P ([a, a]); CG.color = col; SPEED = +sp; C0 = new Circle (r0, 1), C1 = new Circle (r, offset); C2 = new Circle (gr, go); draw (); } //----------------------------------------------- function hndler () { demo (); } STATE.addEventListener ('change', hndler, false); demo (); </script>
location.hash と webapl を連動させるライブラリ
Ajax を利用してアプリを作るとき、location.hash の値と連動して動く。
onHashChange を使用せずに済む。
とある条件でページをスクリプトで生成するプログラムがあるとする。
その条件が変化するごとに location.hash に書き出し、コールバック(生成プログラム)に条件を渡して呼び出す
外部からある条件下でページを生成したい場合 location.hash に条件を書いて呼び出す
インスタンス化した時点の条件を標準とし、それと違う用件だけを location.hash に記述する
2022-07-09 更新
/*---------------------------------------------- onHashChange を使用せず 現在の状態を location.hash に反映させる(逆も可) 対象となるFORM の要素群には id もしくは name 属性が必要である ----------------------------------------------*/ class ApplicationNavigator { #defaultState = null;//初期設定時の状態を基本とする constructor (form = document.querySelector ('form'), cbFunc = null, cbObj = null, ...cbArgs) { this.form = form; this.cbFunc = cbFunc; this.cbObj = cbObj; this.cbArgs = cbArgs; this.elements = [...form.querySelectorAll ('input[id], input[name], select[id], select[name], textarea[id], textarea[name]')]; this.#defaultState = this.constructor.getValues (this.elements); this.hash = location.hash; if (cbFunc) form.addEventListener ('change', this, false); } execute (e) { if ('function' === typeof this.cbFunc) { this.cbFunc.apply (this.cbObj || this, [this.status, ...this.cbArgs]); location.hash = this.hash; } return this; } reset () { this.status = this.#defaultState; return this; } handleEvent (event) { let e = event.target; if (this.elements.includes (e)) this.execute (e); } get status () {//全ての状態を返す return this.constructor.getValues (this.elements); } set status (obj = { }) {//statusには実態がない(その都度要素から収集) this.constructor.setValues (this.elements, Object.assign ({ }, obj)); this.execute ();//コールバック関数を呼び出す } get hash () { let a = this.#defaultState; return '#' + Object.entries (this.status) .filter (([k,v])=> a[k] != v) .map (b=> b.join`=`) .join('&'); } set hash (hash) { this.status = this.constructor.parseParms (hash); } //______________________ static parseParms (str = '') { let reg = /(?:^#)?(\D\w*)(\[\])?=(.*?)(?:\&|\;|$)/g, pieces = new Map, piece; while (piece = reg.exec (str)) { let [, key, isAry, val] = piece; key = decodeURIComponent (key); val = decodeURIComponent (val); if (isAry) val = [val]; if (pieces.has (key)) pieces.set (key, [].concat (pieces.get (key), val)); else pieces.set (key, val); } return Object.fromEntries (pieces); } //要素の値を取得してオブジェクトにして返す //name属性が複数な場合配列として記憶する static getValues ([...es]) { const excludeType = ['fieldset', 'reset', 'submit', 'image', 'file','button'],//除外する要素 obj = new Map; for (let e of es) { let type = e.type, key, value; if (excludeType.includes (type)) continue; if (['checkbox', 'radio'].includes (type) && !e.checked) continue;//checked属性がfalsse は除外する if (key = e.id || e.name) {//keyがあるものだけ有効 //最初から配列とする if ('select-multiple' === type) value = [...e.options].reduce ((a, b)=> (b.selected && a.push (b.value), a), [ ]); else if ('checkbox' === type) value = [value]; else value = e.value; if (obj.has (key))//すでに登録されたものは配列 value = [].concat (obj.get (key), value); obj.set (key, value); } } return Object.fromEntries (obj);//オブジェクト化 } //指定要素群に値を代入する static setValues ([...es], obj = { }) { const priority = ['radio', 'checkbox', 'select-one', 'select-multiple'],//優先順位 prioritize = (a, b)=> priority.indexOf (a.type) - priority.indexOf (b.type); let hs = es.reduce ((a,e)=> (a[e.id||e.name] = (a[e.id||e.name] || []).concat(e), a), { });//名前毎にhashにする //名前毎の中で優先順に並び替え Object.values (hs).forEach (v=> v.sort (prioritize)); //select要素のmultipleのすべてをリセットする es.filter (e=> e.type === 'select-multiple').flatMap (e=> [...e.options]).forEach (e=> e.selected = false); //es.filter (e=> e.hasAttribute ('defaulValue')).forEach (e=> e.value = e.defaultValue); for (let [name, vals] of Object.entries (obj)) {//※valsはコピーしたもの let es = hs[name] || [ ]; vals = [].concat (vals); while (vals.length) { let val = vals.shift (); for (let e of es) { switch (e.type) { //想定のtype順で設定する case 'select-multiple': for (let op of e.options) { if (op.value == val) { op.selected = true; break; } } break; case 'select-one' : e.value = val; break; case 'checkbox' : case 'radio' : e.checked = e.value === val; break; default : e.value = val; break; } } } } } }
location.hash を解析して object にして返す
正規表現を使うのは大げさな気がする。
location.hash を location.search に書き換えて URL.searchParams で取得するほうが簡単だろうか?
[, 変数名, 大括弧, 変数値]に分割しながら解析する
function parseParms (str = '') { let reg = /(?:^#)?(\D\w*)(\[\])?=(.*?)(?:\&|\;|$)/g, pieces = new Map; while (piece = reg.exec (str)) { let [, key, isAry, val] = piece; key = decodeURIComponent (key); val = decodeURIComponent (val); if (isAry) val = [val]; if (pieces.has (key)) pieces.set (key, [].concat (pieces.get (key), val)); else pieces.set (key, val); } return Object.fromEntries (pieces); }
2段階プルダウンで表示内容を切り替えたい
2段階プルダウンで表示内容を切り替えたい
2段階プルダウンで1段階目の選択を終えた後に選択ボックスを見えなくしたい
goo: https://oshiete.goo.ne.jp/qa/13030027.html
okwave:https://okwave.jp/qa/q10026854.html
無駄に答えてしまった。phpのプログラムは評価しづらい。
<!DOCTYPE html> <meta charset="utf-8"> <title></title> <style> </style> <body> <p> <select id="Y"></select> / <select id="M"></select> / <select id="D"></select> </p> <table border="1" id="T"></table> <script> async function ajax (path, args = { }, cbFunc = null, ...cbArgs) { let res = await fetch (path, { method: 'post', body: JSON.stringify (args) }); let txt = await res.text (); let json = JSON.parse(txt); return 'function' === typeof cbFunc ? cbFunc.call (...cbArgs): json; } function ary2tbody (a,b=document.createElement('tbody')){a.reduce((b,a)=>(a.reduce((c,d)=>(c.insertCell().append(d),c),b.insertRow()),b),b)} function replaceOptions (e, ary) {e.replaceChildren (...ary.map (a=> new Option (...a)))} function replaceY (y=(new Date).getFullYear(),n=10) {replaceOptions (Y,[...Array(n)].map ((_,i)=>[y-i]))} function replaceM () {replaceOptions (M,[...Array(12)].map ((_,i)=>[i+1]))} function replaceD (y=Y.value,m=M.value) { replaceOptions (D,[...Array((new Date (y,m,0)).getDate())].map ((_,i)=>[i+1]))} async function loadContent (y=Y.value, m=M.value, d=D.value) { ary2tbody(await ajax ('test.php', {date: `${y}-${m}-${d}`}), T); } function handler (event) { let e = event.target; switch (true) { case M == e : replaceD (); break; case D == e : loadContent (); break; } } document.addEventListener ('change', handler, false); [replaceY,replaceM,replaceD].map(f=>f()); </script>
test.php
<?php const MySQL_DBNAME = '********'; const MySQL_HOST = 'localhost'; const MySQL_USER = '********'; const MySQL_PASS = '********'; $db = sprintf ('mysql:dbname=%s; host=%s; charset=utf8mb4', MySQL_DBNAME, MySQL_HOST); $mysql = new PDO ($db, MySQL_USER, MySQL_PASS); $query = 'select * from table_name where :date < date';//ここは適当に $args = json_decode (file_get_contents ('php://input'), true); $hd = $mysql-> prepare ($query); $hd-> execute ($args); $result = $hd-> fetchAll ( PDO::FETCH_NUM); header ('Content-type: application/json; charset=utf-8'); header ('X-Content-Type-Options: nosniff'); echo json_encode ($result);//JSONに変換する ?>