@idraw/renderer 0.4.0-beta.4 → 0.4.0-beta.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -64,5 +64,5 @@ renderer.on('drawFrameComplete', (e) => {
64
64
 
65
65
  ## Documents
66
66
 
67
- - [Documents](https://idraw.js.org/docs/en/) | [中文文档](https://idraw.js.org/docs/zh/)
68
- - [Online Playground](https://idraw.js.org/playground/) | [在线API示例](https://idraw.js.org/playground/)
67
+ - [Documents](https://idrawjs.com/docs/en/) | [中文文档](https://idrawjs.com/docs/zh/)
68
+ - [Online Playground](https://idrawjs.com/playground/) | [在线API示例](https://idrawjs.com/playground/)
@@ -0,0 +1,44 @@
1
+ import type { Point, Data, Element, ElementType, ViewCalculator, ViewCalculatorOptions, ViewScaleInfo, ViewSizeInfo, ViewRectInfo, ModifyInfo, VirtualFlatItem } from '@idraw/types';
2
+ export declare class Calculator implements ViewCalculator {
3
+ #private;
4
+ constructor(opts: ViewCalculatorOptions);
5
+ toGridNum(num: number, opts?: {
6
+ ignore?: boolean;
7
+ }): number;
8
+ destroy(): void;
9
+ needRender(elem: Element<ElementType>): boolean;
10
+ getPointElement(p: Point, opts: {
11
+ data: Data;
12
+ viewScaleInfo: ViewScaleInfo;
13
+ viewSizeInfo: ViewSizeInfo;
14
+ }): {
15
+ index: number;
16
+ element: null | Element<ElementType>;
17
+ groupQueueIndex: number;
18
+ };
19
+ resetVirtualFlatItemMap(data: Data, opts: {
20
+ viewScaleInfo: ViewScaleInfo;
21
+ viewSizeInfo: ViewSizeInfo;
22
+ }): void;
23
+ updateVisiableStatus(opts: {
24
+ viewScaleInfo: ViewScaleInfo;
25
+ viewSizeInfo: ViewSizeInfo;
26
+ }): void;
27
+ calcViewRectInfoFromOrigin(uuid: string, opts: {
28
+ checkVisible?: boolean;
29
+ viewScaleInfo: ViewScaleInfo;
30
+ viewSizeInfo: ViewSizeInfo;
31
+ }): ViewRectInfo | null;
32
+ calcViewRectInfoFromRange(uuid: string, opts: {
33
+ checkVisible?: boolean;
34
+ viewScaleInfo: ViewScaleInfo;
35
+ viewSizeInfo: ViewSizeInfo;
36
+ }): ViewRectInfo | null;
37
+ modifyText(element: Element<'text'>): void;
38
+ modifyVirtualFlatItemMap(data: Data, opts: {
39
+ modifyInfo: ModifyInfo;
40
+ viewScaleInfo: ViewScaleInfo;
41
+ viewSizeInfo: ViewSizeInfo;
42
+ }): void;
43
+ getVirtualFlatItem(uuid: string): VirtualFlatItem | null;
44
+ }
@@ -0,0 +1,180 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _Calculator_opts, _Calculator_store;
13
+ import { is, getViewPointAtElement, Store, calcViewPointSize, findElementFromListByPosition, getGroupQueueByElementPosition, calcElementOriginRectInfo, originRectInfoToRangeRectInfo } from '@idraw/util';
14
+ import { sortElementsViewVisiableInfoMap, updateVirtualFlatItemMapStatus } from './view-visible';
15
+ import { calcVirtualFlatDetail } from './virtual-flat';
16
+ import { calcVirtualTextDetail } from './virtual-flat/text';
17
+ export class Calculator {
18
+ constructor(opts) {
19
+ _Calculator_opts.set(this, void 0);
20
+ _Calculator_store.set(this, void 0);
21
+ __classPrivateFieldSet(this, _Calculator_opts, opts, "f");
22
+ __classPrivateFieldSet(this, _Calculator_store, new Store({
23
+ defaultStorage: {
24
+ virtualFlatItemMap: {},
25
+ visibleCount: 0,
26
+ invisibleCount: 0
27
+ }
28
+ }), "f");
29
+ }
30
+ toGridNum(num, opts) {
31
+ if ((opts === null || opts === void 0 ? void 0 : opts.ignore) === true) {
32
+ return num;
33
+ }
34
+ return Math.round(num);
35
+ }
36
+ destroy() {
37
+ __classPrivateFieldSet(this, _Calculator_opts, null, "f");
38
+ }
39
+ needRender(elem) {
40
+ const virtualFlatItemMap = __classPrivateFieldGet(this, _Calculator_store, "f").get('virtualFlatItemMap');
41
+ const info = virtualFlatItemMap[elem.uuid];
42
+ if (!info) {
43
+ return true;
44
+ }
45
+ return info.isVisibleInView;
46
+ }
47
+ getPointElement(p, opts) {
48
+ const context2d = __classPrivateFieldGet(this, _Calculator_opts, "f").tempContext;
49
+ return getViewPointAtElement(p, Object.assign(Object.assign({}, opts), { context2d }));
50
+ }
51
+ resetVirtualFlatItemMap(data, opts) {
52
+ if (data) {
53
+ const { virtualFlatItemMap, invisibleCount, visibleCount } = sortElementsViewVisiableInfoMap(data.elements, Object.assign(Object.assign({}, opts), {
54
+ tempContext: __classPrivateFieldGet(this, _Calculator_opts, "f").tempContext
55
+ }));
56
+ __classPrivateFieldGet(this, _Calculator_store, "f").set('virtualFlatItemMap', virtualFlatItemMap);
57
+ __classPrivateFieldGet(this, _Calculator_store, "f").set('invisibleCount', invisibleCount);
58
+ __classPrivateFieldGet(this, _Calculator_store, "f").set('visibleCount', visibleCount);
59
+ }
60
+ }
61
+ updateVisiableStatus(opts) {
62
+ const { virtualFlatItemMap, invisibleCount, visibleCount } = updateVirtualFlatItemMapStatus(__classPrivateFieldGet(this, _Calculator_store, "f").get('virtualFlatItemMap'), opts);
63
+ __classPrivateFieldGet(this, _Calculator_store, "f").set('virtualFlatItemMap', virtualFlatItemMap);
64
+ __classPrivateFieldGet(this, _Calculator_store, "f").set('invisibleCount', invisibleCount);
65
+ __classPrivateFieldGet(this, _Calculator_store, "f").set('visibleCount', visibleCount);
66
+ }
67
+ calcViewRectInfoFromOrigin(uuid, opts) {
68
+ const infoData = __classPrivateFieldGet(this, _Calculator_store, "f").get('virtualFlatItemMap')[uuid];
69
+ if (!(infoData === null || infoData === void 0 ? void 0 : infoData.originRectInfo)) {
70
+ return null;
71
+ }
72
+ const { checkVisible, viewScaleInfo, viewSizeInfo } = opts;
73
+ const { center, left, right, bottom, top, topLeft, topRight, bottomLeft, bottomRight } = infoData.originRectInfo;
74
+ if (checkVisible === true && infoData.isVisibleInView === false) {
75
+ return null;
76
+ }
77
+ const calcOpts = { viewScaleInfo, viewSizeInfo };
78
+ const viewRectInfo = {
79
+ center: calcViewPointSize(center, calcOpts),
80
+ left: calcViewPointSize(left, calcOpts),
81
+ right: calcViewPointSize(right, calcOpts),
82
+ bottom: calcViewPointSize(bottom, calcOpts),
83
+ top: calcViewPointSize(top, calcOpts),
84
+ topLeft: calcViewPointSize(topLeft, calcOpts),
85
+ topRight: calcViewPointSize(topRight, calcOpts),
86
+ bottomLeft: calcViewPointSize(bottomLeft, calcOpts),
87
+ bottomRight: calcViewPointSize(bottomRight, calcOpts)
88
+ };
89
+ return viewRectInfo;
90
+ }
91
+ calcViewRectInfoFromRange(uuid, opts) {
92
+ const infoData = __classPrivateFieldGet(this, _Calculator_store, "f").get('virtualFlatItemMap')[uuid];
93
+ if (!(infoData === null || infoData === void 0 ? void 0 : infoData.originRectInfo)) {
94
+ return null;
95
+ }
96
+ const { checkVisible, viewScaleInfo, viewSizeInfo } = opts;
97
+ const { center, left, right, bottom, top, topLeft, topRight, bottomLeft, bottomRight } = infoData.rangeRectInfo;
98
+ if (checkVisible === true && infoData.isVisibleInView === false) {
99
+ return null;
100
+ }
101
+ const calcOpts = { viewScaleInfo, viewSizeInfo };
102
+ const viewRectInfo = {
103
+ center: calcViewPointSize(center, calcOpts),
104
+ left: calcViewPointSize(left, calcOpts),
105
+ right: calcViewPointSize(right, calcOpts),
106
+ bottom: calcViewPointSize(bottom, calcOpts),
107
+ top: calcViewPointSize(top, calcOpts),
108
+ topLeft: calcViewPointSize(topLeft, calcOpts),
109
+ topRight: calcViewPointSize(topRight, calcOpts),
110
+ bottomLeft: calcViewPointSize(bottomLeft, calcOpts),
111
+ bottomRight: calcViewPointSize(bottomRight, calcOpts)
112
+ };
113
+ return viewRectInfo;
114
+ }
115
+ modifyText(element) {
116
+ const virtualFlatItemMap = __classPrivateFieldGet(this, _Calculator_store, "f").get('virtualFlatItemMap');
117
+ const flatItem = virtualFlatItemMap[element.uuid];
118
+ if (element && element.type === 'text') {
119
+ const newVirtualFlatItem = Object.assign(Object.assign({}, flatItem), calcVirtualTextDetail(element, {
120
+ tempContext: __classPrivateFieldGet(this, _Calculator_opts, "f").tempContext
121
+ }));
122
+ virtualFlatItemMap[element.uuid] = newVirtualFlatItem;
123
+ __classPrivateFieldGet(this, _Calculator_store, "f").set('virtualFlatItemMap', virtualFlatItemMap);
124
+ }
125
+ }
126
+ modifyVirtualFlatItemMap(data, opts) {
127
+ const { modifyInfo, viewScaleInfo, viewSizeInfo } = opts;
128
+ const { type, content } = modifyInfo;
129
+ const list = data.elements;
130
+ const virtualFlatItemMap = __classPrivateFieldGet(this, _Calculator_store, "f").get('virtualFlatItemMap');
131
+ if (type === 'deleteElement') {
132
+ const { element } = content;
133
+ const uuids = [];
134
+ const _walk = (e) => {
135
+ uuids.push(e.uuid);
136
+ if (e.type === 'group' && Array.isArray(e.detail.children)) {
137
+ e.detail.children.forEach((child) => {
138
+ _walk(child);
139
+ });
140
+ }
141
+ };
142
+ _walk(element);
143
+ uuids.forEach((uuid) => {
144
+ delete virtualFlatItemMap[uuid];
145
+ });
146
+ __classPrivateFieldGet(this, _Calculator_store, "f").set('virtualFlatItemMap', virtualFlatItemMap);
147
+ }
148
+ else if (type === 'addElement' || type === 'updateElement') {
149
+ const { position } = content;
150
+ const element = findElementFromListByPosition(position, data.elements);
151
+ const groupQueue = getGroupQueueByElementPosition(list, position);
152
+ if (element) {
153
+ if (type === 'updateElement' && element.type === 'group') {
154
+ this.resetVirtualFlatItemMap(data, { viewScaleInfo, viewSizeInfo });
155
+ }
156
+ else {
157
+ const originRectInfo = calcElementOriginRectInfo(element, {
158
+ groupQueue: groupQueue || []
159
+ });
160
+ const newVirtualFlatItem = Object.assign({ type: element.type, originRectInfo, rangeRectInfo: is.angle(element.angle) ? originRectInfoToRangeRectInfo(originRectInfo) : originRectInfo, isVisibleInView: true, position: [...position] }, calcVirtualFlatDetail(element, {
161
+ tempContext: __classPrivateFieldGet(this, _Calculator_opts, "f").tempContext
162
+ }));
163
+ virtualFlatItemMap[element.uuid] = newVirtualFlatItem;
164
+ __classPrivateFieldGet(this, _Calculator_store, "f").set('virtualFlatItemMap', virtualFlatItemMap);
165
+ if (type === 'updateElement') {
166
+ this.updateVisiableStatus({ viewScaleInfo, viewSizeInfo });
167
+ }
168
+ }
169
+ }
170
+ }
171
+ else if (type === 'moveElement') {
172
+ this.resetVirtualFlatItemMap(data, { viewScaleInfo, viewSizeInfo });
173
+ }
174
+ }
175
+ getVirtualFlatItem(uuid) {
176
+ const itemMap = __classPrivateFieldGet(this, _Calculator_store, "f").get('virtualFlatItemMap');
177
+ return itemMap[uuid] || null;
178
+ }
179
+ }
180
+ _Calculator_opts = new WeakMap(), _Calculator_store = new WeakMap();
@@ -1,11 +1,25 @@
1
1
  import { ViewContext2D, Element, ElementType, ElementSize, ViewScaleInfo, ViewSizeInfo } from '@idraw/types';
2
- export declare function drawBox(ctx: ViewContext2D, viewElem: Element<ElementType>, opts: {
3
- originElem: Element<ElementType>;
2
+ import { Calculator } from '../calculator';
3
+ export declare function getOpacity(elem: Element): number;
4
+ export declare function drawBox(ctx: ViewContext2D, viewElem: Element, opts: {
5
+ originElem: Element;
4
6
  calcElemSize: ElementSize;
5
7
  pattern?: string | CanvasPattern | null;
6
- renderContent: () => void;
8
+ renderContent?: () => void;
9
+ viewScaleInfo: ViewScaleInfo;
10
+ viewSizeInfo: ViewSizeInfo;
11
+ parentOpacity: number;
12
+ }): void;
13
+ export declare function drawBoxBackground(ctx: ViewContext2D, viewElem: Element<ElementType>, opts: {
14
+ pattern?: string | CanvasPattern | null;
15
+ viewScaleInfo: ViewScaleInfo;
16
+ viewSizeInfo: ViewSizeInfo;
17
+ }): void;
18
+ export declare function drawBoxBorder(ctx: ViewContext2D, viewElem: Element<ElementType>, opts: {
19
+ originElem: Element;
7
20
  viewScaleInfo: ViewScaleInfo;
8
21
  viewSizeInfo: ViewSizeInfo;
22
+ calculator?: Calculator;
9
23
  }): void;
10
24
  export declare function drawBoxShadow(ctx: ViewContext2D, viewElem: Element<ElementType>, opts: {
11
25
  viewScaleInfo: ViewScaleInfo;
@@ -1,31 +1,53 @@
1
1
  import { istype, isColorStr, generateSVGPath, rotateElement, is, getDefaultElementDetailConfig, calcViewBoxSize } from '@idraw/util';
2
2
  import { createColorStyle } from './color';
3
3
  const defaultElemConfig = getDefaultElementDetailConfig();
4
+ export function getOpacity(elem) {
5
+ var _a, _b, _c, _d;
6
+ let opacity = 1;
7
+ if (((_a = elem === null || elem === void 0 ? void 0 : elem.detail) === null || _a === void 0 ? void 0 : _a.opacity) !== undefined && ((_b = elem === null || elem === void 0 ? void 0 : elem.detail) === null || _b === void 0 ? void 0 : _b.opacity) >= 0 && ((_c = elem === null || elem === void 0 ? void 0 : elem.detail) === null || _c === void 0 ? void 0 : _c.opacity) <= 1) {
8
+ opacity = (_d = elem === null || elem === void 0 ? void 0 : elem.detail) === null || _d === void 0 ? void 0 : _d.opacity;
9
+ }
10
+ return opacity;
11
+ }
4
12
  export function drawBox(ctx, viewElem, opts) {
5
13
  const { pattern, renderContent, originElem, calcElemSize, viewScaleInfo, viewSizeInfo } = opts || {};
6
- drawClipPath(ctx, viewElem, {
7
- originElem,
8
- calcElemSize,
9
- viewScaleInfo,
10
- viewSizeInfo,
11
- renderContent: () => {
12
- var _a, _b;
13
- if (((_a = viewElem === null || viewElem === void 0 ? void 0 : viewElem.detail) === null || _a === void 0 ? void 0 : _a.opacity) !== undefined && ((_b = viewElem === null || viewElem === void 0 ? void 0 : viewElem.detail) === null || _b === void 0 ? void 0 : _b.opacity) >= 0) {
14
- ctx.globalAlpha = viewElem.detail.opacity;
15
- }
16
- else {
17
- ctx.globalAlpha = 1;
14
+ const { parentOpacity } = opts;
15
+ const opacity = getOpacity(originElem) * parentOpacity;
16
+ const { clipPath, clipPathStrokeColor, clipPathStrokeWidth } = originElem.detail;
17
+ const mainRender = () => {
18
+ ctx.globalAlpha = opacity;
19
+ drawBoxBackground(ctx, viewElem, { pattern, viewScaleInfo, viewSizeInfo });
20
+ renderContent === null || renderContent === void 0 ? void 0 : renderContent();
21
+ drawBoxBorder(ctx, viewElem, { originElem, viewScaleInfo, viewSizeInfo });
22
+ ctx.globalAlpha = parentOpacity;
23
+ };
24
+ if (clipPath) {
25
+ drawClipPath(ctx, viewElem, {
26
+ originElem,
27
+ calcElemSize,
28
+ viewScaleInfo,
29
+ viewSizeInfo,
30
+ renderContent: () => {
31
+ mainRender();
18
32
  }
19
- drawBoxBackground(ctx, viewElem, { pattern, viewScaleInfo, viewSizeInfo });
20
- renderContent === null || renderContent === void 0 ? void 0 : renderContent();
21
- drawBoxBorder(ctx, viewElem, { viewScaleInfo, viewSizeInfo });
22
- ctx.globalAlpha = 1;
33
+ });
34
+ if (typeof clipPathStrokeWidth === 'number' && clipPathStrokeWidth > 0 && clipPathStrokeColor) {
35
+ drawClipPathStroke(ctx, viewElem, {
36
+ originElem,
37
+ calcElemSize,
38
+ viewScaleInfo,
39
+ viewSizeInfo,
40
+ parentOpacity
41
+ });
23
42
  }
24
- });
43
+ }
44
+ else {
45
+ mainRender();
46
+ }
25
47
  }
26
48
  function drawClipPath(ctx, viewElem, opts) {
27
- const { renderContent, originElem, calcElemSize, viewScaleInfo, viewSizeInfo } = opts;
28
- const totalScale = viewScaleInfo.scale * viewSizeInfo.devicePixelRatio;
49
+ const { renderContent, originElem, calcElemSize, viewSizeInfo } = opts;
50
+ const totalScale = viewSizeInfo.devicePixelRatio;
29
51
  const { clipPath } = (originElem === null || originElem === void 0 ? void 0 : originElem.detail) || {};
30
52
  if (clipPath && calcElemSize && clipPath.commands) {
31
53
  const { x, y, w, h } = calcElemSize;
@@ -41,7 +63,45 @@ function drawClipPath(ctx, viewElem, opts) {
41
63
  ctx.scale(totalScale * scaleW, totalScale * scaleH);
42
64
  const pathStr = generateSVGPath(clipPath.commands || []);
43
65
  const path2d = new Path2D(pathStr);
44
- ctx.clip(path2d);
66
+ ctx.clip(path2d, 'nonzero');
67
+ ctx.translate(0 - internalX, 0 - internalY);
68
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
69
+ rotateElement(ctx, Object.assign({}, viewElem), () => {
70
+ renderContent === null || renderContent === void 0 ? void 0 : renderContent();
71
+ });
72
+ ctx.restore();
73
+ }
74
+ else {
75
+ renderContent === null || renderContent === void 0 ? void 0 : renderContent();
76
+ }
77
+ }
78
+ function drawClipPathStroke(ctx, viewElem, opts) {
79
+ const { renderContent, originElem, calcElemSize, viewSizeInfo, parentOpacity } = opts;
80
+ const totalScale = viewSizeInfo.devicePixelRatio;
81
+ const { clipPath, clipPathStrokeColor, clipPathStrokeWidth } = (originElem === null || originElem === void 0 ? void 0 : originElem.detail) || {};
82
+ if (clipPath &&
83
+ calcElemSize &&
84
+ clipPath.commands &&
85
+ typeof clipPathStrokeWidth === 'number' &&
86
+ clipPathStrokeWidth > 0 &&
87
+ clipPathStrokeColor) {
88
+ const { x, y, w, h } = calcElemSize;
89
+ const { originW, originH, originX, originY } = clipPath;
90
+ const scaleW = w / originW;
91
+ const scaleH = h / originH;
92
+ const viewOriginX = originX * scaleW;
93
+ const viewOriginY = originY * scaleH;
94
+ const internalX = x - viewOriginX;
95
+ const internalY = y - viewOriginY;
96
+ ctx.save();
97
+ ctx.globalAlpha = parentOpacity;
98
+ ctx.translate(internalX, internalY);
99
+ ctx.scale(totalScale * scaleW, totalScale * scaleH);
100
+ const pathStr = generateSVGPath(clipPath.commands || []);
101
+ const path2d = new Path2D(pathStr);
102
+ ctx.strokeStyle = clipPathStrokeColor;
103
+ ctx.lineWidth = clipPathStrokeWidth;
104
+ ctx.stroke(path2d);
45
105
  ctx.translate(0 - internalX, 0 - internalY);
46
106
  ctx.setTransform(1, 0, 0, 1, 0, 0);
47
107
  rotateElement(ctx, Object.assign({}, viewElem), () => {
@@ -53,15 +113,10 @@ function drawClipPath(ctx, viewElem, opts) {
53
113
  renderContent === null || renderContent === void 0 ? void 0 : renderContent();
54
114
  }
55
115
  }
56
- function drawBoxBackground(ctx, viewElem, opts) {
116
+ export function drawBoxBackground(ctx, viewElem, opts) {
57
117
  var _a, _b;
58
118
  const { pattern, viewScaleInfo, viewSizeInfo } = opts;
59
119
  const transform = [];
60
- let { borderRadius } = viewElem.detail;
61
- const { borderWidth } = viewElem.detail;
62
- if (typeof borderWidth !== 'number') {
63
- borderRadius = 0;
64
- }
65
120
  if (viewElem.detail.background || pattern) {
66
121
  const { x, y, w, h, radiusList } = calcViewBoxSize(viewElem, {
67
122
  viewScaleInfo,
@@ -113,38 +168,36 @@ function drawBoxBackground(ctx, viewElem, opts) {
113
168
  }
114
169
  }
115
170
  }
116
- ctx.fill();
171
+ ctx.fill('nonzero');
117
172
  if (transform && transform.length > 0) {
118
173
  ctx.setTransform(1, 0, 0, 1, 0, 0);
119
174
  }
120
175
  }
121
176
  }
122
- function drawBoxBorder(ctx, viewElem, opts) {
123
- var _a, _b;
177
+ export function drawBoxBorder(ctx, viewElem, opts) {
124
178
  if (viewElem.detail.borderWidth === 0) {
125
179
  return;
126
180
  }
127
181
  if (!isColorStr(viewElem.detail.borderColor)) {
128
182
  return;
129
183
  }
130
- if (((_a = viewElem === null || viewElem === void 0 ? void 0 : viewElem.detail) === null || _a === void 0 ? void 0 : _a.opacity) !== undefined && ((_b = viewElem === null || viewElem === void 0 ? void 0 : viewElem.detail) === null || _b === void 0 ? void 0 : _b.opacity) >= 0) {
131
- ctx.globalAlpha = viewElem.detail.opacity;
132
- }
133
- else {
134
- ctx.globalAlpha = 1;
135
- }
136
184
  const { viewScaleInfo } = opts;
137
185
  const { scale } = viewScaleInfo;
138
186
  let borderColor = defaultElemConfig.borderColor;
139
187
  if (isColorStr(viewElem.detail.borderColor) === true) {
140
188
  borderColor = viewElem.detail.borderColor;
141
189
  }
142
- const { borderWidth, borderRadius, borderDash, boxSizing = defaultElemConfig.boxSizing } = viewElem.detail;
143
- let bw = 0;
144
- if (typeof borderWidth === 'number') {
145
- bw = borderWidth || 1;
190
+ const { borderDash, borderWidth, borderRadius, boxSizing = defaultElemConfig.boxSizing } = viewElem.detail;
191
+ let viewBorderDash = [];
192
+ if (Array.isArray(borderDash) && borderDash.length > 0) {
193
+ viewBorderDash = borderDash.map((num) => Math.ceil(num * scale));
194
+ }
195
+ if (viewBorderDash.length > 0) {
196
+ ctx.lineCap = 'butt';
197
+ }
198
+ else {
199
+ ctx.lineCap = 'square';
146
200
  }
147
- bw = bw * scale;
148
201
  let radiusList = [0, 0, 0, 0];
149
202
  if (typeof borderRadius === 'number') {
150
203
  const br = borderRadius * scale;
@@ -153,11 +206,12 @@ function drawBoxBorder(ctx, viewElem, opts) {
153
206
  else if (Array.isArray(borderRadius) && (borderRadius === null || borderRadius === void 0 ? void 0 : borderRadius.length) === 4) {
154
207
  radiusList = [borderRadius[0] * scale, borderRadius[1] * scale, borderRadius[2] * scale, borderRadius[3] * scale];
155
208
  }
156
- ctx.strokeStyle = borderColor;
157
- let viewBorderDash = [];
158
- if (Array.isArray(borderDash) && borderDash.length > 0) {
159
- viewBorderDash = borderDash.map((num) => Math.ceil(num * scale));
209
+ let bw = 0;
210
+ if (typeof borderWidth === 'number') {
211
+ bw = borderWidth || 1;
160
212
  }
213
+ bw = bw * scale;
214
+ ctx.strokeStyle = borderColor;
161
215
  let borderTop = 0;
162
216
  let borderRight = 0;
163
217
  let borderBottom = 0;
@@ -242,12 +296,6 @@ function drawBoxBorder(ctx, viewElem, opts) {
242
296
  w = viewElem.w;
243
297
  h = viewElem.h;
244
298
  }
245
- if (viewBorderDash.length > 0) {
246
- ctx.lineCap = 'butt';
247
- }
248
- else {
249
- ctx.lineCap = 'square';
250
- }
251
299
  w = Math.max(w, 1);
252
300
  h = Math.max(h, 1);
253
301
  radiusList = radiusList.map((r) => {
@@ -263,7 +311,6 @@ function drawBoxBorder(ctx, viewElem, opts) {
263
311
  ctx.arcTo(x, y, x + w, y, radiusList[0]);
264
312
  ctx.closePath();
265
313
  ctx.stroke();
266
- ctx.globalAlpha = 1;
267
314
  }
268
315
  ctx.setLineDash([]);
269
316
  }
@@ -281,6 +328,12 @@ export function drawBoxShadow(ctx, viewElem, opts) {
281
328
  ctx.restore();
282
329
  }
283
330
  else {
331
+ ctx.save();
332
+ ctx.shadowColor = 'transparent';
333
+ ctx.shadowOffsetX = 0;
334
+ ctx.shadowOffsetY = 0;
335
+ ctx.shadowBlur = 0;
284
336
  renderContent();
337
+ ctx.restore();
285
338
  }
286
339
  }
@@ -1,49 +1,73 @@
1
- import { rotateElement } from '@idraw/util';
1
+ import { rotateElement, calcViewElementSize } from '@idraw/util';
2
2
  import { createColorStyle } from './color';
3
- import { drawBoxShadow } from './box';
3
+ import { drawBoxShadow, getOpacity } from './box';
4
4
  export function drawCircle(ctx, elem, opts) {
5
5
  const { detail, angle } = elem;
6
- const { background = '#000000', borderColor = '#000000', borderWidth = 0 } = detail;
7
- const { calculator, viewScaleInfo, viewSizeInfo } = opts;
8
- const { x, y, w, h } = (calculator === null || calculator === void 0 ? void 0 : calculator.elementSize({ x: elem.x, y: elem.y, w: elem.w, h: elem.h }, viewScaleInfo, viewSizeInfo)) || elem;
6
+ const { viewScaleInfo, viewSizeInfo, parentOpacity } = opts;
7
+ const { background = '#000000', borderColor = '#000000', boxSizing, borderWidth = 0, borderDash } = detail;
8
+ let bw = 0;
9
+ if (typeof borderWidth === 'number' && borderWidth > 0) {
10
+ bw = borderWidth;
11
+ }
12
+ else if (Array.isArray(borderWidth) && typeof borderWidth[0] === 'number' && borderWidth[0] > 0) {
13
+ bw = borderWidth[0];
14
+ }
15
+ bw = bw * viewScaleInfo.scale;
16
+ const { x, y, w, h } = calcViewElementSize({ x: elem.x, y: elem.y, w: elem.w, h: elem.h }, { viewScaleInfo }) || elem;
9
17
  const viewElem = Object.assign(Object.assign({}, elem), { x, y, w, h, angle });
10
18
  rotateElement(ctx, { x, y, w, h, angle }, () => {
11
19
  drawBoxShadow(ctx, viewElem, {
12
20
  viewScaleInfo,
13
21
  viewSizeInfo,
14
22
  renderContent: () => {
15
- var _a, _b;
16
- const a = w / 2;
17
- const b = h / 2;
23
+ let a = w / 2;
24
+ let b = h / 2;
18
25
  const centerX = x + a;
19
26
  const centerY = y + b;
20
- if (((_a = elem === null || elem === void 0 ? void 0 : elem.detail) === null || _a === void 0 ? void 0 : _a.opacity) !== undefined && ((_b = elem === null || elem === void 0 ? void 0 : elem.detail) === null || _b === void 0 ? void 0 : _b.opacity) >= 0) {
21
- ctx.globalAlpha = elem.detail.opacity;
27
+ const radiusA = a;
28
+ const radiusB = b;
29
+ if (bw > 0) {
30
+ if (boxSizing === 'content-box') {
31
+ }
32
+ else if (boxSizing === 'center-line') {
33
+ a = a - bw / 2;
34
+ b = b - bw / 2;
35
+ }
36
+ else {
37
+ a = a - bw;
38
+ b = b - bw;
39
+ }
22
40
  }
23
- else {
24
- ctx.globalAlpha = 1;
25
- }
26
- if (typeof borderWidth === 'number' && borderWidth > 0) {
27
- const ba = borderWidth / 2 + a;
28
- const bb = borderWidth / 2 + b;
41
+ if (a >= 0 && b >= 0) {
42
+ const opacity = getOpacity(viewElem) * parentOpacity;
43
+ ctx.globalAlpha = opacity;
29
44
  ctx.beginPath();
30
- ctx.strokeStyle = borderColor;
31
- ctx.lineWidth = borderWidth;
32
- ctx.circle(centerX, centerY, ba, bb, 0, 0, 2 * Math.PI);
45
+ const fillStyle = createColorStyle(ctx, background, {
46
+ viewElementSize: { x, y, w, h },
47
+ viewScaleInfo,
48
+ opacity: ctx.globalAlpha
49
+ });
50
+ ctx.fillStyle = fillStyle;
51
+ ctx.circle(centerX, centerY, radiusA, radiusB, 0, 0, 2 * Math.PI);
33
52
  ctx.closePath();
34
- ctx.stroke();
53
+ ctx.fill('nonzero');
54
+ ctx.globalAlpha = parentOpacity;
55
+ if (typeof bw === 'number' && bw > 0) {
56
+ const ba = bw / 2 + a;
57
+ const bb = bw / 2 + b;
58
+ ctx.beginPath();
59
+ if (borderDash) {
60
+ const lineDash = borderDash.map((n) => n * viewScaleInfo.scale);
61
+ ctx.setLineDash(lineDash);
62
+ }
63
+ ctx.strokeStyle = borderColor;
64
+ ctx.lineWidth = bw;
65
+ ctx.circle(centerX, centerY, ba, bb, 0, 0, 2 * Math.PI);
66
+ ctx.closePath();
67
+ ctx.stroke();
68
+ ctx.setLineDash([]);
69
+ }
35
70
  }
36
- ctx.beginPath();
37
- const fillStyle = createColorStyle(ctx, background, {
38
- viewElementSize: { x, y, w, h },
39
- viewScaleInfo,
40
- opacity: ctx.globalAlpha
41
- });
42
- ctx.fillStyle = fillStyle;
43
- ctx.circle(centerX, centerY, a, b, 0, 0, 2 * Math.PI);
44
- ctx.closePath();
45
- ctx.fill();
46
- ctx.globalAlpha = 1;
47
71
  }
48
72
  });
49
73
  });
@@ -4,18 +4,21 @@ const defaultDetail = getDefaultElementDetailConfig();
4
4
  export function drawElementList(ctx, data, opts) {
5
5
  var _a;
6
6
  const { elements = [] } = data;
7
+ const { parentOpacity } = opts;
7
8
  for (let i = 0; i < elements.length; i++) {
8
9
  const element = elements[i];
9
10
  const elem = Object.assign(Object.assign({}, element), {
10
11
  detail: Object.assign(Object.assign({}, defaultDetail), element === null || element === void 0 ? void 0 : element.detail)
11
12
  });
12
13
  if (opts.forceDrawAll !== true) {
13
- if (!((_a = opts.calculator) === null || _a === void 0 ? void 0 : _a.isElementInView(elem, opts.viewScaleInfo, opts.viewSizeInfo))) {
14
+ if (!((_a = opts.calculator) === null || _a === void 0 ? void 0 : _a.needRender(elem))) {
14
15
  continue;
15
16
  }
16
17
  }
17
18
  try {
18
- drawElement(ctx, elem, opts);
19
+ drawElement(ctx, elem, Object.assign(Object.assign({}, opts), {
20
+ parentOpacity
21
+ }));
19
22
  }
20
23
  catch (err) {
21
24
  console.error(err);
@@ -0,0 +1,2 @@
1
+ import type { RendererDrawElementOptions, ViewContext2D, ElementGlobal } from '@idraw/types';
2
+ export declare function drawGlobalBackground(ctx: ViewContext2D, global: ElementGlobal | undefined, opts: RendererDrawElementOptions): void;
@@ -0,0 +1,9 @@
1
+ export function drawGlobalBackground(ctx, global, opts) {
2
+ if (typeof (global === null || global === void 0 ? void 0 : global.background) === 'string') {
3
+ const { viewSizeInfo } = opts;
4
+ const { width, height } = viewSizeInfo;
5
+ ctx.globalAlpha = 1;
6
+ ctx.fillStyle = global.background;
7
+ ctx.fillRect(0, 0, width, height);
8
+ }
9
+ }