https://gyazo.com/d4a1129d1731efa551e6a013e02f8ed0
基本情報
ソースコード
デモ
IndexedDBはファイルやblobなどのデータをクライアントサイドに保存できます。
今まで作ってきたものではページを更新したりするたびに、VRMファイルを読み込み直す必要があり面倒でした。
IndexedDBを使ってページ更新後もVRMを保持できるようにしてみます。
IndexedDBにモデルデータを保存
DBの更新、ストアの新規作成を行います。
code:localDB.ts
const version = 1;
const dbName = 'AvatarDatabase';
const storeName = 'model';
export const initDB = () => {
const request = window.indexedDB.open(dbName, version);
request.onupgradeneeded = (event) => {
console.log('DB create/update');
const target = event.target as IDBOpenDBRequest;
const idbDB = target.result;
if (event.oldVersion < 1) {
idbDB.createObjectStore(storeName, { keyPath: 'name' })
}
idbDB.close();
}
}
モデルデータの保存
vrmファイルをblobとして保存します。
今回は1体だけ保持するので同じキーでputして上書きしてしまうようにしました。
code:localDB.ts
export const dbSaveModel = (model: Blob) => {
const request = window.indexedDB.open(dbName, version);
request.onsuccess = function (event) {
const target = event.target as IDBOpenDBRequest;
const idbDB = target.result;
const transaction = idbDB.transaction(storeName, 'readwrite');
const store = transaction.objectStore(storeName);
// 上書き
const putRequest = store.put({
'model': model,
'name': 'ONE_MODEL_ONLY'
});
putRequest.onsuccess = () => {
console.log('db:put success');
idbDB.close();
}
putRequest.onerror = () => {
console.log('db:put error');
}
};
}
モデルデータのロード
code:localDB.ts
export const dbLoadModel = (onLoad: (blob: Blob) => void): void => {
const request = window.indexedDB.open(dbName, version);
request.onsuccess = function (event) {
const target = event.target as IDBOpenDBRequest;
const idbDB = target.result;
const transaction = idbDB.transaction(storeName, 'readonly');
const store = transaction.objectStore(storeName);
const getRequest = store.get('ONE_MODEL_ONLY');
getRequest.onsuccess = (event) => {
const target = event.target as IDBRequest;
if (!target.result)
return;
const model = target.result.model;
if (!model)
return;
onLoad(model);
idbDB.close();
};
getRequest.onerror = () => {
console.log('db:load error');
}
}
}
vrmとして読み込み
本当は作成したオブジェクトURL を明示的にアンロードした方が良いです。
code:index.ts
// indexDBからモデルの読み込み
dbLoadModel(
(blob) => {
const url = URL.createObjectURL(blob);
avatar.loadVRM(url);
}
);
ソースコード
動作確認
動作確認
デモページ
最初にページを開いたときはアバターが表示されません。
サンプルモデルを読み込むかファイルを選択から自分のアバターを読み込んだ後にページを更新するとそのアバターが読み込まれるはずです。
https://gyazo.com/d4a1129d1731efa551e6a013e02f8ed0
(おまけ)VRMサンプル集
そのためにサンプル集のようなリポジトリを作ることにしました。
パッケージの追加や設定の変更をします。
HtmlWebpackPlugin
HTMLも出力したいので追加
webpackの設定を変更
code:webpack.config.js
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'src/html/index.html'
})
]
code:webpack.config.js
output: {
path: path.resolve(__dirname, ../docs/${path.basename(__dirname)}),
publicPath: /${path.basename(__dirname)},
filename: "app.js"
},
webpack-dev-serverの設定も更新します
code:webpack.config.js
devServer: {
open: true,
openPage: ${path.basename(__dirname)}/index.html,
contentBase: path.resolve(__dirname, ../docs),
watchContentBase: true,
port: 8080,
},
サンプル間で共通部分を使いまわせるように変更しました。
ディレクトリ構造
ToyBox
node_modules
docs (github pages で公開する)
sample.vrm
index.html
SampleA
SampleB (出力先)
index.html
app.js
SampleA
SampleB
src
html
index.html
ts
index.ts
気まぐれにサンプルが追加されていくと思います。
けしごむ.iconたぶん。
参考