QlikView Extensionの作り方について。日本語の紹介サイトがあまりなく、情報収集に困る方も多いであろうから参考になれば幸いである。
対象
本稿ではQlikView(v11以上)を扱っている。Qlik SenseもExtensionと呼ばれる技術があるらしいが、本稿では取り扱っていない。
QlikView Extension
概説
QlikViewではビルトインのいくつかのチャートがある。しかしながら、定型的で表現には限界がある。Extensionを使うことで、CSSとJavaScriptにより自由な表現を行うことができる。
制約
WebViewモードでしか使えない。表現をWebブラウザーのレンダリングに頼っているためである。
活用例
運送会社の案件で、ドライバーごとの移動を視覚化したいとの依頼があった。それに応じ移動経路を地図にプロットするExtensionを開発した。
QlikView Extensionの作り方
フォルダー構成
基本的な構成は次の通りとなる。
エクステンション名/
├ Definition.xml
├ icon.png
├ Script.js
├ DynProperties.qvpp
├ css/
│ ├ Definition.xml
│ ├ a.css
│ └ b.css
└ js/
├ Definition.xml
├ c.js
└ d.js
css/やjs/といったサブフォルダーは設けず、単一のフォルダー(エクステンション名/)に全てまとめても良い。フォルダー毎にDefinition.xmlが必要となるため、サブフォルダーを作るのであれば同ファイルが必要となる。
Definition.xml
概要
ファイル名は固定。その名の通りExtensionのプロパティ定義ファイルである。日本語を含むときはBOM付きでないと文字化けするかもしれない。次のリンクに設定項目は網羅される。
- QlikView extension definition file, QlikTech
- QlikView properties: dimensions, QlikTech
- QlikView properties: measures, QlikTech
- QlikView properties: caption, background and layout, QlikTech
- QlikView properties: text, QlikTech
エクステンション名/Definition.xml
デフォルトのPageHeightは40。値を大きくすればロードするレコードの量が増える。
<?xml version="1.0" encoding="UTF-8" ?>
<ExtensionObject Path="エクステンション名"
Label="エクステンション日本語名"
Description="エクステンションの説明"
PageHeight="100"
Type="object">
<Dimension Label="軸" Initial="" TargetName="軸" />
<Measurement Label="メジャーA" Initial="" />
<Measurement Label="メジャーB" Initial="" />
<Initiate Name="Chart.Dimension.0.Field" Value="軸" />
<Initiate Name="Chart.Expression.0.0.Definition" Value="メジャーA" />
<Initiate Name="Chart.Expression.0.0.Definition" Value="メジャーB" />
<Initiate Name="Chart.Dimension.0.SuppressNull" Value="1" />
<Initiate Name="Chart.Dimension.0.Sort.PrimarySortOrder" Value="1" />
</ExtensionObject>
前述の通りプロパティはいろいろあるので、例えばExtensionの枠が鬱陶しいなと思ったら、このように追記すれば消せる。
<Initiate Name="Caption.Show" Value="0" />
<Initiate Name="Caption.Icon.SendToExcel" Value="0" />
<Initiate Name="Caption.Allow.Maximize" Value="0" />
<Initiate Name="Caption.Allow.Minimize" Value="0" />
<Initiate Name="Caption.Text" Value="エクステンション日本語名" />
<Initiate Name="Layout.Allow.MoveSize" Value="0" />
<Initiate Name="Layout.Border.Use" Value="0" />
エクステンション名/サブフォルダー名/Definition.xml
これ以上の情報はいらない。このDefinition.xmlをサブフォルダー毎に格納すればよい。
<?xml version="1.0" encoding="UTF-8" ?>
<ExtensionObject Type="object">
</ExtensionObject>
icon.png
概要
ファイル名は固定。本Extensionのアイコン。32 x 32px位でよいと思う。
Script.js
概要
ファイル名は固定。initialのスクリプト。日本語を含むときはBOM付きでないと文字化けするかもしれない。
ネットに転がっているExtensionのコードを探したが、後述のパターンAかパターンBの書き方が多いように見受けられた。何を隠そうQv.AddExtensionの呼び出し順が異なるだけである。留意したいのは、Qv.AddExtensionのコールバックでthis.Dataオブジェクトにアクセスできるようになるということだ。
エクステンション名/Script.js:パターンA
function ExtensionInit() {
var _this = this;
var cssFiles = [];
var QV_LOAD_URL = Qva.Remote + (Qva.Remote.indexOf("?") >= 0 ? "&" : "?") + "public=only" + "&name=";
cssFiles.push("Extensions/" + QV_LOAD_URL + "/css/a.css");
cssFiles.push("Extensions/" + QV_LOAD_URL + "/css/b.css");
for (var i = 0; i < cssFiles.length; i++) {
Qva.LoadCSS(QV_LOAD_URL + cssFiles[i]);
}
var jsFiles = [];
jsFiles.push("Extensions/" + QV_EXTENSION_NAME + "/js/c.js");
jsFiles.push("Extensions/" + QV_EXTENSION_NAME + "/js/d.js");
Qv.LoadExtensionScripts(jsFiles,
function () {
alert(Object.keys(_this.Data.Rows));
subA();
subB();
function subA() {
// サブルーチンA
}
function subB() {
// サブルーチンB
}
});
}
var QV_EXTENSION_NAME = "エクステンション名";
Qv.AddExtension(QV_EXTENSION_NAME, ExtensionInit);
エクステンション名/Script.js:パターンB
function ExtensionInit() {
var QV_EXTENSION_NAME = "エクステンション名";
var cssFiles = [];
var QV_LOAD_URL = Qva.Remote + (Qva.Remote.indexOf("?") >= 0 ? "&" : "?") + "public=only" + "&name=";
cssFiles.push("Extensions/" + QV_LOAD_URL + "/css/a.css");
cssFiles.push("Extensions/" + QV_LOAD_URL + "/css/b.css");
for (var i = 0; i < cssFiles.length; i++) {
Qva.LoadCSS(QV_LOAD_URL + cssFiles[i]);
}
var jsFiles = [];
jsFiles.push("Extensions/" + QV_EXTENSION_NAME + "/js/c.js");
jsFiles.push("Extensions/" + QV_EXTENSION_NAME + "/js/d.js");
Qv.LoadExtensionScripts(jsFiles,
function () {
Qv.AddExtension(QV_EXTENSION_NAME,
function () {
var _this = this;
alert(Object.keys(_this.Data.Rows));
subA();
subB();
function subA() {
// サブルーチンA
}
function subB() {
// サブルーチンB
}
});
});
}
ExtensionInit();
データへのアクセス
Rowsオブジェクトにアクセスするだけ。とてもかんたん。
alert(this.Data.Rows[0][0].text);
ページサイズを可変にする例
Definition.xmlに次の通り追加することで、プロパティダイアログにテキストボックスができる。
<Text Label="ページサイズ" Type="text" Expression="500" />
Script.jsで同テキストボックスを参照するようにすれば、それに応じてページサイズを変更できる。
Data.SetPagesizeY(_this.Layout.Text0.text.toString());
DynProperties.qvpp
概要
ファイル名は固定。DynProperties.qvppはプロパティダイアログの表示(見た目)を管理している。Extensionをインストールするか、当該Extensionの埋め込まれたドキュメントを開くと自動的に生成される。
パッケージング
概要
qarファイルがExtensionのファイルとなる。実態はただのzipファイル。拡張子を除けばファイル名に制約はない。
作り方
zipで固めて、拡張子をqarとするだけ。
1. フォルダー エクステンション名/をzipで固める(例:エクステンション名.zip)
2. 同ファイルをの拡張子をzipからqarへ変更する(例:エクステンション名.qar)
インストール
qarファイルはQlikViewに関連付けられていることを前提にダブルクリックするだけ。インストールが上手く行けばQlikViewのダイアログが表示される。
再インストールの際は、QlikViewのドキュメントからも一度削除し、再配置すのが無難。
アンインストール
次のフォルダから当該Extension名のフォルダを削除すればよい。
%AppData%\Local\QlikTech\QlikView\Extensions\Objects\エクステンション名
その他
QVとQVAの名前空間について
提供されるAPIは、Qv.ExtensionやQva.AddExtensionといったように、QvとQvaの名前空間(?)が混在している。QlikView v10とv11以降の違いとも言われるが、Qvに集約されたコードを見た試しがない。
参考
GitHubにもいくつか例はあるし、それらを参考にできると思う。