@idraw/renderer 0.4.0-beta.3 → 0.4.0-beta.30

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/)
@@ -1,9 +1,20 @@
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
+ export declare function getOpacity(elem: Element): number;
3
+ export declare function drawBox(ctx: ViewContext2D, viewElem: Element, opts: {
4
+ originElem: Element;
4
5
  calcElemSize: ElementSize;
5
6
  pattern?: string | CanvasPattern | null;
6
- renderContent: () => void;
7
+ renderContent?: () => void;
8
+ viewScaleInfo: ViewScaleInfo;
9
+ viewSizeInfo: ViewSizeInfo;
10
+ parentOpacity: number;
11
+ }): void;
12
+ export declare function drawBoxBackground(ctx: ViewContext2D, viewElem: Element<ElementType>, opts: {
13
+ pattern?: string | CanvasPattern | null;
14
+ viewScaleInfo: ViewScaleInfo;
15
+ viewSizeInfo: ViewSizeInfo;
16
+ }): void;
17
+ export declare function drawBoxBorder(ctx: ViewContext2D, viewElem: Element<ElementType>, opts: {
7
18
  viewScaleInfo: ViewScaleInfo;
8
19
  viewSizeInfo: ViewSizeInfo;
9
20
  }): void;
@@ -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, { 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;
@@ -53,15 +75,43 @@ function drawClipPath(ctx, viewElem, opts) {
53
75
  renderContent === null || renderContent === void 0 ? void 0 : renderContent();
54
76
  }
55
77
  }
