iPad向けCSS対応

端末サイズによって font-size を変えたい時、rem を使うと思いますが、意外と rem は万能ではなく、iPad だとかなり小さく見えます。

なので以下のように端末サイズによって分岐して指定した方が良いです。

1
2
3
4
5
6
7
8
9
10
11
12
13
/* for iPad */
@media screen and (min-width: 768px) {
html {
font-size: 1.2rem;
}
}

/* for iPhone */
@media screen and (max-width: 767px) {
html {
font-size: 0.7rem;
}
}

【Vue.js】モーダルコンポーネントのサンプル

Vue.js のモーダルコンポーネントのサンプルです。

モーダルコンポーネント

MyModal.vue

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<template>
<transition name="b2t">
<div class="modal-wrapper" @click.self.stop="$emit('hide')" v-if="isOpened">
<div id="modal" class="modal-container">
<div class="hide" @click="$emit('hide')">
<i class="far fa-times"></i>
</div>
</div>
</div>
</transition>
</template>

<script>
export default {
props: {
isOpened: false,
},
}
</script>

<style scoped="" lang="scss">
.modal {
&-wrapper {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
background: rgba(0, 0, 0, 0.6);
z-index: 10000;
}
&-container {
position: fixed;
top: 20vh;
left: 10vw;
width: 80vw;
background-color: white;
border-radius: 15px 15px 0px 0px;
padding: 15px;
padding-top: 5vh;
overflow: auto;
}
}

.hide {
position: absolute;
top: 0;
right: 2vw;
font-size: 2.5rem;
}

.b2t-enter-active,
.b2t-leave-active {
transition: opacity 300ms;
}
.b2t-enter-active > .modal-container,
.b2t-leave-active > .modal-container {
transition: all 300ms;
}
.b2t-enter > .modal-container {
transform: translateX(100vw);
}
.b2t-leave-to > .modal-container {
transform: translateX(100vw);
}
</style>

モーダルコンポーネントを呼び出すコンポーネント

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<MyModal
:isOpened="isOpenModal"
@hide="isOpenModal = false"
/>
</template>

<script>
import MyModal from '@/components/MyModal.vue';

export default {
components: {
MyModal,
},
data() {
return {
isOpenModal: false,
};
},
}

モーダル表示時に後ろをスクロールしないようにする

モーダル表示時のみ body に overflow を追加すれば OK です。

1
2
3
4
5
6
7
8
9
watch: {
modalOpened(new_status, old_status) {
if (new_status) {
document.querySelector('body').style.overflow = 'hidden';
} else {
document.querySelector('body').style.overflow = 'visible';
}
},
},

モーダル画面にoverflow: auto;を付けるのも忘れずに。

JavaScriptでバーコードを読み取る方法

利用ライブラリ

利用ライブラリ
https://github.com/ericblade/quagga2

※元々はhttps://github.com/serratus/quaggaJS の方ですが保守されていないのでフォークされた上の方が良いです

コード

html

1
2
3
4
5
<button type="button" class="btn btn-fab btn-round btn-info btc_scan" name="btc_scan"></button>
<!-- スキャンエリア -->
<div class="scan_area" style="height: 100vh; display:none">
<div id="photo-area" class="viewport"></div>
</div>

js

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// スキャン
function register_btc_scan() {
$('.btc_scan').on('click', (event) => {
$('.scan_area').show()
startScanner()
scrollTo(0, 0)
})
const startScanner = () => {
Quagga.init(
{
inputStream: {
numOfWorkers: 0,
frequency: 1,
name: 'Live',
type: 'LiveStream',
target: document.querySelector('#photo-area'),
constraints: {
decodeBarCodeRate: 3,
successTimeout: 500,
codeRepetition: false,
tryVertical: true,
frameRate: 15,
facingMode: 'environment',
},
},
decoder: {
readers: ['ean_reader'],
},
},
function (err) {
if (err) {
console.log(err)
return
}
console.log('Initialization finished. Ready to start')
Quagga.start()
_scannerIsRunning = true
}
)
Quagga.onProcessed(_onProcessed)
Quagga.onDetected(_onDetected)
}
}
// スキャン中
function _onProcessed(result) {
var drawingCtx = Quagga.canvas.ctx.overlay,
drawingCanvas = Quagga.canvas.dom.overlay
if (result) {
if (result.boxes) {
drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute('width')), parseInt(drawingCanvas.getAttribute('height')))
result.boxes
.filter(function (box) {
return box !== result.box
})
.forEach(function (box) {
Quagga.ImageDebug.drawPath(
box,
{
x: 0,
y: 1,
},
drawingCtx,
{
color: 'green',
lineWidth: 2,
}
)
})
}
if (result.box) {
Quagga.ImageDebug.drawPath(
result.box,
{
x: 0,
y: 1,
},
drawingCtx,
{
color: '#00F',
lineWidth: 2,
}
)
}
if (result.codeResult && result.codeResult.code) {
Quagga.ImageDebug.drawPath(
result.line,
{
x: 'x',
y: 'y',
},
drawingCtx,
{
color: 'red',
lineWidth: 3,
}
)
}
}
}

