jsPanel4 使ってますか?
相変わらずバニラJS書きしている昨今ですが、ウィンドウ内にフローティングパネルを表示するのに、jsPanelばかり使っているんです。
その上で、なんの工夫もないとウィンドウのリサイズ(最大化も含めて)時に、せっかく表示しているパネルが元の位置に放置されてしまって少し残念でした。
リサイズ時にオフセット量を踏まえて表示位置を追従させたいと思い、コードを工夫しました。
工夫あれこれ
自作クラスでのプロパティにpositionを持たせる
this._position = { my:'right-top', at:'right-top', offsetX: -4, offsetY: 4 };
こんな感じにpositionを持たせて、ドラッグ操作後にoffsetXとoffsetYを計算して上書きすることを考えます。
ただ、jspanelのイベント処理がdocumentに対するグローバルなものになるため、あらかじめグローバル側にも入れ物を用意しておきます:
if (window.App === undefined) {
window.App = {};
}
let App = window.App;
って書き方でいいかよくわかりませんが、window.Appになんでもかんでもしまってしまう癖がつきました。
jsPanel.create() 時の工夫
jspanel.create() に渡すoptionsにて、こんな風にしました:
show(target_id) { // パネルを表示するメソッド
// const elemHeader = document.getElementById('header');
this._target_id = target_id;
this._position = { my:'right-top', at:'right-top', offsetX: -4, offsetY: 4 };
const panel = jsPanel.create({
container: '#'+target_id, // div#main-content を想定
content: /*略*/,
css: /*略*/,
dragit: {
stop: (panel, paneldata, event) => {
// ウィンドウリサイズ時に右上基準のオフセット量を保持するための処理
// console.log('dragit.stop: paneldata: '+JSON.stringify(paneldata));
const elemContainer = document.getElementById('main-content'); // 親divを取得
this._position.offsetX = (paneldata.left + paneldata.width) - elemContainer.clientWidth; // 右側からのオフセット量を計算
this._position.offsetY = paneldata.top;
App.panelPosition['(パネルの識別子)'] = this._position;
},
},
headerControls: /*略*/,
headerTitle: /*略*/,
iconfont: /*略*/,
id: this.id,
minimizeTo: 'parent',
panelSize: /*略*/,
position: this._position,
theme: 'primary'
});
this.panel = panel;
ポイントは、dragit.stopコールバック関数にて、paneldataにtop, left, width, heightとしてCSSでもそのまま使える位置および大きさ情報が入ってくるので、このタイミングでオフセット量を計算して、App.panelPositionオブジェクトに格納しています。
リサイズ処理にてオフセット量を復元
まずグローバルにはこんな感じで onresize() 関数をリサイズイベントに登録します。
window.addEventListener('resize', onresize);
onresize();
で、肝心の中身は:
function onresize() {
/*略*/
const elem = document.getElementById('(パネルのid)');
if (elem) {
jsPanel.position(elem, App.panelPosition['(パネルの識別子)']);
}
}
ということで、とりあえずしっくりきてます。
複数のパネルで同じようなことをすることも考慮して、positionの保持方法はid由来としてます。
jsPanel4ユーザーさんとつながりたい
なるべく使い方ややり方がわかったものは、こんな感じのメモを残そうと思うので、よろしくです。
略、とした箇所に、色付けの仕方とか、アイコンのカスタマイズとか仕込んでたりしますので、暇ができたらまとめたいです。
余談:jsPanel4、これはやっとけ、お勧め設定
jsPanel.create() に与えるoptionsオブジェクトで挙動が変わるのですが、これは必ず加えておいた方がいいよという設定をご紹介します。
dragit.containment
dragitの中でも、containmentを与えておくことで、親要素の外にはみ出てパネル自体を操作することが不可能になる事態を回避することができます。 たまにふざけてdivの外にぶん投げて、あっ元に戻せない、なんて悲しいですからね。
containment では4つまでの値を持つ配列を与えられます。 4つ与えれば、順に [上, 右, 下, 左] の制限だそうです。 4つすべて同じ値であれば、1つの値を与えるだけでOKっていう楽な記述です。
ちなみに、[上下, 左右] という与え方も、[上, 左右, 下] という与え方も可能だそうです。
const panel = jsPanel.create({
// ~略~
dragit: {
containment: [4],
},
// ~略~
});
container と minimizeTo: 'parent', をセットで使う
containerはパネル表示する際の親要素の指定です。 省略すると 'window' になります。
私の使い方としては、ヘッダーおよびフッターを固定表示しているときにメインコンテンツのdivを指定してます。
そうすると、パネルを最小化表示したときに、なんの工夫もしないとフッターにかぶって悲しくなってしまうので、container を与えたらセットで minimizeTo: 'parent',
も与えることにしています。 そうすることで、親要素内で左下に最小化タイトルバーが表示されるのでフッターとかぶりません。
const panel = jsPanel.create({
// ~略~
container: "#main-content", // 親要素のid
// ~略~
minimizeTo: 'parent',
// ~略~
});