Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added fillTheParentElement feature and added responsive sizes about issue #27 #52

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ An optional size in pixels to render at

**Default:** automatic size based on the value provided (recommended)

#### fillTheParentElement: boolean (optional)
If this value is true then `size` value will be overridden. The new `size` value will be equal to the parent element's width.

#### debounceTime: number (optional)
If fillTheParentElement is `true`, `resize` event will trigger in every `debounceTime` ms. Default value is `100`.

#### darkColor: RGBAColor (optional)
An RGBA Hex string to use as the color for the dark / filled modules.
If an invalid value is passed, the default will be used.
Expand Down
142 changes: 112 additions & 30 deletions projects/ng-qrcode-demo/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,96 @@
<div class="header">
<qr-code value="https://www.npmjs.com/package/ng-qrcode" size="40"></qr-code>

<h1>
ng-qrcode demo
</h1>
<h1>ng-qrcode demo</h1>

<span style="flex: 1 1 auto"></span>

<a href="https://github.com/mnahkies/ng-qrcode" rel="noreferrer" target="_blank">
<img alt="GitHub stars" height="20px" src="https://img.shields.io/github/stars/mnahkies/ng-qrcode.svg">
<a
href="https://github.com/mnahkies/ng-qrcode"
rel="noreferrer"
target="_blank"
>
<img
alt="GitHub stars"
height="20px"
src="https://img.shields.io/github/stars/mnahkies/ng-qrcode.svg"
/>
</a>

<a href="https://www.npmjs.com/package/ng-qrcode" rel="noreferrer" target="_blank">
<img alt="npm" height="20px" src="https://img.shields.io/npm/v/ng-qrcode.svg">
<a
href="https://www.npmjs.com/package/ng-qrcode"
rel="noreferrer"
target="_blank"
>
<img
alt="npm"
height="20px"
src="https://img.shields.io/npm/v/ng-qrcode.svg"
/>
</a>
</div>

<div class="container">
<div class="body">

<h3>Inputs:</h3>
<form ngForm>
<label for="value">Value</label>
<input id="value" name="value" [(ngModel)]="value"/>

<label for="size">Size</label>
<input id="size" name="size" [(ngModel)]="size"/>
<input id="value" name="value" [(ngModel)]="value" />

<label for="fillparent">Fill The Parent</label>
<input
id="fillparent"
name="fillparent"
[(ngModel)]="fillParentElement"
type="checkbox"
/>

<ng-container *ngIf="!fillParentElement; else fillTheParentSettings">
<label for="size">Size</label>
<input id="size" name="size" [(ngModel)]="size" />
</ng-container>

<ng-template #fillTheParentSettings>
<label for="columnsize">Column Size</label>
<select
id="columnsize"
name="columnsize"
[(ngModel)]="columnSize"
>
<option
value="{{ i + 1 }}"
*ngFor="let col of [].constructor(12); let i = index"
>
{{ i + 1 }}
</option>
</select>

<label for="debounce-time">
Debounce Time
</label>
<input
id="debounce-time"
type="number"
name="debounce-time"
[(ngModel)]="debounceTime"
/>
</ng-template>

<label for="darkColor">Dark Color</label>
<input id="darkColor" name="size" [(ngModel)]="darkColor"/>
<input id="darkColor" name="size" [(ngModel)]="darkColor" />

<label for="lightColor">Light Color</label>
<input id="lightColor" name="size" [(ngModel)]="lightColor"/>
<input id="lightColor" name="size" [(ngModel)]="lightColor" />

<label for="errorCorrectionLevel">Error Correction Level</label>
<select id="errorCorrectionLevel" name="errorCorrectionLevel" [(ngModel)]="errorCorrectionLevel">
<option *ngFor="let value of errorCorrectionLevels" [value]="value">{{value}}</option>
<select
id="errorCorrectionLevel"
name="errorCorrectionLevel"
[(ngModel)]="errorCorrectionLevel"
>
<option *ngFor="let value of errorCorrectionLevels" [value]="value">
{{ value }}
</option>
</select>

<label for="showImage">Show Image in Center?</label>
Expand All @@ -46,29 +101,56 @@ <h3>Inputs:</h3>
</select>

