Skip to content

Commit 8e2210c

Browse files
author
farfromrefug
committed
feat(ui-svg): refactor so that ui-canvas peer dependency is not needed anymore if only using SVGView. Consequently the import for CanvasSVG or SVG changed (see readme)
1 parent 5ea27bc commit 8e2210c

File tree

11 files changed

+535
-512
lines changed

11 files changed

+535
-512
lines changed

packages/ui-svg/blueprint.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,29 @@ Run the following command from the root of your project:
1010

1111
`ns plugin add {{ pkg.name }}`
1212

13-
## Configuration
14-
15-
For now only `vue` (and core) is supported.
1613

1714
### NativeScript + Vue
1815

1916
```ts
20-
import CanvasSVG from '@nativescript-community/ui-svg/vue';
21-
Vue.use(CanvasSVG);
17+
import SVGPlugin from '@nativescript-community/ui-svg/vue';
18+
Vue.use(SVGPlugin);
19+
// or if you want the canvas version
20+
import CanvasSVGPlugin from '@nativescript-community/ui-svg/vue/canvas';
21+
Vue.use(CanvasSVGPlugin);
22+
```
23+
24+
For other flavors you need to register the components directly:
25+
```ts
26+
import { SVGView } from '@nativescript-community/ui-svg';
27+
import { CanvasSVG, SVG } from '@nativescript-community/ui-svg/canvas';
28+
2229
```
2330

2431
It works in 3 ways!.
2532

2633
`CanvasSVG` extending `Canvas`
2734