56
- function drawBoxBackground(ctx, viewElem, opts) {
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 && calcElemSize && clipPath.commands && typeof clipPathStrokeWidth === 'number' && clipPathStrokeWidth > 0 && clipPathStrokeColor) {
83
+ const { x, y, w, h } = calcElemSize;
84
+ const { originW, originH, originX, originY } = clipPath;
85
+ const scaleW = w / originW;
86
+ const scaleH = h / originH;
87
+ const viewOriginX = originX * scaleW;
88
+ const viewOriginY = originY * scaleH;
89
+ const internalX = x - viewOriginX;
90
+ const internalY = y - viewOriginY;
91
+ ctx.save();
92
+ ctx.globalAlpha = parentOpacity;
93
+ ctx.translate(internalX, internalY);
94
+ ctx.scale(totalScale * scaleW, totalScale * scaleH);
95
+ const pathStr = generateSVGPath(clipPath.commands || []);
96
+ const path2d = new Path2D(pathStr);
97
+ ctx.strokeStyle = clipPathStrokeColor;
98
+ ctx.lineWidth = clipPathStrokeWidth;
99
+ ctx.stroke(path2d);
100
+ ctx.translate(0 - internalX, 0 - internalY);
101
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
102
+ rotateElement(ctx, Object.assign({}, viewElem), () => {
103
+ renderContent === null || renderContent === void 0 ? void 0 : renderContent();
104
+ });
105
+ ctx.restore();
106
+ }
107
+ else {
108
+ renderContent === null || renderContent === void 0 ? void 0 : renderContent();
109
+ }
110
+ }
111
+ export function drawBoxBackground(ctx, viewElem, opts) {
57
112
  var _a, _b;
58
113
  const { pattern, viewScaleInfo, viewSizeInfo } = opts;
59
114
  const transform = [];
60
- let { borderRadius } = viewElem.detail;
61
- const { borderWidth } = viewElem.detail;
62
- if (typeof borderWidth !== 'number') {
63
- borderRadius = 0;
64
- }
65
115
  if (viewElem.detail.background || pattern) {
66
116
  const { x, y, w, h, radiusList } = calcViewBoxSize(viewElem, {
67
117
  viewScaleInfo,
@@ -119,20 +169,13 @@ function drawBoxBackground(ctx, viewElem, opts) {
119
169
  }
120
170
  }
121
171
  }
122
- function drawBoxBorder(ctx, viewElem, opts) {
123
- var _a, _b;
172
+ export function drawBoxBorder(ctx, viewElem, opts) {
124
173
  if (viewElem.detail.borderWidth === 0) {
125
174
  return;
126
175
  }
127
176
  if (!isColorStr(viewElem.detail.borderColor)) {
128
177
  return;
129
178
  }
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
179
  const { viewScaleInfo } = opts;
137
180
  const { scale } = viewScaleInfo;
138
181
  let borderColor = defaultElemConfig.borderColor;
@@ -263,7 +306,6 @@ function drawBoxBorder(ctx, viewElem, opts) {
263
306
  ctx.arcTo(x, y, x + w, y, radiusList[0]);
264
307
  ctx.closePath();
265
308
  ctx.stroke();
266
- ctx.globalAlpha = 1;
267
309
  }
268
310
  ctx.setLineDash([]);
269
311
  }
@@ -281,6 +323,12 @@ export function drawBoxShadow(ctx, viewElem, opts) {
281
323
  ctx.restore();
282
324
  }
283
325
  else {
326
+ ctx.save();
327
+ ctx.shadowColor = 'transparent';
328
+ ctx.shadowOffsetX = 0;
329
+ ctx.shadowOffsetY = 0;
330
+ ctx.shadowBlur = 0;
284
331
  renderContent();
332
+ ctx.restore();
285
333
  }
286
334
  }
@@ -1,49 +1,75 @@
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
+ a = a;
32
+ b = b;
33
+ }
34
+ else if (boxSizing === 'center-line') {
35
+ a = a - bw / 2;
36
+ b = b - bw / 2;
37
+ }
38
+ else {
39
+ a = a - bw;
40
+ b = b - bw;
41
+ }
22
42
  }
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;
43
+ if (a >= 0 && b >= 0) {
44
+ const opacity = getOpacity(viewElem) * parentOpacity;
45
+ ctx.globalAlpha = opacity;
29
46
  ctx.beginPath();
30
- ctx.strokeStyle = borderColor;
31
- ctx.lineWidth = borderWidth;
32
- ctx.circle(centerX, centerY, ba, bb, 0, 0, 2 * Math.PI);
47
+ const fillStyle = createColorStyle(ctx, background, {
48
+ viewElementSize: { x, y, w, h },
49
+ viewScaleInfo,
50
+ opacity: ctx.globalAlpha
51
+ });
52
+ ctx.fillStyle = fillStyle;
53
+ ctx.circle(centerX, centerY, radiusA, radiusB, 0, 0, 2 * Math.PI);
33
54
  ctx.closePath();
34
- ctx.stroke();
55
+ ctx.fill();
56
+ ctx.globalAlpha = parentOpacity;
57
+ if (typeof bw === 'number' && bw > 0) {
58
+ const ba = bw / 2 + a;
59
+ const bb = bw / 2 + b;
60
+ ctx.beginPath();
61
+ if (borderDash) {
62
+ const lineDash = borderDash.map((n) => n * viewScaleInfo.scale);
63
+ ctx.setLineDash(lineDash);
64
+ }
65
+ ctx.strokeStyle = borderColor;
66
+ ctx.lineWidth = bw;
67
+ ctx.circle(centerX, centerY, ba, bb, 0, 0, 2 * Math.PI);
68
+ ctx.closePath();
69
+ ctx.stroke();
70
+ ctx.setLineDash([]);
71
+ }
35
72
  }
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
73
  }
48
74
  });
49
75
  });
@@ -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, ElementGlobalDetail } from '@idraw/types';
2
+ export declare function drawGlobalBackground(ctx: ViewContext2D, global: ElementGlobalDetail | 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
+ }
@@ -1,17 +1,27 @@
1
- import { rotateElement, calcViewBoxSize } from '@idraw/util';
1
+ import { rotateElement, calcViewBoxSize, calcViewElementSize } from '@idraw/util';
2
2
  import { drawCircle } from './circle';
3
3
  import { drawRect } from './rect';
4
4
  import { drawImage } from './image';
5
5
  import { drawText } from './text';
6
6
  import { drawSVG } from './svg';
7
7
  import { drawHTML } from './html';
8
- import { drawBox, drawBoxShadow } from './box';
8
+ import { drawBox, drawBoxShadow, getOpacity } from './box';
9
9
  import { drawPath } from './path';