<label for="centerImageSize">Center Image Size</label>
<input id="centerImageSize" name="centerImageSize" [(ngModel)]="centerImageSize"/>
<input
id="centerImageSize"
name="centerImageSize"
[(ngModel)]="centerImageSize"
/>

<label for="margin">Margin</label>
<input id="margin" name="margin" [(ngModel)]="margin"/>

<input id="margin" name="margin" [(ngModel)]="margin" />
</form>

<h3>Usage:</h3>
<pre [innerText]="example">
</pre>
<pre [innerText]="example"></pre>

<h3>Result:</h3>
<div class="container">
<qr-code [value]="value"
[size]="size"
[darkColor]="darkColor"
[lightColor]="lightColor"
[errorCorrectionLevel]="errorCorrectionLevel"
[centerImageSrc]="centerImageSrc"
[centerImageSize]="centerImageSize ? this.centerImageSize : undefined"
[margin]="margin">
</div>

<div class="row">
<div class="container" *ngIf="!fillParentElement; else previewFillParent">
<qr-code
[value]="value"
[size]="size"
[darkColor]="darkColor"
[lightColor]="lightColor"
[errorCorrectionLevel]="errorCorrectionLevel"
[centerImageSrc]="centerImageSrc"
[centerImageSize]="centerImageSize ? this.centerImageSize : undefined"
[margin]="margin"
>
</qr-code>
</div>

<ng-template #previewFillParent>
<div class="col-{{ columnSize }}">
<ng-container>
<qr-code
[fillTheParentElement]="true"
[debounceTime]="debounceTime"
[value]="value"
[darkColor]="darkColor"
[lightColor]="lightColor"
[errorCorrectionLevel]="errorCorrectionLevel"
[centerImageSrc]="centerImageSrc"
[centerImageSize]="
centerImageSize ? this.centerImageSize : undefined
"
[margin]="margin"
>
</qr-code>
</ng-container>
</div>
</ng-template>
</div>
</div>
27 changes: 26 additions & 1 deletion projects/ng-qrcode-demo/src/app/app.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@
pre {
background-color: lightgray;
white-space: pre-wrap;
word-break: keep-all
word-break: keep-all;
}

.container {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
width: 100%;
}

