今回はゆるーく、便利系の実装。
SVGタグだけじゃなく、HTMLタグも扱えるようにしたいのでそのあたりで楽をするためのモノ作っていきます。
シリーズ
-
SVGを書くのが面倒なので入力補完できるようにしてみる 1
内部に持った状態を変更させるオブジェクト、メソッドチェイン、基本シェイプ、<path>
のd要素 -
SVGを書くのが面倒なので入力補完できるようにしてみる 2
useに潜んでいた罠、<animate>
-
SVGを書くのが面倒なので入力補完できるようにしてみる 3
render周りを便利にしたい - SVGを書くのが面倒なので入力補完できるようにしてみる 4
引き続き ↓ コレ作ってるときの話です。
GitHub: mafumafuultu/svg.js dev
とりあえず今回で一区切り
便利系の実装
-
fill
,stroke
は割と使う -
viewBox
で中央に表示する座標と倍率指定があるとよさそう -
undefined
長い -
textContent
長い -
onload
はpromise
になっていた方が使い勝手がいいと思う。 - 通常のHTMLタグも喰えるようにしたので、HTMLElementが混じっていても使えるようにする
- すでに作っていた関数を、抱えている要素にあてたい
準備
これらを用意する前に、まず内部的にエラーを防ぐ仕組み・製薬を用意。
const __BASE_PROTO__ = {
type : { value (v, is) {return typeof t === is;} },
of : { value (v, t) {return v instanceof t;} },
has : { value (prop) {return prop in this['@'];} }
};
属性は前方互換としても存在している__BASE_PROTO__.attrs
を呼ぶと、だいたい解決する。
よく使う属性とか
// 長い
const none = undefined;
const __BASE_PROTO__ = {
fill: {
value(color = 'transparent') {
return this.type(color, 'string')
? this.attrs({'fill': color})
: this;
}
},
stroke: {
value(color = 'transparent', width) {
return this.type(color, 'string')
? Object.is(width, undefined)
? this.attrs({stroke : color})
: this.attrs({stroke : color, 'stroke-width' : width})
: this;
}
},
fillStroke : {
value(fill = 'transparent', stroke = 'transparent') {
return this.type(fill, 'string') && this.type(stroke, 'string')
? this.attrs({fill, stroke})
: this;
}
},
txt : {
value(txt = '') {
if (this.has('textContent')) {
this['@'].textContent = txt;
}
return this;
}
}
};
viewbox zoom
viewBox
の指定方法は rect
と同じなので計算は簡単ですね。
const __BASE_PROTO__ = {
zoom: {
value(center=[0,0], x) {
if (this.has('viewBox')) {
let {width, height} = this.attrs();
let w = width/x, h = height/x;
this.attrs({viewBox: `${center[0] - w/2} ${center[1] - h/2} ${w} ${h}`})
}
return this;
}
},
};
onloadをpromiseに
const onload = () => document.readyState !== 'complete'
? new Promise(r => document.addEventListener('readystatechange', () => {
switch (document.readyState) {
case 'complete': r();break;
default:
}
}))
: Promise.resolve();
普通のHTMLタグも扱いやすく
なんだかんだ使う id
とか class
とか data
とか
const __BASE_PROTO__ = {
id : {
value (id) {
if (this.has('id') && this.type(id, 'string')) {
this['@'].id = id;
}
return this;
}
},
cls : {
value(v, force = true) {
if (this.has('classList') && this.type(v, 'string')) {
this['@'].classList.toggle(v, force);
}
return this;
}
},
data : {
value(o) {
if (this.has('dataset') && this.type(k, 'string')) {
v == null
? delete this['@'].dataset[k]
: this['@'].dataset[k] = v;
}
return this;
}
}
}
すでに作っていた関数を、抱えている要素にあてたい
全部をErrにするのもいまいちイケてないので try-catch
const __BASE_PROTO__ = {
f: {
value(f = el => {}) {
try {
f(this['@'])
} catch (e) {
console.error(e);
}
return this;
}
},
}