スポットライト[classic]
今回はExt.ux.Spotlightの紹介です。
Exampleを眺めていたら見つけて試したくなりました(http://examples.sencha.com/extjs/6.5.1/examples/classic/core/spotlight.html)。
これを使うと、特定の要素を目立たせることができます。
使い方
Ext.ux.Spotlightのインスタンスで目立たせたい要素を引数にしてshowメソッドを実行します。
var button1 = panel.down('#button1'), spot = Ext.create('Ext.ux.Spotlight'); spot.show(button1.getEl());
すると、下記のようにボタン1をマスク表示で囲うような表現となります。
スポットライト用のスタイルが見当たらなかったので、自分で定義する必要があるようです。
ここでは下記のようにしています。
.#{$prefix}spotlight { background-color: #999; z-index: 8999; position: absolute; top: 0; left: 0; @include opacity(.5); width: 0; height: 0; zoom: 1; font-size: 0; }
応用
サービスへの初回ログイン時のナビゲーションに使えそうなので、それっぽいものを試してみました。
gifにしたので画質が悪くなっています。。。
しかし、それなりに形になりました。これから作るアプリケーションでは組み込んでいこうと思います。
メインのビュー
Ext.define('Sample.view.sample.Panel', { extend: 'Ext.panel.Panel', xtype: 'sample_panel', controller: 'sample_panel', cls: 'sample-panel', layout: 'fit', listeners: { afterlayout: 'onAfterLayout' }, dockedItems: { xtype: 'toolbar', cls: 'nav-toolbar', items: [ { xtype: 'label', cls: 'brand', text: 'ロゴ' }, '->', { reference: 'envelope_button', iconCls: 'x-fa fa-envelope', scale: 'large' }, { reference: 'comment_button', iconCls: 'x-fa fa-comment', scale: 'large' }, { reference: 'info_button', iconCls: 'x-fa fa-info-circle', scale: 'large' } ] }, items: { xtype: 'panel' } }); Ext.define('Sample.view.sample.PanelController', { extend: 'Ext.app.ViewController', alias: 'controller.sample_panel', requires: [ 'Ext.ux.Spotlight' ], helpRefs: [ 'envelope_button', 'comment_button', 'info_button' ], helpInfo: { 'envelope_button': { text: 'メンテナンスや新機能追加のお知らせは、こちらからご確認いただけます。', align: 'tr-br', offset: [0, 10] }, 'comment_button': { text: 'ユーザからのコメントは、こちらからご確認いただけます。', align: 'tr-br', offset: [0, 10] }, 'info_button': { text: '分からない機能があれば、このボタンからヘルプをご確認いただけます。', align: 'tr-br', offset: [0, 10] } }, config: { /** * @cfg {Ext.ux.Spotlight} スポットライトオブジェクト。 */ spot: null, /** * @cfg {Number} 現在表示しているヘルプ参照のインデックス。 */ currentHelpIndex: null, /** * @cfg {Sample.view.balloon.Panel} 吹き出しパネル。 */ balloon: null }, /** * afterlayoutイベント時の処理。 */ onAfterLayout: function () { this.runHelp(); }, /** * ヘルプの表示を開始する。 */ runHelp: function () { var me = this, refInfo = me.currentHelpRefInfo(); me.showHelp(refInfo); }, /** * 前のヘルプを表示する。 */ showPrevHelp: function () { var me = this, refInfo = me.prevHelpRefInfo(); me.showHelp(refInfo); }, /** * 次のヘルプを表示する。 */ showNextHelp: function () { var me = this, refInfo = me.nextHelpRefInfo(); me.showHelp(refInfo); }, /** * ヘルプを表示する。 * @param {object} helpRefInfo ヘルプ参照情報 */ showHelp: function (helpRefInfo) { var me = this, spot = me.getSpot(), ref = helpRefInfo.ref, target = me.lookupReference(ref), helpInfo = me.helpInfo[ref]; me.setCurrentHelpIndex(helpRefInfo.index); // 前の吹き出しが残っていたら破棄する me.destroyPreBalloonPanel(); // スポットライトを当てる spot.show(target.getEl()); // 吹き出し表示 me.showBallonPanel({ target: target, text: helpInfo.text, first: helpRefInfo.first, last: helpRefInfo.last, align: helpInfo.align, offset: helpInfo.offset }); }, /** * 吹き出しを表示する。 * @param {object} params パラメータ */ showBallonPanel: function (params) { var me = this; Ext.defer(function () { var balloonPanel = Ext.widget('sample_balloon_panel', { html: params.text, first: params.first, last: params.last, listeners: { prev: 'onPrevBalloonPanel', next: 'onNextBalloonPanel', end: 'onEndBalloonPanel', destroy: 'onDestroyBalloonPanel', scope: me } }); me.setBalloon(balloonPanel); balloonPanel.showBy(params.target, params.align, params.offset); }, params.first ? 500 : 100); }, /** * 前の吹き出しを破棄する。 */ destroyPreBalloonPanel: function () { var me = this, balloon = me.getBalloon(); if (balloon) { balloon.destroy(); } }, /** * 吹き出しパネルprevイベント時の処理。 * @param {Sample.view.balloon.Panel} panel 吹き出しパネル */ onPrevBalloonPanel: function (panel) { var me = this; panel.destroy(); me.showPrevHelp(); }, /** * 吹き出しパネルnextイベント時の処理。 * @param {Sample.view.balloon.Panel} panel 吹き出しパネル */ onNextBalloonPanel: function (panel) { var me = this; panel.destroy(); me.showNextHelp(); }, /** * 吹き出しパネルendイベント時の処理。 * @param {Sample.view.balloon.Panel} panel 吹き出しパネル */ onEndBalloonPanel: function (panel) { var me = this, spot = me.getSpot(); panel.destroy(); me.setCurrentHelpIndex(null); spot.hide(); }, /** * 吹き出しパネルdestroyイベント時の処理。 */ onDestroyBalloonPanel: function () { this.setBalloon(null); }, /** * 現在の参照情報を返す。 * @return {object} 現在の参照情報 */ currentHelpRefInfo: function () { var me = this, currentHelpIndex = me.getCurrentHelpIndex(); if (currentHelpIndex === null) { currentHelpIndex = 0; } return me.getHelpRefInfo(currentHelpIndex); }, /** * 前の参照情報を返す。 * @return {object} 前の参照情報 */ prevHelpRefInfo: function () { var me = this, currentHelpIndex = me.getCurrentHelpIndex(), index; if (currentHelpIndex > 0) { index = currentHelpIndex - 1; } else { index = 0; } return me.getHelpRefInfo(index); }, /** * 次の参照情報を返す。 * @return {object} 次の参照情報 */ nextHelpRefInfo: function () { var me = this, currentHelpIndex = me.getCurrentHelpIndex(), index; if (currentHelpIndex === null) { index = 0; } else if (currentHelpIndex >= 0) { index = currentHelpIndex + 1; } return me.getHelpRefInfo(index); }, /** * 指定されたインデックスのヘルプ参照情報を返す。 * * @param {number} index インデックス * @return {object} ヘルプ参照情報 */ getHelpRefInfo: function (index) { var me = this, helpRefs = me.helpRefs, refInfo = { ref: null, first: false, last: false, index: index }; if (index === 0) { refInfo.first = true; } else if (index === helpRefs.length - 1) { refInfo.last = true; } refInfo.ref = helpRefs[index]; return refInfo; }, // @override getSpot: function () { var me = this, spot = me.callParent(arguments); if (!spot) { spot = Ext.create('Ext.ux.Spotlight', { easing: 'easeOut', duration: 300 }); me.setSpot(spot); } return spot; } });
@charset "UTF-8"; .sample-panel { .nav-toolbar { background-color: $base-color; .brand { color: #fff; } } } .#{$prefix}spotlight { background-color: #999; z-index: 8999; position: absolute; top: 0; left: 0; @include opacity(.5); width: 0; height: 0; zoom: 1; font-size: 0; }
吹き出し部分
ビューモデルやビューコントローラも使わず、スタイルも吹き出しっぽくしてなくて、結構手抜きです。
Ext.define('Sample.view.sample.balloon.Panel', { extend: 'Ext.panel.Panel', xtype: 'sample_balloon_panel', cls: 'sample-balloon-panel', floating: true, bodyPadding: 15, maxWidth: 300, // @override initComponent: function () { var me = this; Ext.apply(me, { buttons: [ { text: 'Prev', hidden: me.first, handler: function () { var p = this.up('sample_balloon_panel'); p.fireEvent('prev', p); }, scope: 'this' }, { text: 'Next', hidden: me.last, handler: function () { var p = this.up('sample_balloon_panel'); p.fireEvent('next', p); }, scope: 'this' }, { text: 'End', hidden: !me.last, handler: function () { var p = this.up('sample_balloon_panel'); p.fireEvent('end', p); }, scope: 'this' } ] }); me.callParent(arguments); } });
@charset "UTF-8"; .sample-balloon-panel { background-color: #fff; .#{$prefix}panel-body { color: #666; font-size: 16px; line-height: 1.2; } }