はじめに

NativeScript(NatvieScript-vue) で JsBarcode を使ってバーコードを 生成/描画 する方法。

通常通りの使い方ではエラーとなるため、少しトリッキーな方法を用いている。

なお、有料で良ければ @proplugins/nativescript-zxing を使うのが早いと思われる。

TL;DR

目次

  1. はじめに
  2. TL;DR
  3. 環境・条件
  4. 詳細
    1. 前置き
      1. JsBarcode の使い方
      2. NativeScript で JsBarcode を使う(NG パターン)
      3. JsBarcode の使い方2
    2. 本題: NativeScript で JsBarcode を使う(OK パターン)
  5. まとめ
  6. その他・メモ
    1. 懸念点
    2. Canvas, SVG の利用
    3. nativescript-zxing について
  7. 参考文献

環境・条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.15.4
BuildVersion: 19E287

$ node -v
v12.7.0

$ npm -v
6.10.3

$ tns --version
6.4.0

$ grep -C1 version package.json
"tns-android": {
"version": "6.0.0"
},
"tns-ios": {
"version": "6.4.2"
}

$ tns plugin
Dependencies:
┌──────────────────────────────┬─────────┐
│ Plugin │ Version │
│ @nativescript/theme │ ^2.2.1 │
│ @vue/devtools │ ^5.0.6 │
│ jsbarcode │ ^3.11.0 │
│ nativescript-socketio │ ^3.2.1 │
│ nativescript-toasty │ ^1.3.0 │
│ nativescript-vue │ ^2.4.0 │
│ nativescript-vue-devtools │ ^1.2.0 │
│ tns-core-modules │ ^6.0.0 │
└──────────────────────────────┴─────────┘
Dev Dependencies:
┌────────────────────────────────────┬─────────┐
│ Plugin │ Version │
│ @babel/core │ ^7.0.0 │
│ @babel/preset-env │ ^7.0.0 │
│ babel-loader │ ^8.0.2 │
│ nativescript-dev-webpack │ ^1.0.0 │
│ nativescript-vue-template-compiler │ ^2.0.0 │
│ nativescript-worker-loader │ ~0.9.0 │
│ node-sass │ ^4.9.2 │
│ vue-loader │ ^15.4.0 │
└────────────────────────────────────┴─────────┘

詳細

前置き

JsBarcode の使い方

一般的なブラウザで使う場合であれば、Examples の最初あたりに記載の使い方で問題ない。

以下のようにすることで <img id="code"> などの要素に対してバーコードが描画される。

1
2
const JsBarcode = require('jsbarcode');
JsBarcode('#code', 'test');

オプション指定あり

1
2
3
4
5
JsBarcode('#code', 'test', {
format: "pharmacode",
lineColor: "#0aa",
...,
});

他の呼び方

1
2
3
4
5
6
JsBarcode("#code")
.options({font: "OCR-B"})
.EAN13("1234567890128", {fontSize: 18, textMargin: 0})
.blank(20)
.EAN5("12345", {height: 85, textPosition: "top", fontSize: 16, marginTop: 15})
.render();

NativeScript で JsBarcode を使う(NG パターン)

NativeScript で前述の Examples 通りの使い方をすると ReferenceError: document is not defined のエラーになる。

これは JsBarcode の内部で document.querySelectorAll を使って描画対象の要素を取得しているが、NativeScript では document が使用できないために起きる。

<Image id="code" /> に対して JsBarcode でバーコードの描画を試行例。

コード概要

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<Page>
<ActionBar title="hello"/>
<StackLayout>
<Image id="code" src="" stretch="none" />
</StackLayout>
</Page>
</template>

<script >
const JsBarcode = require('jsbarcode');

export default {
created() {
JsBarcode('#code', 'test');
},
}
</script>

エラー内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
$ tns debug android --emulator
...
JS: [Vue warn]: Error in created hook: "ReferenceError: document is not defined"
JS:
JS: found in
JS:
JS: ---> <App> at components/App.vue
JS: <Frame>
JS: <Root>
JS: 'firebase.init success'
System.err: An uncaught Exception occurred on "main" thread.
System.err: Unable to start activity ComponentInfo{com.example/com.tns.NativeScriptActivity}: com.tns.NativeScriptException: Calling js method onCreate failed
System.err: ReferenceError: document is not defined
System.err:
System.err: StackTrace:
System.err: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example/com.tns.NativeScriptActivity}: com.tns.NativeScriptException: Calling js method onCreate failed
System.err: ReferenceError: document is not defined
System.err: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817)
System.err: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
System.err: at android.app.ActivityThread.-wrap11(Unknown Source:0)
System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
System.err: at android.os.Handler.dispatchMessage(Handler.java:105)
System.err: at android.os.Looper.loop(Looper.java:164)
System.err: at android.app.ActivityThread.main(ActivityThread.java:6541)
System.err: at java.lang.reflect.Method.invoke(Native Method)
System.err: at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
System.err: Caused by: com.tns.NativeScriptException: Calling js method onCreate failed
System.err: ReferenceError: document is not defined
System.err: at com.tns.Runtime.callJSMethodNative(Native Method)
System.err: at com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:1242)
System.err: at com.tns.Runtime.callJSMethodImpl(Runtime.java:1122)
System.err: at com.tns.Runtime.callJSMethod(Runtime.java:1109)
System.err: at com.tns.Runtime.callJSMethod(Runtime.java:1089)
System.err: at com.tns.Runtime.callJSMethod(Runtime.java:1081)
System.err: at com.tns.NativeScriptActivity.onCreate(NativeScriptActivity.java:19)
System.err: at android.app.Activity.performCreate(Activity.java:6975)
System.err: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
System.err: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
System.err: ... 9 more