function _getMedian(arr) {
arr.sort((a, b) => a - b)
const half = Math.floor(arr.length / 2)
if (arr.length % 2 === 1)
// Odd length
return arr[half]
return (arr[half - 1] + arr[half]) / 2.0
}

let codes = []

// 検知した
function _onDetected(result) {
// 1つでもエラー率0.16以上があれば除外
let is_err = false
$.each(result.codeResult.decodedCodes, function (id, error) {
if (error.error != undefined) {
if (parseFloat(error.error) > 0.16) {
is_err = true
}
}
})
if (is_err) return

// エラー率のmedianが0.05以上なら除外
const errors = result.codeResult.decodedCodes.filter((_) => _.error !== undefined).map((_) => _.error)
const median = _getMedian(errors)
if (median > 0.05) {
return
}

// 3連続同じ数値だった場合のみ採用する
codes.push(result.codeResult.code)
if (codes.length < 3) return
let is_same_all = false
if (codes.every((v) => v === codes[0])) {
is_same_all = true
}
if (!is_same_all) {
codes.shift()
return
}

alert(result.codeResult.code)
$('.scan_area').hide()
Quagga.stop()
Quagga.offProcessed(_onProcessed)
Quagga.offDetected(_onDetected)
}

そのままだと画面いっぱいのサイズにならないので以下を追加して画面いっぱいのサイズになるようにしました
無理やり感ありますが、、

1
2
3
4
5
6
7
8
#photo-area.viewport video {
transform: translateX(-20vw) translateY(-30vw);
width: 120vw;
}

#photo-area.viewport canvas {
transform: translateX(-20vw) translateY(-200vw);
}

Kotlinの勉強メモ

日本語化
https://sukkiri.jp/technologies/ides/intellij-idea/intellij-idea-mac.html

Kotlin Bootcamp for Programmers 2
https://codelabs.developers.google.com/codelabs/kotlin-bootcamp-basics/#0

  • 変数を宣言する時に自動的に型が設定される(明示的に型を宣言することも可能)
  • 変数に別の方の値を代入するとエラーになる(自動的に型変換されない)
  • val→ 値を変更不可能
  • var→ 値を変更可能
  • 変数の結合は+演算子
  • 通常は変数に null を入れることはできない
  • 入れたい場合はvar marbles: Int? = nullのように?を付けて宣言する
  • null だったらエラーを吐く場合は!!を使う →val len = s!!.length
  • リストの宣言は listOf→val school = listOf("mackerel", "trout", "halibut")
  • 配列の宣言は listOf→val school = arrayOf("shark", "salmon", "minnow")
  • リストは要素数が可変だけど配列の方がアクセスが早い

配列を for ループ

1
2
3
4
val school = arrayOf("shark", "salmon", "minnow")
for (element in school) {
print(element + " ")
}

配列をインデックス付きの for ループ

1
2
3
for ((index, element) in school.withIndex()) {
println("Item at $index is $element\n")
}
  • main()に引数を渡す →[実行]> [構成の編集]>[プログラム引数]

関数を1行で書く

1
fun isTooHot(temperature: Int) = temperature > 30

リストから一部だけ抽出

1
2
3
4
5
6
val decorations = listOf("rock", "pagoda", "plastic plant", "alligator", "flowerpot")
// 先頭がpの文字列だけを抽出
val eager = decorations.filter({x -> x[0] == 'p'})
// 以下は等価
// val eager = decorations.filter {it[0] == 'p'}
println("eager: $eager")

