|
1 | | -const {create_svg_el, set_attr} = require('./dom'); |
| 1 | +const {create_svg_el, get_attr} = require('./dom'); |
2 | 2 |
|
3 | | -const wrap_ctx = ctx => { |
| 3 | +const create_draw_ctx = ctx => { |
4 | 4 | const rnd = x => Math.round(x * 10) / 10; |
| 5 | + const rndo = x => Math.round(x * 10) / 10 + ctx.o; |
5 | 6 | return { |
6 | | - m(x, y) {ctx.p += `M ${rnd(x)} ${rnd(y)} `; return this;}, |
7 | | - l(x, y) {ctx.p += `L ${rnd(x)} ${rnd(y)} `; return this;}, |
8 | | - a(x, y, rad) {ctx.p += `A ${rnd(rad)} ${rnd(rad)} 0 0 1 ${rnd(x)} ${rnd(y)} `; return this;} |
| 7 | + m(x, y) {ctx.p += `M ${rndo(x)} ${rndo(y)} `; return this;}, |
| 8 | + l(x, y) {ctx.p += `L ${rndo(x)} ${rndo(y)} `; return this;}, |
| 9 | + a(x, y, rad) {ctx.p += `A ${rnd(rad)} ${rnd(rad)} 0 0 1 ${rndo(x)} ${rndo(y)} `; return this;} |
9 | 10 | }; |
10 | 11 | }; |
11 | 12 |
|
@@ -81,57 +82,129 @@ const draw_mod = (qr, ctx, settings, width, row, col) => { |
81 | 82 | const dark_sw = is_dark(row_s, col_w); |
82 | 83 | const dark_w = is_dark(row, col_w); |
83 | 84 |
|
84 | | - ctx = wrap_ctx(ctx); |
85 | | - |
86 | 85 | if (dark_center) { |
87 | 86 | draw_dark(ctx, left, top, right, bottom, radius, !dark_n && !dark_w, !dark_n && !dark_e, !dark_s && !dark_e, !dark_s && !dark_w); |
88 | 87 | } else { |
89 | 88 | draw_light(ctx, left, top, right, bottom, radius, dark_n && dark_w && dark_nw, dark_n && dark_e && dark_ne, dark_s && dark_e && dark_se, dark_s && dark_w && dark_sw); |
90 | 89 | } |
91 | 90 | }; |
92 | 91 |
|
93 | | -const draw_modules = (qr, ctx, settings) => { |
| 92 | +const create_path = (qr, settings) => { |
94 | 93 | if (!qr) { |
95 | | - return; |
| 94 | + return ''; |
96 | 95 | } |
97 | 96 |
|
| 97 | + const ctx = {p: '', o: 0}; |
98 | 98 | const mod_count = qr.module_count; |
99 | | - const mod_size = settings.size / mod_count; |
| 99 | + let mod_size = settings.size / mod_count; |
| 100 | + if (settings.crisp) { |
| 101 | + mod_size = Math.floor(mod_size); |
| 102 | + ctx.o = Math.floor((settings.size - mod_size * mod_count) / 2); |
| 103 | + } |
100 | 104 |
|
| 105 | + const draw_ctx = create_draw_ctx(ctx); |
101 | 106 | for (let row = 0; row < mod_count; row += 1) { |
102 | 107 | for (let col = 0; col < mod_count; col += 1) { |
103 | | - draw_mod(qr, ctx, settings, mod_size, row, col); |
| 108 | + draw_mod(qr, draw_ctx, settings, mod_size, row, col); |
104 | 109 | } |
105 | 110 | } |
| 111 | + |
| 112 | + return ctx.p; |
106 | 113 | }; |
107 | 114 |
|
108 | | -const create_svg_qrcode = (qr, settings) => { |
109 | | - const ctx = {p: ''}; |
| 115 | +const add_label = (el, settings) => { |
| 116 | + console.warn('svg label not implemented yet', el, settings); |
| 117 | + const size = settings.size; |
| 118 | + const font = 'bold ' + settings.mSize * 0.01 * size + 'px ' + settings.fontname; |
| 119 | + |
| 120 | + const {create_canvas, dpr} = require('./dom'); |
| 121 | + const ratio = settings.ratio || dpr; |
| 122 | + const ctx = create_canvas(size, ratio).getContext('2d'); |
| 123 | + ctx.strokeStyle = settings.back; |
| 124 | + ctx.lineWidth = settings.mSize * 0.01 * size * 0.1; |
| 125 | + ctx.fillStyle = settings.fontcolor; |
| 126 | + ctx.font = font; |
| 127 | + const w = ctx.measureText(settings.label).width; |
| 128 | + |
| 129 | + const sh = settings.mSize * 0.01; |
| 130 | + const sw = w / size; |
| 131 | + const sl = (1 - sw) * settings.mPosX * 0.01; |
| 132 | + const st = (1 - sh) * settings.mPosY * 0.01; |
| 133 | + const x = sl * size; |
| 134 | + const y = st * size + 0.75 * settings.mSize * 0.01 * size; |
| 135 | + |
| 136 | + const text_el = create_svg_el('text', { |
| 137 | + x, |
| 138 | + y |
| 139 | + }); |
| 140 | + Object.assign(text_el.style, { |
| 141 | + font, |
| 142 | + fill: settings.fontcolor, |
| 143 | + 'paint-order': 'stroke', |
| 144 | + stroke: settings.back, |
| 145 | + 'stroke-width': ctx.lineWidth |
| 146 | + }); |
| 147 | + |
| 148 | + text_el.textContent = settings.label; |
| 149 | + el.appendChild(text_el); |
| 150 | +}; |
110 | 151 |
|
111 | | - draw_modules(qr, ctx, settings); |
112 | | - // draw_mode(ctx, settings); |
| 152 | +const add_image = (el, settings) => { |
| 153 | + const size = settings.size; |
| 154 | + const w = settings.image.naturalWidth || 1; |
| 155 | + const h = settings.image.naturalHeight || 1; |
| 156 | + const sh = settings.mSize * 0.01; |
| 157 | + const sw = sh * w / h; |
| 158 | + const sl = (1 - sw) * settings.mPosX * 0.01; |
| 159 | + const st = (1 - sh) * settings.mPosY * 0.01; |
| 160 | + const x = sl * size; |
| 161 | + const y = st * size; |
| 162 | + const iw = sw * size; |
| 163 | + const ih = sh * size; |
| 164 | + |
| 165 | + const img_el = create_svg_el('image', { |
| 166 | + href: get_attr(settings.image, 'src'), |
| 167 | + x, |
| 168 | + y, |
| 169 | + width: iw, |
| 170 | + height: ih |
| 171 | + }); |
| 172 | + el.appendChild(img_el); |
| 173 | +}; |
113 | 174 |
|
| 175 | +const create_svg_qrcode = (qr, settings) => { |
114 | 176 | const size = settings.size; |
115 | | - const svg_el = create_svg_el('svg'); |
116 | | - set_attr(svg_el, 'xmlns', 'http://www.w3.org/2000/svg'); |
117 | | - set_attr(svg_el, 'width', size); |
118 | | - set_attr(svg_el, 'height', size); |
119 | | - set_attr(svg_el, 'viewBox', `0 0 ${size} ${size}`); |
| 177 | + const mode = settings.mode; |
| 178 | + |
| 179 | + const svg_el = create_svg_el('svg', { |
| 180 | + xmlns: 'http://www.w3.org/2000/svg', |
| 181 | + width: size, |
| 182 | + height: size, |
| 183 | + viewBox: `0 0 ${size} ${size}` |
| 184 | + }); |
120 | 185 | svg_el.style.width = `${size}px`; |
121 | 186 | svg_el.style.height = `${size}px`; |
122 | 187 |
|
123 | | - const rect_el = create_svg_el('rect'); |
124 | | - set_attr(rect_el, 'x', 0); |
125 | | - set_attr(rect_el, 'y', 0); |
126 | | - set_attr(rect_el, 'width', size); |
127 | | - set_attr(rect_el, 'height', size); |
128 | | - set_attr(rect_el, 'fill', settings.back); |
129 | | - svg_el.appendChild(rect_el); |
130 | | - |
131 | | - const path_el = create_svg_el('path'); |
132 | | - set_attr(path_el, 'd', ctx.p); |
133 | | - set_attr(path_el, 'fill', settings.fill); |
134 | | - svg_el.appendChild(path_el); |
| 188 | + if (settings.back) { |
| 189 | + svg_el.appendChild(create_svg_el('rect', { |
| 190 | + x: 0, |
| 191 | + y: 0, |
| 192 | + width: size, |
| 193 | + height: size, |
| 194 | + fill: settings.back |
| 195 | + })); |
| 196 | + } |
| 197 | + |
| 198 | + svg_el.appendChild(create_svg_el('path', { |
| 199 | + d: create_path(qr, settings), |
| 200 | + fill: settings.fill |
| 201 | + })); |
| 202 | + |
| 203 | + if (mode === 'label') { |
| 204 | + add_label(svg_el, settings); |
| 205 | + } else if (mode === 'image') { |
| 206 | + add_image(svg_el, settings); |
| 207 | + } |
135 | 208 |
|
136 | 209 | return svg_el; |
137 | 210 | }; |
|
0 commit comments