JsBarcode の使い方2

ひっそりと書かれているので分かりづらいが、Retrieve the barcode values so you can render it any way you’d like に書かれている通り、描画先を指定していた第一引数に Object を渡すことで描画処理無しにバーコード生成結果を取得できる。

1101..11 となっている箇所が生成されたバーコード部分にあたる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
const data = {};
JsBarcode(data, 'test', {});

console.log(data);
// => {
// encodings: [
// {
// text: 'test',
// data: '1101001000010011110100101100100001011110010010011110100111100101001100011101011',
// options: [Object]
// }
// ]
// }

console.log(data.encodings[0].options);
// => {
// width: 2,
// height: 100,
// format: 'CODE128',
// displayValue: true,
// fontOptions: '',
// font: 'monospace',
// text: undefined,
// textAlign: 'center',
// textPosition: 'bottom',
// textMargin: 2,
// fontSize: 20,
// background: '#ffffff',
// lineColor: '#000000',
// margin: 10,
// marginTop: 10,
// marginBottom: 10,
// marginLeft: 10,
// marginRight: 10,
// valid: [Function: valid]
// }

なお、利用するフォーマットによっては data.encodings の要素数が変わるので注意。

複数に分かれている場合は、各 encodings 内の data を結合すれば最終的なコードが得られる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
JsBarcode(data, '2000000000008', { format: 'EAN13' });

console.log(data.encodings.length);
// => 6

console.log(data.encodings); // 長いので一部割愛
// [
// {
// data: '000000000000',
// text: '2',
// options: {
// width: 2,
// ...
// }
// },
// {
// data: '101',
// options: {
// width: 2,
// ...
// },
// text: ''
// },
// {
// data: '000110100011010100111010011100011010100111',
// text: '000000',
// options: {
// width: 2,
// ...
// }
// },
// ...
// ]

const code = data.encodings.map(d => d.data).join('');
console.log(code);
// => '00000000000010100011010001101010011101001110001101010011101010111001011100101110010111001011100101001000101'

本題: NativeScript で JsBarcode を使う(OK パターン)

(ある程度察しがつくと思うが) 前述の方法で得られたコードを元にして、 StackLayout 内にバーを列挙していくことで、バーコードを描画する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<template>
<StackLayout orientation="horizontal">
<Label width="5%" height="25%" />
<template v-for="(b, key) in bitmap">
<Label :backgroundColor="colors[b]" :width="`${barWidth}%`" height="25%" :key="key" />
</template>
<Label width="5%" height="25%" />
</StackLayout>
</template>

<script >
const JsBarcode = require('jsbarcode');
export default {
data() {
return {
code: '2000000000008',
bitmap: '',
barWitdh: 0,
colors: {
0: '',
1: 'black',
},
}
},
created() {
this.generateBarcode();
},
methods: {
generateBarcode() {
let data = {};
try {
JsBarcode(data, this.code, { format: 'EAN13' });
} catch (error) {
console.error({error});
return;
}

this.bitmap = data.encodings.map(encoding => encoding.data).join('');
this.barWidth = this.bitmap ? 90 / this.bitmap.length : 0;
},
},
}
</script>

ざっくり解説

  • orientation="horizontal" で水平方向にスタッキング
  • バーコードの左右余白を v-for の前後の Label で確保(10%)
  • 左右余白を除いた分(90%)をコード長で割ることで、バー1本の長さを算出
  • コードを1文字ずつ Label で処理
    • 1: backgroundColor で黒塗りつぶし
    • 0: 塗りつぶしなし

以下のような感じでバーコードを生成できる。

まとめ

その他・メモ

懸念点

描画コストがどの程度なのか、という点。

NativeScript の深い部分まで理解できていないので、StackLayout + Label での描画がどの程度重いのかが不明。

Canvas, SVG の利用

Canvas, SVG を導入して描画するという方法もあるかもしれない(試してない)ので、プラグインのリンクをメモ。

nativescript-zxing について

冒頭に簡単に書いたが、有料でよければ以下プラグインを導入することで簡単にバーコードの生成や描画が可能と思われる。

@proplugins/nativescript-zxing

料金については ProPlugins - Subscribe に記載されている。

  • 最初の500人までは月額 $9.99
  • 501人目以降は月額 $14.99(年間購読であれば月額 $12.99)

参考文献

関連記事