ラムダ関数

  • ラムダ関数(無名関数)を waterFilter 変数に入れている
  • 引数として Int 型を受け取り、Int 型を返す
1
2
3
4
5
6
val waterFilter: (Int) -> Int = { dirty -> dirty / 2 }

// 引数が1つの場合はitとして表現可能
val waterFilter: (Int) -> Int = { it / 2 }

waterFilter(10)

関数を引数に与える時は::を使う

1
2
fun increaseDirty( start: Int ) = start + 1
println(updateDirty(15, ::increaseDirty))
1
2
fun increaseDirty( start: Int ) = start + 1
println(updateDirty(15, ::increaseDirty))

クラスの変数に設定できる修飾子は以下の4つ
アクセス可能な範囲は以下の通り

  1. public→ どこからでも
  2. internal→ 同じモジュール内であれば
  3. private→ 同じクラス内であれば
  4. protected→ 同じサブクラス内であれば

クラスやクラス内変数はデフォルトだとサブクラスによる上書きはできない
上書きを許可する場合はopenをつける →open val shape = "rectangle"

Aquarium クラスを TowerTank がオーバーライドする例

1
2
3
4
5
6
7
class TowerTank (override var height: Int, var diameter: Int): Aquarium(height = height, width = diameter, length = diameter) {
override var volume: Int
// ellipse area = π * r1 * r2
get() = (width/2 * length/2 * height / 1000 * PI).toInt()
set(value) {
height = ((value * 1000 / PI) / (width/2 * length/2)).toInt()
}
  • ラムダ式のreturnは外側の関数のreturnとなる
  • 関数の早期脱出が目的であればラムダ式ではなく代わりに匿名関数を利用する必要がある

CSSで改行を反映させる方法

CSS で改行を反映させる方法

style="white-space: pre-wrap;"

簡単ですがすぐ忘れちゃうのでメモ。。

VSCode で複数行に跨がる文字列を検索したいとき

例えば以下のような状態で appole と orange が含まれる箇所を検索したい場合など

hoge hoge apple hogehoge
ダミー行
ダミー行
hoge orange hogehoge

以下のように指定すれば OK
入力欄の右端にある正規表現チェックにチェックするのを忘れずに

1
2
apple
*[\s\S]*?orange

ITMS-90809-Deprecated-API-Usageエラーの解消

ITMS-90809-Deprecated-API-Usage エラーの解消方法です。

  1. config.xml に以下の1文を追加する

<preference name="WKWebViewOnly" value="true" />

  1. 以下を実行する
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# エラー要因となるプラグインをアンインストール
cordova plugin rm cordova-plugin-wkwebview-engine

# 最新のcordova-plugin-ionic-webviewプラグインをインストール
cordova plugin rm cordova-plugin-ionic-webview
cordova plugin add cordova-plugin-ionic-webview@latest

# 他のプラグインも最新化する
npm install -g cordova-check-plugins
cordova-check-plugins --update=auto

# cordova-iosを6.0.0に
cordova platform remove ios
cordova platform add ios@6.0.0

参考
https://ionicframework.com/blog/understanding-itms-90809-uiwebview-api-deprecation/

JavaScriptでクリップボードにコピーする

html 部分

1
2
<input id="user_id" type="text" style="display: none" value="コピー対象の文言" />
<button class="btn btn-secondary" onclick="copyToClipboard('user_id')">クリップボードにコピー</button>

JavaScript 部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script type="text/javascript">
function copyToClipboard(id) {
var copyTarget = document.getElementById(id)

var textarea = document.createElement('textarea')
textarea.textContent = copyTarget.value
document.body.appendChild(textarea)

var selection = document.getSelection()
var range = document.createRange()
range.selectNode(textarea)
selection.removeAllRanges()
selection.addRange(range)

console.log('copy success', document.execCommand('copy'))
selection.removeAllRanges()

document.body.removeChild(textarea)

alert('コピー完了 : ' + copyTarget.value)
}
</script>

ググると以下のやり方が出てきましたが、これだと Chrome でコピーできないので上のやり方にしました
https://www.w3schools.com/howto/howto_js_copy_clipboard.asp

参考
https://stackoverflow.com/questions/47879184/document-execcommandcopy-not-working-on-chrome?rq=1

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×