35+
2836
```html
2937
<CanvasSVG>
3038
<CSVG horizontalAlignment="left" src="~/assets/svgs/Ghostscript_Tiger.svg" height="100%" stretch="aspectFit" />

packages/ui-svg/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"url": "https://github.com/nativescript-community/ui-canvas/issues"
4141
},
4242
"peerDependencies": {
43-
"@nativescript-community/ui-canvas": "^4.5.1"
43+
"@nativescript-community/ui-canvas": "^4.6.27"
4444
},
4545
"gitHead": "6dc5e24339bbc329a239584e71c1cc30de9cedd4"
4646
}

src/ui-svg/canvas.android.ts

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import { Canvas, CanvasView } from '@nativescript-community/ui-canvas';
2+
import { File, ImageAsset, Length, Screen, Utils } from '@nativescript/core';
3+
import { SVG as SVGBase, xfermodeFromString } from './canvas.common';
4+
import { getSVG } from './index.android';
5+
export { CanvasSVG } from './canvas.common';
6+
7+
let bgdImagePaint: android.graphics.Paint;
8+
9+
export class SVG extends SVGBase {
10+
_svg: com.caverock.androidsvg.SVG;
11+
_src: string | File | ImageAsset;
12+
_cachedImage: android.graphics.Bitmap;
13+
private renderOptions = new com.caverock.androidsvg.RenderOptions();
14+
15+
getWidth(availableWidth, availableHeight) {
16+
if (this.width) {
17+
return super.getWidth(availableWidth, availableHeight);
18+
}
19+
const svg = this._svg;
20+
if (!svg) {
21+
return 0;
22+
}
23+
const viewRect = svg.getDocumentViewBox();
24+
if (viewRect) {
25+
const nativeWidth = viewRect.width();
26+
const nativeHeight = viewRect.height();
27+
const width = Math.min(nativeWidth, availableWidth);
28+
const height = this.height ? this.getHeight(availableWidth, availableHeight) : Math.min(nativeHeight, availableHeight);
29+
let paintedWidth = width;
30+
let paintedHeight = height;
31+
const nativeAspectRatio = nativeWidth / nativeHeight;
32+
const boundedAspectRatio = width / height;
33+
if (this._stretch === 'aspectFit') {
34+
if (nativeAspectRatio >= boundedAspectRatio) {
35+
// blank space on top and bottom
36+
paintedHeight = paintedWidth / nativeAspectRatio;
37+
} else {
38+
paintedWidth = paintedHeight * nativeAspectRatio;
39+
}
40+
return paintedWidth;
41+
} else if (this._stretch === 'aspectFill') {
42+
if (nativeAspectRatio <= boundedAspectRatio) {
43+
// blank space on top and bottom
44+
paintedHeight = paintedWidth / nativeAspectRatio;
45+
} else {
46+
paintedWidth = paintedHeight * nativeAspectRatio;
47+
}
48+
return paintedWidth;
49+
}
50+
return paintedWidth;
51+
}
52+
53+
return svg.getDocumentWidth();
54+
}
55+
getHeight(availableWidth: number, availableHeight: number) {
56+
if (this.height) {
57+
return super.getHeight(availableWidth, availableHeight);
58+
}
59+
const svg = this._svg;
60+
if (!svg) {
61+
return 0;
62+
}
63+
const viewRect = svg.getDocumentViewBox();
64+
if (viewRect) {
65+
const nativeWidth = viewRect.width();
66+
const nativeHeight = viewRect.height();
67+
const height = Math.min(nativeHeight, availableHeight);
68+
const width = this.width ? this.getWidth(availableWidth, availableHeight) : Math.min(nativeHeight, availableHeight);
69+
let paintedWidth = width;
70+
let paintedHeight = height;
71+
const nativeAspectRatio = nativeWidth / nativeHeight;
72+
const boundedAspectRatio = width / height;
73+
if (this._stretch === 'aspectFit') {
74+
if (nativeAspectRatio >= boundedAspectRatio) {
75+
// blank space on top and bottom
76+
paintedHeight = paintedWidth / nativeAspectRatio;
77+
} else {
78+
paintedWidth = paintedHeight * nativeAspectRatio;
79+
}
80+
return paintedHeight;
81+
} else if (this._stretch === 'aspectFill') {
82+
if (nativeAspectRatio <= boundedAspectRatio) {
83+
// blank space on top and bottom
84+
paintedHeight = paintedWidth / nativeAspectRatio;
85+
} else {
86+
paintedWidth = paintedHeight * nativeAspectRatio;
87+
}
88+
return paintedHeight;
89+
}
90+
return paintedHeight;
91+
}
92+
93+
return svg.getDocumentHeight();
94+
}
95+
drawOnCanvas(canvas: Canvas, parent: CanvasView) {
96+
const svg = this._svg;
97+
if (svg) {
98+
// const startTime = new Date().valueOf();
99+
// const wasCached = !!this._cachedImage;
100+
const availableWidth = Utils.layout.toDevicePixels(canvas.getWidth());
101+
const availableHeight = Utils.layout.toDevicePixels(canvas.getHeight());
102+
let options = this.renderOptions;
103+
const width = this.getWidth(availableWidth, availableHeight);
104+
const height = this.getHeight(availableWidth, availableHeight);
105+
// const box = svg.getDocumentViewBox();
106+
// const nativeWidth = box ? box.width() : width;
107+
// const nativeHeight = box ? box.height() : height;
108+
109+
// const nativeAspectRatio = nativeWidth / nativeHeight;
110+
// const boundedAspectRatio = width / height;
111+
112+
const paintedWidth = width;
113+
const paintedHeight = height;
114+
// does not seem like we need this. Handled by options?
115+
// if (nativeAspectRatio >= boundedAspectRatio) {
116+
// paintedHeight = paintedWidth / nativeAspectRatio;
117+
// } else {
118+
// paintedWidth = paintedHeight * nativeAspectRatio;
119+
// }
120+
const xOrigin = (width - paintedWidth) / 2.0;
121+
const yOrigin = (height - paintedHeight) / 2.0;
122+
options = options.preserveAspectRatio(this._preserveAspectRatio);
123+
124+
if (this.blendingMode || this.cache) {
125+
let newBitmap: android.graphics.Bitmap = this._cachedImage;
126+
const scale = Screen.mainScreen.scale;
127+
if (!this.cache || !this._cachedImage) {
128+
newBitmap = android.graphics.Bitmap.createBitmap(width * scale, height * scale, android.graphics.Bitmap.Config.ARGB_8888);
129+
const bmcanvas = new android.graphics.Canvas(newBitmap);
130+
bmcanvas.setDensity(Math.round(scale * 160));
131+
svg.renderToCanvas(bmcanvas, options);
132+
if (this.cache) {
133+
this._cachedImage = newBitmap;
134+
}
135+
}
136+
if (this.blendingMode) {
137+
if (!bgdImagePaint) {
138+
bgdImagePaint = new android.graphics.Paint();
139+
}
140+
bgdImagePaint.setXfermode(new android.graphics.PorterDuffXfermode(xfermodeFromString(this.blendingMode)));
141+
}
142+
canvas.drawBitmap(newBitmap, new android.graphics.Rect(0, 0, width * scale, height * scale), new android.graphics.Rect(xOrigin, yOrigin, width, height), bgdImagePaint as any);
143+
} else {
144+
options.viewPort(
145+
-xOrigin + Utils.layout.toDeviceIndependentPixels(Length.toDevicePixels(this.left)),
146+
-yOrigin + Utils.layout.toDeviceIndependentPixels(Length.toDevicePixels(this.top)),
147+
width,
148+
height
149+
);
150+
svg.renderToCanvas((canvas as any).getNative(), options);
151+
}
152+
// console.log('drawSvg', wasCached, Date.now() - startTime, 'ms');
153+
}
154+
}
155+
set src(value: string | File | ImageAsset) {
156+
this._src = value;
157+
this._svg = getSVG(value);
158+
if (this._svg) {
159+
this._svg.setDocumentWidth('100%');
160+
this._svg.setDocumentHeight('100%');
161+
}
162+
}
163+
get src(): string | File | ImageAsset {
164+
return this._src;
165+
}
166+
167+
_stretch: 'fill' | 'aspectFill' | 'aspectFit';
168+
_preserveAspectRatio: com.caverock.androidsvg.PreserveAspectRatio = com.caverock.androidsvg.PreserveAspectRatio.LETTERBOX;
169+
set stretch(value: 'fill' | 'aspectFill' | 'aspectFit') {
170+
this._stretch = value;
171+
switch (value) {
172+
case 'aspectFill':
173+
this._preserveAspectRatio = com.caverock.androidsvg.PreserveAspectRatio.FULLSCREEN;
174+
break;
175+
case 'fill':
176+
this._preserveAspectRatio = com.caverock.androidsvg.PreserveAspectRatio.STRETCH;
177+
break;
178+
case 'aspectFit':
179+
this._preserveAspectRatio = com.caverock.androidsvg.PreserveAspectRatio.LETTERBOX;
180+
break;
181+
}
182+
}
183+
get stretch(): 'fill' | 'aspectFill' | 'aspectFit' {
184+
return this._stretch;
185+
}
186+
}

src/ui-svg/canvas.common.ts

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { Canvas, CanvasView, PorterDuffMode } from '@nativescript-community/ui-canvas';
2+
import Shape, { lengthProperty, percentLengthProperty } from '@nativescript-community/ui-canvas/shapes/shape';
3+
import { CSSType, CoreTypes, ImageAsset, Property, View } from '@nativescript/core';
4+
5+
export function xfermodeFromString(str) {
6+
switch (str) {
7+
case 'overlay':
8+
return PorterDuffMode.OVERLAY;
9+
case 'lighten':
10+
return PorterDuffMode.LIGHTEN;
11+
case 'screen':
12+
return PorterDuffMode.SCREEN;
13+
case 'multiply':
14+
return PorterDuffMode.MULTIPLY;
15+
case 'dst_atop':
16+
return PorterDuffMode.DST_ATOP;
17+
case 'dst_over':
18+
return PorterDuffMode.DST_OVER;
19+
case 'dst_out':
20+
return PorterDuffMode.DST_OUT;
21+
case 'dst_in':
22+
return PorterDuffMode.DST_IN;
23+
case 'clear':
24+
return PorterDuffMode.CLEAR;
25+
case 'src_atop':
26+
return PorterDuffMode.SRC_ATOP;
27+
case 'src_over':
28+
return PorterDuffMode.SRC_OVER;
29+
case 'src_in':
30+
return PorterDuffMode.SRC_IN;
31+
case 'src_out':
32+
return PorterDuffMode.SRC_OUT;
33+
default:
34+
return null;
35+
}
36+
}
37+
38+
export abstract class SVG extends Shape {
39+
_parent: WeakRef<any>;
40+
@percentLengthProperty width: CoreTypes.PercentLengthType;
41+
@percentLengthProperty height: CoreTypes.PercentLengthType;
42+
@lengthProperty left: CoreTypes.LengthType = CoreTypes.zeroLength;
43+
@lengthProperty top: CoreTypes.LengthType = CoreTypes.zeroLength;
44+
blendingMode: PorterDuffMode;
45+
cache: boolean = true;
46+
drawOnCanvas(canvas: Canvas, parent: CanvasView) {}
47+
_cachedImage: any;
48+
clearCache() {
49+
this._cachedImage = null;
50+
}
51+
}
52+
53+
@CSSType('CanvasSVG')
54+
export class CanvasSVG extends CanvasView {
55+
// constructor() {
56+
// super();
57+
// }
58+
//@ts-ignore
59+
// set color(value) {
60+
// this.style.color = value;
61+
// }
62+
// get padding(): string | Length {
63+
// return this.style.padding;
64+
// }
65+
// set padding(value: string | Length) {
66+
// this.style.padding = value;
67+
// }
68+
// get paddingTop(): Length {
69+
// return this.style.paddingTop;
70+
// }
71+
// set paddingTop(value: Length) {
72+
// this.style.paddingTop = value;
73+
// }
74+
// get paddingRight(): Length {
75+
// return this.style.paddingRight;
76+
// }
77+
// set paddingRight(value: Length) {
78+
// this.style.paddingRight = value;
79+
// }
80+
// get paddingBottom(): Length {
81+
// return this.style.paddingBottom;
82+
// }
83+
// set paddingBottom(value: Length) {
84+
// this.style.paddingBottom = value;
85+
// }
86+
// get paddingLeft(): Length {
87+
// return this.style.paddingLeft;
88+
// }
89+
// set paddingLeft(value: Length) {
90+
// this.style.paddingLeft = value;
91+
// }
92+
}

src/ui-svg/canvas.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './canvas.android';

0 commit comments

Comments
 (0)