Skip to content

Commit

Permalink
Merge pull request #285 from e-picsa/feat/custom-drawing-integration
Browse files Browse the repository at this point in the history
Feat/custom drawing integration
  • Loading branch information
chrismclarke authored Jun 5, 2024
2 parents dd8a69a + f5ab6a6 commit b6550c7
Show file tree
Hide file tree
Showing 15 changed files with 184 additions and 144 deletions.

This file was deleted.

Empty file.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { BudgetMaterialModule } from '../material.module';
// Components
import { BudgetBalanceDotValueComponent } from './balance/balance-dot-value/dot-value';
import { BudgetBalanceLegendComponent } from './balance/balance-legend/balance-legend';
import { BudgetDrawComponent } from './budget-draw/budget-draw.component';
import { BudgetSummaryComponent } from './budget-summary/budget-summary.component';
import { BudgetCardComponent } from './card/budget-card';
import { BudgetCardImageComponent } from './card/card-image/budget-card-image';
Expand Down Expand Up @@ -72,7 +71,7 @@ const components = [
RouterModule,
MatTooltipModule,
MatIconModule,
PicsaDrawingComponent
PicsaDrawingComponent,
],
exports: components,
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,15 @@ export class BudgetCardImageComponent implements OnInit, OnDestroy {
// so convert to html that embeds within an <img> tag and div innerhtml
private convertSVGToImageData(svgTag: string) {
const encodedSVG = this._encodeSVG(svgTag);
const Html = `<img class='card-image' style='width:100%;height:100%;' src="data:image/svg+xml,${encodedSVG}"/>`;
const Html = `<img class='card-image' style='width:100%;height:100%;' src="${encodedSVG}"/>`;
return this.sanitizer.bypassSecurityTrustHtml(Html);
}

// method taken from http://yoksel.github.io/url-encoder/
// applies selective replacement of uri characters
private _encodeSVG(data: string): string {
const symbols = /[\r\n%#()<>?[\\\]^`{|}]/g;
data = data.replace(/"/g, "'");
data = data.replace(/>\s{1,}</g, '><');
data = data.replace(/\s{2,}/g, ' ');
return data.replace(symbols, encodeURIComponent);
// ignore already encoded
if (data.startsWith('data:')) return data;
return `data:image/svg+xml;base64,${btoa(data)}`;
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
<mat-card appearance="outlined" mat-elevation-z4 class="budget-card selectable">
<!-- <mat-card appearance="outlined" mat-elevation-z4 class="budget-card selectable">
<budget-card-image [card]="card"></budget-card-image>
<div class="card-title">{{ card.label | translate }}</div>
</mat-card>
<mat-form-field>
</mat-card> -->

<picsa-custom-drawing (onChange)="setBudgetDrawing($event)"></picsa-custom-drawing>
<mat-form-field class="label-input">
<mat-label>{{'Card Label' | translate}}</mat-label>
<input matInput [(ngModel)]="card.label" />
</mat-form-field>
<button mat-stroked-button (click)="save()" [disabled]="card.label === ''" style="margin-top: 1em; width: 70%">
<button mat-stroked-button (click)="save()" [disabled]="!card.label || !imgData" style="margin-top: 1em; width: 70%">
<mat-icon>check</mat-icon>{{ 'Save' | translate }}
</button>
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@
background: #dcdcdc;
overflow: auto;
}
.label-input {
width: 100%;
margin-top: 1rem;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,24 @@ import { IBudgetCard } from '../../../schema';
templateUrl: './card-new-dialog.html',
styleUrls: ['./card-new-dialog.scss'],
})
// eslint-disable-next-line @angular-eslint/component-class-suffix
export class BudgetCardNewDialog {
public card: IBudgetCard;
constructor(public dialogRef: MatDialogRef<BudgetCardNewDialog>, @Inject(MAT_DIALOG_DATA) card: IBudgetCard) {
this.card = card;
}

public imgData: string;

public setBudgetDrawing(svgData: string) {
if (svgData) {
this.imgData = `data:image/svg+xml;base64,${btoa(svgData)}`;
}
}
save() {
this.card.id = this.card.label.replace(/\s+/g, '-').toLowerCase();
this.card.id = `custom_${this.card.label.replace(/\s+/g, '-').toLowerCase()}`;
this.card.customMeta = {
imgData: this.generateImage(this.card.label),
imgData: this.imgData,
dateCreated: new Date().toISOString(),
createdBy: '',
};
Expand All @@ -26,7 +35,7 @@ export class BudgetCardNewDialog {

// return an svg circle with text in the middle
// text is either first 2 initials (if multiple words) or first 2 letters (if one word)
generateImage(text: string) {
private generateImage(text: string) {
const byWord = text.split(' ');
const abbr = byWord.length > 1 ? `${byWord[0].charAt(0)}.${byWord[1].charAt(0)}` : text.substring(0, 2);
return `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export class BudgetCardNew {
imgType: 'svg',
};
const dialogRef = this.dialog.open(BudgetCardNewDialog, {
width: '250px',
data: card,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { MobxAngularModule } from 'mobx-angular';
import { BudgetToolComponentsModule } from '../../components/budget-tool.components';
import { BudgetMaterialModule } from '../../material.module';
import { BudgetHomePage } from './budget-home.page';
import { BudgetDrawComponent } from '../../components/budget-draw/budget-draw.component';

const routes: Routes = [
{
Expand All @@ -28,7 +27,6 @@ const routes: Routes = [
BudgetMaterialModule,
BudgetToolComponentsModule,
MobxAngularModule,
BudgetDrawComponent
],
declarations: [BudgetHomePage],
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@
<img src="assets/budget-icons/budget-import.svg" />
</button>
</div>
<!-- This is a drawing test div -->
<div>
<h3>Draw here!</h3>
<budget-draw/>
</div>


<h2>{{ 'Saved Budgets' | translate }}</h2>
<div *mobxAutorun data-tourid="create">
<budget-list-item
Expand Down
64 changes: 35 additions & 29 deletions libs/shared/src/features/drawing/drawing.component.html
Original file line number Diff line number Diff line change
@@ -1,33 +1,39 @@
<button mat-raised-button (click)="dialog.open(editorDialog)">Click to Draw</button>
<div class="dialog-container">
<div class="edit-buttons">
<button mat-stroked-button (click)="undoSvgStroke()"><mat-icon>undo</mat-icon>{{ 'Undo' | translate }}</button>
<button mat-stroked-button (click)="redoSvgStroke()"><mat-icon>redo</mat-icon>{{ 'Redo' | translate }}</button>
<button mat-stroked-button style="margin-left: auto" (click)="clearDraw()">{{ 'Clear All' | translate }}</button>
</div>
<div class="svg-container" [style.width]="size() + 'px'" [style.height]="size() + 'px'">
<svg
xmlns="http://www.w3.org/2000/svg"
[attr.viewBox]="viewbox()"
[attr.height]="size()"
[attr.width]="size()"
#svgElement
(pointerdown)="handlePointerDown($event)"
(pointermove)="handlePointerMove($event)"
(mouseup)="handlePointerUp()"
(pointerup)="handlePointerUp()"
style="touch-action: none"
>
<!-- Previously rendered segments -->
@for(segment of segments; track segment.id){
<path [attr.d]="segment.path()" [id]="segment.id" />
}

<ng-template #editorDialog>
<div class="svg-container">
<div className="flex flex-row">
<button mat-stroked-button (click)="undoSvgStroke()">Undo</button>
<button mat-stroked-button (click)="redoSvgStroke()">Redo</button>
<!-- Active segment -->
@if(activeSegment.path()){
<path [attr.d]="activeSegment.path()" [id]="activeSegment.id" />
}
</svg>
<!-- Draw Prompt Logo -->
@if(segments.length===0 && !activeSegment.path()){
<div class="draw-logo">
<mat-icon>draw</mat-icon>
<div>{{ 'Draw Here' | translate }}</div>
</div>
<div class="svg-dialog-container">
<svg
#svgElement
width="100%"
height="100%"
(pointerdown)="handlePointerDown($event)"
(pointermove)="handlePointerMove($event)"
(mouseup)="handlePointerUp()"
(pointerup)="handlePointerUp()"
style="touch-action: none"
>
<!-- Previously rendered segments -->
@for(segment of segments; track segment.id){
<path [attr.d]="segment.path()" id="path-1" />
}

<!-- Active segment -->
@if(activeSegment){
<path [attr.d]="activeSegment.path()" id="path-1" />
}
</svg>
</div>
<button mat-stroked-button (click)="clearDraw()">Clear All</button>
}
</div>
</ng-template>
</div>
32 changes: 21 additions & 11 deletions libs/shared/src/features/drawing/drawing.component.scss
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
.svg-dialog-container {
.dialog-container {
text-align: center;
}
.svg-container {
border: 1px solid #eeeeee;
border-radius: 4px;
box-sizing: border-box;
// mat-dialog has max-width 80vw and includes 24px padding so just fit max
width: calc(80vw - 48px);
height: 70vh;
position: relative;
overflow: hidden;
}

.flex.flex-row{
display: flex;
flex-direction: row;
justify-content: flex-start;
.draw-logo {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: var(--color-light);
mat-icon {
font-size: 48px;
height: 48px;
width: 48px;
}
}

.svg-container{
height: 100%;
.edit-buttons {
display: flex;
gap: 8px;
margin-bottom: 8px;
}
Loading

0 comments on commit b6550c7

Please sign in to comment.