.body {
Expand All @@ -40,3 +43,25 @@ form {
grid-gap: 1rem;
grid-template-columns: auto 1fr;
}

.row {
margin-left: 0;
margin-right: 0;
display: flex;
flex-wrap: wrap;
justify-content: center;
width: 100%;
}

@for $i from 1 through 12 {
.col-#{$i} {
flex: 0 0 #{$i * calc(100% / 12)};
max-width: 100%;

qr-code {
width: 100%;
position: relative;
display: block;
}
}
}
18 changes: 12 additions & 6 deletions projects/ng-qrcode-demo/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,26 @@ export class AppComponent {
darkColor?: RGBAColor
lightColor?: RGBAColor

fillParentElement = false
debounceTime = 100
columnSize = "3"

get centerImageSrc() {
return this.showImage === "yes" ? "./assets/angular-logo.png" : undefined
}

get example() {
return `
<qr-code value="${ this.value }"
size="${ this.size }"${this.darkColor ? `
<qr-code value="${this.value}"
size="${this.size}"${this.darkColor ? `
darkColor="${this.darkColor}"` : ""}${this.lightColor ? `
lightColor="${this.lightColor}"` : ""}
errorCorrectionLevel="${ this.errorCorrectionLevel }"
centerImageSrc="${ this.centerImageSrc }"
centerImageSize="${ this.centerImageSize ? parseInt(this.centerImageSize, 10) : undefined }"
margin="${ this.margin }">
errorCorrectionLevel="${this.errorCorrectionLevel}"
centerImageSrc="${this.centerImageSrc}"
centerImageSize="${this.centerImageSize ? parseInt(this.centerImageSize, 10) : undefined}"
margin="${this.margin}"${this.fillParentElement ? `
[fillTheParentElement]=\"true\"` : ""}${this.fillParentElement ? `
[debounceTime]="${this.debounceTime}"` : ""}>
</qr-code>`
}

Expand Down
7 changes: 7 additions & 0 deletions projects/ng-qrcode/src/lib/qr-code.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { QrCodeErrorCorrectionLevel, RGBAColor } from "./types"
[height]="size"
[darkColor]="darkColor"
[lightColor]="lightColor"
[fillTheParentElement]="fillTheParentElement"
[debounceTime]="debounceTime"
>
</canvas>
`,
Expand All @@ -34,6 +36,9 @@ export class QrCodeComponent {
@Input()
lightColor?: RGBAColor

@Input()
fillTheParentElement?: boolean

@Input()
errorCorrectionLevel?: QrCodeErrorCorrectionLevel

Expand All @@ -46,4 +51,6 @@ export class QrCodeComponent {
@Input()
margin?: number

@Input()
debounceTime?: number
}
42 changes: 39 additions & 3 deletions projects/ng-qrcode/src/lib/qr-code.directive.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Directive, Input, isDevMode, OnChanges, ViewContainerRef } from "@angular/core"
import { Directive, Input, isDevMode, OnChanges, OnDestroy, OnInit, ViewContainerRef } from "@angular/core"
import qrcode from "qrcode"
import { QrCodeErrorCorrectionLevel, RGBAColor } from "./types"

Expand All @@ -8,7 +8,7 @@ const validColorRegex = /^#(?:[0-9a-fA-F]{3,4}){1,2}$/
// eslint-disable-next-line @angular-eslint/directive-selector
selector: `canvas[qrCode]`,
})
export class QrCodeDirective implements OnChanges {
export class QrCodeDirective implements OnChanges, OnInit, OnDestroy {

static readonly DEFAULT_ERROR_CORRECTION_LEVEL: QrCodeErrorCorrectionLevel = "M"
static readonly DEFAULT_CENTER_IMAGE_SIZE = 40
Expand All @@ -24,8 +24,10 @@ export class QrCodeDirective implements OnChanges {

@Input() width?: number
@Input() height?: number
@Input() fillTheParentElement?: boolean
@Input() darkColor: RGBAColor = "#000000FF"
@Input() lightColor: RGBAColor = "#FFFFFFFF"
@Input() debounceTime = 100

// eslint-disable-next-line @angular-eslint/no-input-rename
@Input("qrCodeCenterImageSrc") centerImageSrc?: string
Expand All @@ -37,6 +39,8 @@ export class QrCodeDirective implements OnChanges {
// eslint-disable-next-line @angular-eslint/no-input-rename
@Input("qrCodeMargin") margin = 16

private resizeEventObserver: ResizeObserver | undefined

private centerImage?: HTMLImageElement

constructor(
Expand All @@ -61,7 +65,6 @@ export class QrCodeDirective implements OnChanges {
}

const canvas = this.viewContainerRef.element.nativeElement as HTMLCanvasElement | null

if (!canvas) {
// native element not available on server side rendering
return
Expand All @@ -87,6 +90,15 @@ export class QrCodeDirective implements OnChanges {
console.error("[ng-qrcode] lightColor set to invalid value, must be RGBA hex color string, eg: #3050A130")
}
}

if (this.fillTheParentElement) {
const PARENT = canvas?.parentElement

if (PARENT) {
this.width = PARENT.clientWidth
}
}

await qrcode
.toCanvas(canvas, this.value, {
version: this.version,
Expand Down Expand Up @@ -134,6 +146,30 @@ export class QrCodeDirective implements OnChanges {

}

ngOnInit(): void {
if (this.fillTheParentElement) {
const QRCODECOMPONENT = this.viewContainerRef.element.nativeElement?.parentElement

if (QRCODECOMPONENT) {
let debounceTimeout: NodeJS.Timeout
this.resizeEventObserver = new ResizeObserver(async () => {
clearTimeout(debounceTimeout)
debounceTimeout = setTimeout(async () => {
await this.ngOnChanges()
}, this.debounceTime)
})

this.resizeEventObserver.observe(QRCODECOMPONENT)
}
}
}

ngOnDestroy(): void {
if (this.resizeEventObserver) {
this.resizeEventObserver.disconnect()
}
}

}

function getIntOrDefault(value: string | number | undefined, defaultValue: number): number {
Expand Down