10
+ const visiableMinSize = 0.4;
10
11
  export function drawElement(ctx, elem, opts) {
11
- var _a;
12
+ var _a, _b, _c;
12
13
  if (((_a = elem === null || elem === void 0 ? void 0 : elem.operations) === null || _a === void 0 ? void 0 : _a.invisible) === true) {
13
14
  return;
14
15
  }
16
+ const { w, h } = elem;
17
+ const { scale } = opts.viewScaleInfo;
18
+ if ((scale < 1 && (w * scale < visiableMinSize || h * scale < visiableMinSize)) || opts.parentOpacity === 0) {
19
+ return;
20
+ }
21
+ const { overrideElementMap } = opts;
22
+ if ((_c = (_b = overrideElementMap === null || overrideElementMap === void 0 ? void 0 : overrideElementMap[elem.uuid]) === null || _b === void 0 ? void 0 : _b.operations) === null || _c === void 0 ? void 0 : _c.invisible) {
23
+ return;
24
+ }
15
25
  try {
16
26
  switch (elem.type) {
17
27
  case 'rect': {
@@ -57,10 +67,11 @@ export function drawElement(ctx, elem, opts) {
57
67
  }
58
68
  }
59
69
  export function drawGroup(ctx, elem, opts) {
60
- const { calculator, viewScaleInfo, viewSizeInfo } = opts;
61
- const { x, y, w, h, angle } = (calculator === null || calculator === void 0 ? void 0 : calculator.elementSize({ x: elem.x, y: elem.y, w: elem.w, h: elem.h, angle: elem.angle }, viewScaleInfo, viewSizeInfo)) || elem;
70
+ const { viewScaleInfo, viewSizeInfo, parentOpacity } = opts;
71
+ const { x, y, w, h, angle } = calcViewElementSize({ x: elem.x, y: elem.y, w: elem.w, h: elem.h, angle: elem.angle }, { viewScaleInfo }) || elem;
62
72
  const viewElem = Object.assign(Object.assign({}, elem), { x, y, w, h, angle });
63
73
  rotateElement(ctx, { x, y, w, h, angle }, () => {
74
+ ctx.globalAlpha = getOpacity(elem) * parentOpacity;
64
75
  drawBoxShadow(ctx, viewElem, {
65
76
  viewScaleInfo,
66
77
  viewSizeInfo,
@@ -70,6 +81,7 @@ export function drawGroup(ctx, elem, opts) {
70
81
  calcElemSize: { x, y, w, h, angle },
71
82
  viewScaleInfo,
72
83
  viewSizeInfo,
84
+ parentOpacity,
73
85
  renderContent: () => {
74
86
  const { x, y, w, h, radiusList } = calcViewBoxSize(viewElem, {
75
87
  viewScaleInfo,
@@ -105,12 +117,12 @@ export function drawGroup(ctx, elem, opts) {
105
117
  y: newParentSize.y + child.y
106
118
  });
107
119
  if (opts.forceDrawAll !== true) {
108
- if (!(calculator === null || calculator === void 0 ? void 0 : calculator.isElementInView(child, opts.viewScaleInfo, opts.viewSizeInfo))) {
120
+ if (!(calculator === null || calculator === void 0 ? void 0 : calculator.needRender(child))) {
109
121
  continue;
110
122
  }
111
123
  }
112
124
  try {
113
- drawElement(ctx, child, Object.assign({}, opts));
125
+ drawElement(ctx, child, Object.assign(Object.assign({}, opts), { parentOpacity: parentOpacity * getOpacity(elem) }));
114
126
  }
115
127
  catch (err) {
116
128
  console.error(err);
@@ -118,12 +130,12 @@ export function drawGroup(ctx, elem, opts) {
118
130
  }
119
131
  }
120
132
  if (elem.detail.overflow === 'hidden') {
121
- ctx.globalAlpha = 1;
122
133
  ctx.restore();
123
134
  }
124
135
  }
125
136
  });
126
137
  }
127
138
  });
139
+ ctx.globalAlpha = parentOpacity;
128
140
  });
129
141
  }
@@ -1,17 +1,17 @@
1
- import { rotateElement } from '@idraw/util';
1
+ import { rotateElement, calcViewElementSize } from '@idraw/util';
2
+ import { getOpacity } from './box';
2
3
  export function drawHTML(ctx, elem, opts) {
3
4
  const content = opts.loader.getContent(elem);
4
- const { calculator, viewScaleInfo, viewSizeInfo } = opts;
5
- const { x, y, w, h, angle } = (calculator === null || calculator === void 0 ? void 0 : calculator.elementSize(elem, viewScaleInfo, viewSizeInfo)) || elem;
5
+ const { viewScaleInfo, viewSizeInfo, parentOpacity } = opts;
6
+ const { x, y, w, h, angle } = calcViewElementSize(elem, { viewScaleInfo, viewSizeInfo }) || elem;
6
7
  rotateElement(ctx, { x, y, w, h, angle }, () => {
7
- if (!content) {
8
+ if (!content && !opts.loader.isDestroyed()) {
8
9
  opts.loader.load(elem, opts.elementAssets || {});
9
10
  }
10
11
  if (elem.type === 'html' && content) {
11
- const { opacity } = elem.detail;
12
- ctx.globalAlpha = opacity ? opacity : 1;
12
+ ctx.globalAlpha = getOpacity(elem) * parentOpacity;
13
13
  ctx.drawImage(content, x, y, w, h);
14
- ctx.globalAlpha = 1;
14
+ ctx.globalAlpha = parentOpacity;
15
15
  }
16
16
  });
17
17
  }
@@ -1,9 +1,9 @@
1
- import { rotateElement, calcViewBoxSize } from '@idraw/util';
2
- import { drawBox, drawBoxShadow } from './box';
1
+ import { rotateElement, calcViewBoxSize, calcViewElementSize } from '@idraw/util';
2
+ import { drawBox, drawBoxShadow, getOpacity } from './box';
3
3
  export function drawImage(ctx, elem, opts) {
4
4
  const content = opts.loader.getContent(elem);
5
- const { calculator, viewScaleInfo, viewSizeInfo } = opts;
6
- const { x, y, w, h, angle } = (calculator === null || calculator === void 0 ? void 0 : calculator.elementSize(elem, viewScaleInfo, viewSizeInfo)) || elem;
5
+ const { viewScaleInfo, viewSizeInfo, parentOpacity } = opts;
6
+ const { x, y, w, h, angle } = calcViewElementSize(elem, { viewScaleInfo }) || elem;
7
7
  const viewElem = Object.assign(Object.assign({}, elem), { x, y, w, h, angle });
8
8
  rotateElement(ctx, { x, y, w, h, angle }, () => {
9
9
  drawBoxShadow(ctx, viewElem, {
@@ -15,17 +15,21 @@ export function drawImage(ctx, elem, opts) {
15
15
  calcElemSize: { x, y, w, h, angle },
16
16
  viewScaleInfo,
17
17
  viewSizeInfo,
18
+ parentOpacity,
18
19
  renderContent: () => {
19
- if (!content) {
20
+ if (!content && !opts.loader.isDestroyed()) {
20
21
  opts.loader.load(elem, opts.elementAssets || {});
21
22
  }
22
23
  if (elem.type === 'image' && content) {
23
- const { opacity } = elem.detail;
24
- ctx.globalAlpha = opacity ? opacity : 1;
24
+ ctx.globalAlpha = getOpacity(elem) * parentOpacity;
25
25
  const { x, y, w, h, radiusList } = calcViewBoxSize(viewElem, {
26
26
  viewScaleInfo,
27
27
  viewSizeInfo
28
28
  });
29
+ const { detail } = elem;
30
+ const { scaleMode, originW = 0, originH = 0 } = detail;
31
+ const imageW = ctx.$undoPixelRatio(originW);
32
+ const imageH = ctx.$undoPixelRatio(originH);
29
33
  ctx.save();
30
34
  ctx.fillStyle = 'transparent';
31
35
  ctx.beginPath();
@@ -37,8 +41,45 @@ export function drawImage(ctx, elem, opts) {
37
41
  ctx.closePath();
38
42
  ctx.fill();
39
43
  ctx.clip();
40
- ctx.drawImage(content, x, y, w, h);
41
- ctx.globalAlpha = 1;
44
+ if (scaleMode && originH && originW) {
45
+ let sx = 0;
46
+ let sy = 0;
47
+ let sWidth = imageW;
48
+ let sHeight = imageH;
49
+ const dx = x;
50
+ const dy = y;
51
+ const dWidth = w;
52
+ const dHeight = h;
53
+ if (imageW > elem.w || imageH > elem.h) {
54
+ if (scaleMode === 'fill') {
55
+ const sourceScale = Math.max(elem.w / imageW, elem.h / imageH);
56
+ const newImageWidth = imageW * sourceScale;
57
+ const newImageHeight = imageH * sourceScale;
58
+ sx = (newImageWidth - elem.w) / 2 / sourceScale;
59
+ sy = (newImageHeight - elem.h) / 2 / sourceScale;
60
+ sWidth = elem.w / sourceScale;
61
+ sHeight = elem.h / sourceScale;
62
+ }
63
+ else if (scaleMode === 'tile') {
64
+ sx = 0;
65
+ sy = 0;
66
+ sWidth = elem.w;
67
+ sHeight = elem.h;
68
+ }
69
+ else if (scaleMode === 'fit') {
70
+ const sourceScale = Math.min(elem.w / imageW, elem.h / imageH);
71
+ sx = (imageW - elem.w / sourceScale) / 2;
72
+ sy = (imageH - elem.h / sourceScale) / 2;
73
+ sWidth = elem.w / sourceScale;
74
+ sHeight = elem.h / sourceScale;
75
+ }
76
+ }
77
+ ctx.drawImage(content, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
78
+ }
79
+ else {
80
+ ctx.drawImage(content, x, y, w, h);
81
+ }
82
+ ctx.globalAlpha = parentOpacity;
42
83
  ctx.restore();
43
84
  }
44
85
  }
@@ -5,3 +5,5 @@ export { drawSVG } from './svg';
5
5
  export { drawHTML } from './html';
6
6
  export { drawText } from './text';
7
7
  export { drawElementList } from './elements';
8
+ export { drawLayout } from './layout';
9
+ export { drawGlobalBackground } from './global';
@@ -5,3 +5,5 @@ export { drawSVG } from './svg';
5
5
  export { drawHTML } from './html';
6
6
  export { drawText } from './text';
7
7
  export { drawElementList } from './elements';
8
+ export { drawLayout } from './layout';
9
+ export { drawGlobalBackground } from './global';
@@ -0,0 +1,2 @@
1
+ import type { RendererDrawElementOptions, ViewContext2D, DataLayout } from '@idraw/types';
2
+ export declare function drawLayout(ctx: ViewContext2D, layout: DataLayout, opts: RendererDrawElementOptions, renderContent: (ctx: ViewContext2D) => void): void;
@@ -0,0 +1,44 @@
1
+ import { calcViewElementSize, calcViewBoxSize } from '@idraw/util';
2
+ import { drawBoxShadow, drawBoxBackground, drawBoxBorder } from './box';
3
+ export function drawLayout(ctx, layout, opts, renderContent) {
4
+ const { viewScaleInfo, viewSizeInfo, parentOpacity } = opts;
5
+ const elem = Object.assign({ uuid: 'layout', type: 'group' }, layout);
6
+ const { x, y, w, h } = calcViewElementSize(elem, { viewScaleInfo }) || elem;
7
+ const angle = 0;
8
+ const viewElem = Object.assign(Object.assign({}, elem), { x, y, w, h, angle });
9
+ ctx.globalAlpha = 1;
10
+ drawBoxShadow(ctx, viewElem, {
11
+ viewScaleInfo,
12
+ viewSizeInfo,
13
+ renderContent: () => {
14
+ drawBoxBackground(ctx, viewElem, { viewScaleInfo, viewSizeInfo });
15
+ }
16
+ });
17
+ if (layout.detail.overflow === 'hidden') {
18
+ const { viewScaleInfo, viewSizeInfo } = opts;
19
+ const elem = Object.assign({ uuid: 'layout', type: 'group' }, layout);
20
+ const viewElemSize = calcViewElementSize(elem, { viewScaleInfo }) || elem;
21
+ const viewElem = Object.assign(Object.assign({}, elem), viewElemSize);
22
+ const { x, y, w, h, radiusList } = calcViewBoxSize(viewElem, {
23
+ viewScaleInfo,
24
+ viewSizeInfo
25
+ });
26
+ ctx.save();
27
+ ctx.fillStyle = 'transparent';
28
+ ctx.beginPath();
29
+ ctx.moveTo(x + radiusList[0], y);
30
+ ctx.arcTo(x + w, y, x + w, y + h, radiusList[1]);
31
+ ctx.arcTo(x + w, y + h, x, y + h, radiusList[2]);
32
+ ctx.arcTo(x, y + h, x, y, radiusList[3]);
33
+ ctx.arcTo(x, y, x + w, y, radiusList[0]);
34
+ ctx.closePath();
35
+ ctx.fill();
36
+ ctx.clip();
37
+ }
38
+ renderContent(ctx);
39
+ if (layout.detail.overflow === 'hidden') {
40
+ ctx.restore();
41
+ }
42
+ drawBoxBorder(ctx, viewElem, { viewScaleInfo, viewSizeInfo });
43
+ ctx.globalAlpha = parentOpacity;
44
+ }