Skip to content

Commit 4dad26a

Browse files
committed
updates
feat(): initial svg js api feat(): add support for cpu only 2d views
1 parent d4fac92 commit 4dad26a

File tree

62 files changed

+1784
-683
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1784
-683
lines changed

CanvasNative.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Pod::Spec.new do |s|
22

33
s.name = "CanvasNative"
44

5-
s.version = "0.9.7"
5+
s.version = "0.9.9"
66

77
s.summary = "A Canvas library"
88

apps/demo/src/app.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
import { Application } from '@nativescript/core';
2-
32
Application.run({ moduleName: 'app-root' });

packages/canvas/Canvas/index.android.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,8 @@ export class Canvas extends CanvasBase {
2323
private _canvas;
2424
private _didPause: boolean = false;
2525

26-
constructor() {
26+
constructor(useCpu = false) {
2727
super();
28-
let useCpu = false;
2928
if (arguments.length === 1) {
3029
if (typeof arguments[0] === 'boolean') {
3130
useCpu = arguments[0];

packages/canvas/Canvas/index.ios.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ export class Canvas extends CanvasBase {
2020
private _isReady: boolean = false;
2121
private _readyListener: any;
2222

23-
constructor() {
23+
constructor(useCpu = false) {
2424
super();
25-
this._canvas = TNSCanvas.alloc().initWithFrame(
26-
CGRectZero
25+
this._canvas = TNSCanvas.alloc().initWithFrameUseCpu(
26+
CGRectZero,
27+
useCpu
2728
);
2829
const ref = new WeakRef(this);
2930
const listener = (NSObject as any).extend({

packages/canvas/SVG/Circle.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import {Property} from "@nativescript/core";
2-
import {SVGItem} from "./SVGItem";
3-
import {CanvasGradient, Path2D} from "../Canvas2D";
1+
import { Property } from "@nativescript/core";
2+
import { SVGItem } from "./SVGItem";
3+
import { CanvasGradient, Path2D } from "../Canvas2D";
44

55
export const cxProperty = new Property<Circle, any>({
66
name: 'cx'

packages/canvas/SVG/G.ts

Lines changed: 123 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,25 @@
1-
import {AddChildFromBuilder} from "@nativescript/core";
2-
import {Canvas} from "../Canvas";
3-
import {SVGItem} from "./SVGItem";
1+
import { AddChildFromBuilder, View } from "@nativescript/core";
2+
import { Canvas } from "../Canvas";
3+
import { Svg } from "./SVG";
4+
import { SVGItem } from "./SVGItem";
45

56
export class G extends SVGItem implements AddChildFromBuilder {
6-
_canvas: Canvas;
77
_views: any[];
8+
_children: Map<string, View>;
9+
#viewPostion: Map<number, string>;
810
transform: string;
911
x: any;
1012
y: any;
1113

1214
constructor() {
1315
super();
16+
this.#viewPostion = new Map();
1417
this._views = [];
18+
this._children = new Map<string, View>();
1519
}
1620

17-
_addChildFromBuilder(name: string, value: any): void {
18-
value._canvas = this._canvas;
19-
value.parent = this;
20-
this._views.push(value);
21-
this._appendChild(value.id || value._domId, value);
22-
}
23-
24-
handleValues() {
21+
handleValues(canvas) {
22+
this._canvas = canvas;
2523
const ctx = this._canvas.getContext('2d') as any;
2624
ctx.save();
2725
if (typeof this.transform === 'string') {
@@ -55,7 +53,7 @@ export class G extends SVGItem implements AddChildFromBuilder {
5553
if (typeof view.handleValues === 'function') {
5654
updateColors();
5755
ctx.globalAlpha = this.opacity;
58-
view.handleValues();
56+
view.handleValues(this._canvas);
5957
} else if (view instanceof G) {
6058
view._views.forEach((view) => {
6159
updateColors();
@@ -65,4 +63,116 @@ export class G extends SVGItem implements AddChildFromBuilder {
6563
});
6664
ctx.restore();
6765
}
66+
67+
_refresh() {
68+
if (this.parent && this.parent instanceof Svg) {
69+
this._views.forEach((view) => {
70+
if (typeof view.handleValues === 'function') {
71+
view.handleValues(this._canvas);
72+
}
73+
})
74+
}
75+
}
76+
_forceRedraw() {
77+
if (this.parent && this.parent instanceof Svg) {
78+
const ctx = this._canvas.getContext('2d');
79+
this._views.forEach((view) => {
80+
if (typeof view.handleValues === 'function') {
81+
view.handleValues(this._canvas);
82+
}
83+
});
84+
}
85+
}
86+
87+
eachChildView(callback: (child: View) => boolean) {
88+
this._children.forEach((view, key) => {
89+
callback(view);
90+
});
91+
}
92+
93+
94+
public _addChildFromBuilder(name: string, value: any) {
95+
if (value instanceof View) {
96+
this.addChild(value);
97+
}
98+
}
99+
100+
getChildrenCount(): number {
101+
return this._children.size;
102+
}
103+
104+
// overrides the base property.
105+
get _childrenCount(): number {
106+
return this._children.size;
107+
}
108+
109+
getChildAt(index: number): View {
110+
return this._views[index];
111+
}
112+
113+
getChildIndex(child: View): number {
114+
return this._views.indexOf(child);
115+
}
116+
117+
public getChildById(id: string) {
118+
return this._getViewById(id);
119+
}
120+
121+
public _registerLayoutChild(child: View) {
122+
//Overridden
123+
}
124+
125+
public _unregisterLayoutChild(child: View) {
126+
//Overridden
127+
}
128+
129+
public addChildren(...children: View[]) {
130+
children.forEach(child => {
131+
this._views.push(child);
132+
this._children.set(`${child.id || child._domId}`, child);
133+
this._addView(child);
134+
this._registerLayoutChild(child);
135+
});
136+
this._refresh();
137+
}
138+
139+
public addChild(child: View): void {
140+
this._views.push(child);
141+
this._children.set(`${child.id || child._domId}`, child);
142+
this._addView(child);
143+
this._registerLayoutChild(child);
144+
this._refresh();
145+
}
146+
147+
public insertChild(child: View, atIndex: number): void {
148+
this._views.splice(atIndex, 0, child);
149+
this._children.set(`${child.id || child._domId}`, child);
150+
this._addView(child, atIndex);
151+
this._registerLayoutChild(child);
152+
this._refresh();
153+
}
154+
155+
public removeChild(child: View): void {
156+
this._removeView(child);
157+
// TODO: consider caching the index on the child.
158+
const index = this._views.indexOf(child);
159+
this._views.splice(index, 1);
160+
this._children.delete(`${child.id || child._domId}`)
161+
this._unregisterLayoutChild(child);
162+
if (!this.#isRemoving) {
163+
this._refresh();
164+
}
165+
}
166+
167+
#isRemoving: boolean = false;
168+
public removeChildren(): void {
169+
this.#isRemoving = true;
170+
while (this.getChildrenCount() !== 0) {
171+
this.removeChild(this._views[this.getChildrenCount() - 1]);
172+
}
173+
if (this.#isRemoving) {
174+
this._refresh();
175+
}
176+
this.#isRemoving = false;
177+
}
68178
}

packages/canvas/SVG/Image.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import {SVGItem} from "./SVGItem";
1+
import { ImageAsset } from "@nativescript/canvas";
2+
import { SVGItem } from "./SVGItem";
23

34
const b64Extensions = {
45
"/": "jpg",
@@ -27,7 +28,10 @@ function getMIMEforBase64String(b64) {
2728
export class Image extends SVGItem {
2829
xlink: { href?: string } = {};
2930
href: string;
30-
31+
x: any = 0;
32+
y: any = 0;
33+
#loadedSrc: string;
34+
#asset = new ImageAsset();
3135
handleValues(canvas?) {
3236
let ctx: any;
3337
if (canvas) {
@@ -47,8 +51,12 @@ export class Image extends SVGItem {
4751
if (this.isBase64(src)) {
4852
const nativeImage = this.loadSrc(src);
4953
if (nativeImage) {
50-
ctx.drawImage(nativeImage, 0, 0, this.width as any, this.height as any);
54+
ctx.drawImage(nativeImage, this.x, this.y, this.width as any, this.height as any);
5155
}
56+
} else if (this.#loadedSrc === src) {
57+
ctx.drawImage(this.#asset, this.x, this.y, this.width as any, this.height);
58+
} else {
59+
this.loadSrc(src);
5260
}
5361
}
5462
ctx.restore();
@@ -61,6 +69,7 @@ export class Image extends SVGItem {
6169
}
6270

6371
loadSrc(src) {
72+
this.#loadedSrc = undefined;
6473
if (
6574
typeof src === "string" &&
6675
src.startsWith &&
@@ -86,6 +95,12 @@ export class Image extends SVGItem {
8695
} catch (error) {
8796
return null;
8897
}
98+
} else if (typeof src === "string" && src.startsWith('http')) {
99+
this.#asset.loadFromUrlAsync(src)
100+
.then(() => {
101+
this.#loadedSrc = src;
102+
(this.parent as any)?._forceRedraw();
103+
});
89104
}
90105
return null;
91106
}

packages/canvas/SVG/Line.ts

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,57 @@ export class Line extends SVGItem {
3333
line.lineTo(this.x2, this.y2);
3434
ctx.save();
3535
ctx.lineWidth = this.strokeWidth;
36-
if (this._doStroke()) {
37-
ctx.strokeStyle = this._realStroke;
36+
ctx.globalAlpha = this._realOpacity;
37+
let lastOpacity;
38+
if (this._doFillOpacity()) {
39+
lastOpacity = ctx.globalAlpha;
40+
ctx.globalAlpha = this._realFillOpacity;
41+
}
42+
if (this._doFill()) {
43+
if (this.fill !== undefined && this.fill !== 'none') {
44+
if (this.fill && this.fill.indexOf('url') > -1) {
45+
const fill = this._getViewById(this.fill);
46+
if (fill) {
47+
const style = fill._getFillOrStrokeStyle();
48+
if (style instanceof CanvasGradient) {
49+
if (typeof fill.gradientTransform === 'string' && fill.gradientTransform.indexOf('rotate')) {
50+
let rotation = parseInt(fill.gradientTransform.replace('rotate(', '').replace(')', ''));
51+
if (!isNaN(rotation)) {
52+
ctx.rotate(rotation);
53+
}
54+
}
55+
ctx.fillStyle = style;
56+
} else {
57+
ctx.fillStyle = ctx.createPattern(style, 'repeat');
58+
}
59+
}
60+
} else {
61+
ctx.fillStyle = this.fill;
62+
}
63+
}
3864
ctx.fill(line);
3965
}
66+
if (lastOpacity !== undefined) {
67+
ctx.globalAlpha = lastOpacity;
68+
}
69+
if (this._doStroke()) {
70+
if (this.stroke !== undefined && this.stroke !== 'none') {
71+
if (this.stroke && this.stroke.indexOf('url') > -1) {
72+
const stroke = this._getViewById(this.stroke);
73+
if (stroke) {
74+
const style = stroke._getFillOrStrokeStyle();
75+
if (stroke instanceof CanvasGradient) {
76+
ctx.strokeStyle = style;
77+
} else {
78+
ctx.strokeStyle = ctx.createPattern(style, 'repeat');
79+
}
80+
}
81+
} else {
82+
ctx.strokeStyle = this.stroke;
83+
}
84+
}
85+
ctx.stroke(line);
86+
}
4087
ctx.restore();
4188
}
4289

packages/canvas/SVG/LinearGradient.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {SVGItem} from "./SVGItem";
2-
import {SVG} from "./SVG";
2+
import {Svg} from "./SVG";
33
import {AddChildFromBuilder} from "@nativescript/core";
44
import {Stop} from "./Stop";
55

@@ -25,7 +25,7 @@ export class LinearGradient extends SVGItem implements AddChildFromBuilder {
2525
ctx = this._canvas.getContext('2d') as any;
2626
}
2727
let svg: any = this.parent;
28-
while (!(svg instanceof SVG)) {
28+
while (!(svg instanceof Svg)) {
2929
svg = svg.parent;
3030
if (svg === undefined || svg === null) {
3131
break;

packages/canvas/SVG/Path.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
import {Property} from "@nativescript/core";
2-
import {Path2D, CanvasGradient} from "../Canvas2D";
3-
import {SVGItem} from "./SVGItem";
1+
import { Property } from "@nativescript/core";
2+
import { Path2D, CanvasGradient } from "../Canvas2D";
3+
import { SVGItem } from "./SVGItem";
44

55
export const dProperty = new Property<Path, string>({
66
name: 'd'
77
});
88

99
export class Path extends SVGItem {
1010
public d: string;
11-
11+
constructor() {
12+
super();
13+
this.fill = 'black';
14+
}
1215
handleValues(canvas?) {
1316
let ctx: CanvasRenderingContext2D;
1417
if (canvas) {
@@ -27,7 +30,7 @@ export class Path extends SVGItem {
2730
}
2831
ctx.globalAlpha = this._realOpacity;
2932
let lastOpacity;
30-
// @ts-ignore
33+
// @ts-ignore
3134
if (this._doFillOpacity()) {
3235
lastOpacity = ctx.globalAlpha;
3336
ctx.globalAlpha = this._realFillOpacity;

0 commit comments

Comments
 (0)