Skip to content

Commit

Permalink
feat: convert options to setup.
Browse files Browse the repository at this point in the history
  • Loading branch information
scopewu committed Sep 4, 2021
1 parent a17e4db commit 56c40bb
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 77 deletions.
123 changes: 47 additions & 76 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { defineComponent, h } from 'vue'
import { defineComponent, h, onMounted, onUpdated, ref } from 'vue'
import QR, { ErrorCorrectLevel } from 'qr.js'

type Modules = boolean[][]

const defaultErrorCorrectLevel = 'H'

// Thanks the `qrcode.react`
Expand All @@ -13,7 +15,7 @@ const SUPPORTS_PATH2D: boolean = (function () {
return true
})()

function QRCode(data: string, errorCorrectLevel: number): { modules: boolean[][] } {
function QRCode(data: string, errorCorrectLevel: number): { modules: Modules } {
// We'll use type===-1 to force QRCode to automatically pick the best type
return new QR(data, { typeNumber: -1, errorCorrectLevel })
}
Expand Down Expand Up @@ -58,7 +60,7 @@ function toUTF8String(str: string): string {
return utf8Str
}

function generatePath(modules: boolean[][], margin: number = 0): string {
function generatePath(modules: Modules, margin: number = 0): string {
const ops: string[] = []
modules.forEach(function (row, y) {
let start: number | null = null
Expand Down Expand Up @@ -143,100 +145,58 @@ const QRCodeVueProps = {
} as const

const QRCodeSvg = defineComponent({
render() {
const {
size,
background,
foreground,
numCells,
fgPath,
} = this

return h(
'svg',
{
width: size,
height: size,
'shape-rendering': `crispEdges`,
xmlns: 'http://www.w3.org/2000/svg',
viewBox: `0 0 ${numCells} ${numCells}`,
},
[
h('path', { fill: background, d: `M0,0 h${numCells}v${numCells}H0z` }),
h('path', { fill: foreground, d: fgPath }),
]
)
},
props: QRCodeProps,
data() {
return {
numCells: 0,
fgPath: '',
}
},
created() {
this.generate()
},
updated() {
this.generate()
},
methods: {
generate() {
const {
value,
level,
margin,
} = this
setup(props) {
const numCells = ref(0)
const fgPath = ref('')

const { modules: cells } = QRCode(toUTF8String(value), ErrorCorrectLevel[level])
const generate = () => {
const { value, level, margin } = props

this.numCells = cells.length + margin * 2
const { modules: cells } = QRCode(toUTF8String(value), ErrorCorrectLevel[level])
numCells.value = cells.length + margin * 2

// Drawing strategy: instead of a rect per module, we're going to create a
// single path for the dark modules and layer that on top of a light rect,
// for a total of 2 DOM nodes. We pay a bit more in string concat but that's
// way faster than DOM ops.
// For level 1, 441 nodes -> 2
// For level 40, 31329 -> 2
this.fgPath = generatePath(cells, margin)
fgPath.value = generatePath(cells, margin)
}
},
})

const QRCodeCanvas = defineComponent({
render() {
const {
size,
} = this
generate()

return h(
'canvas',
onUpdated(generate)

return () => h(
'svg',
{
style: { width: `${size}px`, height: `${size}px`},
width: props.size,
height: props.size,
'shape-rendering': `crispEdges`,
xmlns: 'http://www.w3.org/2000/svg',
viewBox: `0 0 ${numCells.value} ${numCells.value}`,
},
[
h('path', { fill: props.background, d: `M0,0 h${numCells.value}v${numCells.value}H0z` }),
h('path', { fill: props.foreground, d: fgPath.value }),
]
)
},
})

const QRCodeCanvas = defineComponent({
props: QRCodeProps,
mounted() {
this.generate()
},
updated() {
this.generate()
},
methods: {
generate() {
const {
value,
level,
size,
margin,
background,
foreground,
} = this
setup(props) {
const canvasEl = ref<HTMLCanvasElement>(null!)

const generate = () => {
const { value, level, size, margin, background, foreground } = props

const { modules: cells } = QRCode(toUTF8String(value), ErrorCorrectLevel[level])
const numCells = cells.length + margin * 2
const canvas: HTMLCanvasElement = this.$el
const canvas = canvasEl.value

if (!canvas) {
return;
Expand Down Expand Up @@ -271,6 +231,17 @@ const QRCodeCanvas = defineComponent({
})
}
}

onMounted(generate)
onUpdated(generate)

return () => h(
'canvas',
{
ref: canvasEl,
style: { width: `${props.size}px`, height: `${props.size}px`},
},
)
},
})

Expand Down
4 changes: 3 additions & 1 deletion webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ module.exports = (env, { mode = 'production' }) => {
resolve: {
extensions: ['.ts', '.js'],
alias: {
vue$: 'vue/dist/vue.esm-browser.js'
vue$: mode === 'production'
? 'vue/dist/vue.esm-browser.prod.js'
: 'vue/dist/vue.esm-browser.js'
},
},
module: {
Expand Down

0 comments on commit 56c40bb

Please sign in to comment.