1- import React , { PureComponent } from 'react'
2- import { Image as RNImage } from 'react-native'
3- import PropTypes from 'prop-types'
4- import Svg , { Defs , G , Rect , Path , Image , ClipPath } from 'react-native-svg'
5- import genMatrix from './genMatrix'
1+ import React , { PureComponent } from 'react' ;
2+ import { Image as RNImage } from 'react-native' ;
3+ import PropTypes from 'prop-types' ;
4+ import Svg , { Defs , G , Rect , Path , Image , ClipPath } from 'react-native-svg' ;
5+ import genMatrix from './genMatrix' ;
66
7- const DEFAULT_SIZE = 100
8- const DEFAULT_BG_COLOR = 'white'
7+ const DEFAULT_SIZE = 100 ;
8+ const DEFAULT_BG_COLOR = 'white' ;
9+
10+ /* calculate the size of the cell and draw the path */
11+ function calculateMatrix ( props ) {
12+ const { value, size, ecl, onError} = props ;
13+ try {
14+ const matrix = genMatrix ( value , ecl ) ;
15+ const cellSize = size / matrix . length ;
16+ return {
17+ value,
18+ size,
19+ cellSize,
20+ path : transformMatrixIntoPath ( cellSize , matrix )
21+ } ;
22+ } catch ( error ) {
23+ if ( onError && typeof onError === 'function' ) {
24+ onError ( error ) ;
25+ } else {
26+ // Pass the error when no handler presented
27+ throw error ;
28+ }
29+ }
30+ return { } ;
31+ }
32+
33+ /* project the matrix into path draw */
34+ function transformMatrixIntoPath ( cellSize , matrix ) {
35+ // adjust origin
36+ let d = '' ;
37+ matrix . forEach ( ( row , i ) => {
38+ let needDraw = false ;
39+ row . forEach ( ( column , j ) => {
40+ if ( column ) {
41+ if ( ! needDraw ) {
42+ d += `M${ cellSize * j } ${ cellSize / 2 + cellSize * i } ` ;
43+ needDraw = true ;
44+ }
45+ if ( needDraw && j === matrix . length - 1 ) {
46+ d += `L${ cellSize * ( j + 1 ) } ${ cellSize / 2 + cellSize * i } ` ;
47+ }
48+ } else {
49+ if ( needDraw ) {
50+ d += `L${ cellSize * j } ${ cellSize / 2 + cellSize * i } ` ;
51+ needDraw = false ;
52+ }
53+ }
54+ } ) ;
55+ } ) ;
56+ return d ;
57+ }
958
1059/**
1160 * A simple component for displaying QR Code using svg
@@ -41,6 +90,7 @@ export default class QRCode extends PureComponent {
4190 */
4291 onError : PropTypes . func
4392 } ;
93+
4494 static defaultProps = {
4595 value : 'This is a QR Code.' ,
4696 size : DEFAULT_SIZE ,
@@ -53,84 +103,52 @@ export default class QRCode extends PureComponent {
53103 ecl : 'M' ,
54104 onError : undefined
55105 } ;
56- constructor ( props ) {
57- super ( props )
58- this . _matrix = null
59- this . _cellSize = null
60- this . _path = null
61- this . setMatrix ( props )
62- }
63- componentWillUpdate ( nextProps ) {
64- // if value has changed, re-setMatrix
65- if ( nextProps . value !== this . props . value || nextProps . size !== this . props . size ) {
66- this . setMatrix ( nextProps )
67- }
106+
107+ constructor ( props ) {
108+ super ( props ) ;
109+ this . state = calculateMatrix ( props ) ;
68110 }
69- /* calculate the size of the cell and draw the path */
70- setMatrix ( props ) {
71- const { value, size, ecl, onError } = props
72- try {
73- this . _matrix = genMatrix ( value , ecl )
74- this . _cellSize = size / this . _matrix . length
75- this . _path = this . transformMatrixIntoPath ( )
76- } catch ( error ) {
77- if ( onError && typeof onError === 'function' ) {
78- onError ( error )
79- } else {
80- // Pass the error when no handler presented
81- throw error
82- }
111+
112+ static getDerivedStateFromProps ( props , state ) {
113+ // if value has changed, re-calculateMatrix
114+ if ( props . value !== state . value || props . size !== state . size ) {
115+ return calculateMatrix ( props ) ;
83116 }
117+ return null ;
84118 }
85- /* project the matrix into path draw */
86- transformMatrixIntoPath ( ) {
87- const matrix = this . _matrix
88- const cellSize = this . _cellSize
89- // adjust origin
90- let d = ''
91- matrix . forEach ( ( row , i ) => {
92- let needDraw = false
93- row . forEach ( ( column , j ) => {
94- if ( column ) {
95- if ( ! needDraw ) {
96- d += `M${ cellSize * j } ${ cellSize / 2 + cellSize * i } `
97- needDraw = true
98- }
99- if ( needDraw && j === matrix . length - 1 ) {
100- d += `L${ cellSize * ( j + 1 ) } ${ cellSize / 2 + cellSize * i } `
101- }
102- } else {
103- if ( needDraw ) {
104- d += `L${ cellSize * j } ${ cellSize / 2 + cellSize * i } `
105- needDraw = false
106- }
107- }
108- } )
109- } )
110- return d
111- }
112- render ( ) {
119+
120+ render ( ) {
113121 const {
114- getRef, size, color, backgroundColor,
115- logo, logoSize, logoMargin, logoBackgroundColor, logoBorderRadius
116- } = this . props
122+ getRef,
123+ size,
124+ color,
125+ backgroundColor,
126+ logo,
127+ logoSize,
128+ logoMargin,
129+ logoBackgroundColor,
130+ logoBorderRadius
131+ } = this . props ;
132+
133+ const logoPosition = size / 2 - logoSize / 2 - logoMargin ;
134+ const logoWrapperSize = logoSize + logoMargin * 2 ;
135+ const logoWrapperBorderRadius =
136+ logoBorderRadius + ( logoBorderRadius && logoMargin ) ;
117137
118- const logoPosition = size / 2 - logoSize / 2 - logoMargin
119- const logoWrapperSize = logoSize + logoMargin * 2
120- const logoWrapperBorderRadius = logoBorderRadius + ( logoBorderRadius && logoMargin )
138+ const { cellSize, path} = this . state ;
121139
122140 return (
123141 < Svg ref = { getRef } width = { size } height = { size } >
124142 < Defs >
125- < ClipPath id = ' clip-wrapper' >
143+ < ClipPath id = " clip-wrapper" >
126144 < Rect
127145 width = { logoWrapperSize }
128146 height = { logoWrapperSize }
129147 rx = { logoWrapperBorderRadius }
130148 ry = { logoWrapperBorderRadius }
131149 />
132150 </ ClipPath >
133- < ClipPath id = ' clip-logo' >
151+ < ClipPath id = " clip-logo" >
134152 < Rect
135153 width = { logoSize }
136154 height = { logoSize }
@@ -139,38 +157,30 @@ export default class QRCode extends PureComponent {
139157 />
140158 </ ClipPath >
141159 </ Defs >
142- < Rect
143- width = { size }
144- height = { size }
145- fill = { backgroundColor }
146- />
147- { this . _path && this . _cellSize && (
148- < Path
149- d = { this . _path }
150- stroke = { color }
151- strokeWidth = { this . _cellSize }
152- />
160+ < Rect width = { size } height = { size } fill = { backgroundColor } />
161+ { path && cellSize && (
162+ < Path d = { path } stroke = { color } strokeWidth = { cellSize } />
153163 ) }
154164 { logo && (
155165 < G x = { logoPosition } y = { logoPosition } >
156166 < Rect
157167 width = { logoWrapperSize }
158168 height = { logoWrapperSize }
159169 fill = { logoBackgroundColor }
160- clipPath = ' url(#clip-wrapper)'
170+ clipPath = " url(#clip-wrapper)"
161171 />
162172 < G x = { logoMargin } y = { logoMargin } >
163173 < Image
164174 width = { logoSize }
165175 height = { logoSize }
166- preserveAspectRatio = ' xMidYMid slice'
176+ preserveAspectRatio = " xMidYMid slice"
167177 href = { logo }
168- clipPath = ' url(#clip-logo)'
178+ clipPath = " url(#clip-logo)"
169179 />
170180 </ G >
171181 </ G >
172182 ) }
173183 </ Svg >
174- )
184+ ) ;
175185 }
176186}
0 commit comments