foliko 1.1.1 → 1.1.2
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/.agent/data/weixin-media/2026-04-08/img_1775618677512.jpg +0 -0
- package/.agent/data/weixin-media/2026-04-08/img_1775619073340.jpg +0 -0
- package/.agent/data/weixin-media/2026-04-08/img_1775619097536.jpg +0 -0
- package/.agent/data/weixin-media/2026-04-08/img_1775619209388.jpg +0 -0
- package/.agent/plugins/poster-plugin/package.json +2 -1
- package/.agent/plugins/poster-plugin/src/canvas.js +70 -7
- package/.agent/plugins/poster-plugin/src/components/barcode.js +120 -0
- package/.agent/plugins/poster-plugin/src/components/bubble.js +153 -0
- package/.agent/plugins/poster-plugin/src/components/button.js +124 -0
- package/.agent/plugins/poster-plugin/src/components/cta.js +26 -24
- package/.agent/plugins/poster-plugin/src/components/featureGrid.js +22 -17
- package/.agent/plugins/poster-plugin/src/components/frame.js +230 -0
- package/.agent/plugins/poster-plugin/src/components/highlightText.js +144 -0
- package/.agent/plugins/poster-plugin/src/components/icon.js +94 -0
- package/.agent/plugins/poster-plugin/src/components/index.js +19 -0
- package/.agent/plugins/poster-plugin/src/components/listItem.js +6 -5
- package/.agent/plugins/poster-plugin/src/components/qrcode.js +74 -0
- package/.agent/plugins/poster-plugin/src/components/ribbon.js +193 -0
- package/.agent/plugins/poster-plugin/src/components/seal.js +146 -0
- package/.agent/plugins/poster-plugin/src/components/table.js +17 -9
- package/.agent/plugins/poster-plugin/src/components/tagCloud.js +24 -17
- package/.agent/plugins/poster-plugin/src/components/timeline.js +24 -12
- package/.agent/plugins/poster-plugin/src/composer.js +392 -150
- package/.agent/plugins/poster-plugin/src/elements/background.js +36 -4
- package/.agent/plugins/poster-plugin/src/elements/image.js +4 -47
- package/.agent/plugins/poster-plugin/src/elements/index.js +2 -0
- package/.agent/plugins/poster-plugin/src/elements/richText.js +230 -0
- package/.agent/plugins/poster-plugin/src/elements/svg.js +35 -19
- package/.agent/plugins/poster-plugin/src/index.js +430 -7
- package/.agent/plugins/poster-plugin/src/utils/imageLoader.js +84 -0
- package/.agent/plugins/poster-plugin/test-background.svg +1 -0
- package/.agent/plugins/poster-plugin/test-full-poster.svg +2 -0
- package/.agent/plugins/poster-plugin/test-image.png +0 -0
- package/.agent/sessions/cli_default.json +1089 -145
- package/.agent/sessions/weixin_o9cq80zgZqKPA2-s59PN43GdDy1w@im.wechat.json +8902 -0
- package/.claude/settings.local.json +6 -1
- package/output/beef-love-poster.png +0 -0
- package/output/international-news-daily.png +0 -0
- package/package.json +2 -1
- package/plugins/extension-executor-plugin.js +33 -32
- package/plugins/file-system-plugin.js +4 -19
- package/plugins/subagent-plugin.js +37 -14
- package/plugins/weixin-plugin.js +167 -47
- package/poster-test-2.png +0 -0
- package/skills/poster-guide/SKILL.md +497 -5
- package/src/core/agent-chat.js +141 -8
- package/src/core/agent.js +6 -3
- package/calc_tokens_weixin.js +0 -81
- package/foliko-creative-3.png +0 -0
- package/foliko-creative-4.png +0 -0
- package/foliko-creative-5.png +0 -0
- package/story-cover-book-v2.png +0 -0
- package/story-cover-japanese-1.png +0 -0
- package/story-cover-japanese-2.png +0 -0
- package/story-cover-japanese-3.png +0 -0
- package/story-cover-moran.png +0 -0
- package/undefined.png +0 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 丝带/飘带组件
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const paper = require('paper')
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 创建丝带
|
|
9
|
+
*/
|
|
10
|
+
function createRibbon(project, args) {
|
|
11
|
+
const {
|
|
12
|
+
x = 0,
|
|
13
|
+
y = 0,
|
|
14
|
+
width = 300,
|
|
15
|
+
text = '',
|
|
16
|
+
fontSize = 28,
|
|
17
|
+
fontFamily,
|
|
18
|
+
color = '#ffffff',
|
|
19
|
+
backgroundColor = '#e74c3c',
|
|
20
|
+
borderColor,
|
|
21
|
+
borderWidth = 2,
|
|
22
|
+
shadow,
|
|
23
|
+
position = 'top', // top, bottom, left, right
|
|
24
|
+
style = 'fold', // fold, diagonal, corner
|
|
25
|
+
opacity = 1,
|
|
26
|
+
} = args
|
|
27
|
+
|
|
28
|
+
const items = []
|
|
29
|
+
|
|
30
|
+
if (style === 'diagonal') {
|
|
31
|
+
// 对角丝带
|
|
32
|
+
const diagonalLength = Math.sqrt(width ** 2 + 60 ** 2)
|
|
33
|
+
const angle = Math.atan2(60, width) * 180 / Math.PI
|
|
34
|
+
|
|
35
|
+
const ribbon = new paper.Path.Rectangle({
|
|
36
|
+
point: [x, y],
|
|
37
|
+
size: [diagonalLength, 60],
|
|
38
|
+
radius: 4,
|
|
39
|
+
fillColor: new paper.Color(backgroundColor),
|
|
40
|
+
})
|
|
41
|
+
ribbon.rotate(angle, new paper.Point(x, y))
|
|
42
|
+
|
|
43
|
+
if (borderColor) {
|
|
44
|
+
ribbon.strokeColor = new paper.Color(borderColor)
|
|
45
|
+
ribbon.strokeWidth = borderWidth
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (shadow) {
|
|
49
|
+
ribbon.shadowColor = new paper.Color(shadow.color || '#000000')
|
|
50
|
+
ribbon.shadowBlur = shadow.blur || 8
|
|
51
|
+
ribbon.shadowOffset = new paper.Point(shadow.offsetX || 3, shadow.offsetY || 3)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (opacity !== 1) ribbon.opacity = opacity
|
|
55
|
+
items.push(ribbon)
|
|
56
|
+
|
|
57
|
+
// 文字
|
|
58
|
+
const textItem = new paper.PointText({
|
|
59
|
+
point: [x + diagonalLength / 2, y + 60 / 2 + fontSize / 3],
|
|
60
|
+
content: text,
|
|
61
|
+
fontSize,
|
|
62
|
+
fontFamily: fontFamily || 'sans-serif',
|
|
63
|
+
fillColor: new paper.Color(color),
|
|
64
|
+
justification: 'center',
|
|
65
|
+
})
|
|
66
|
+
textItem.rotate(angle, new paper.Point(x + diagonalLength / 2, y + 60 / 2))
|
|
67
|
+
|
|
68
|
+
if (opacity !== 1) textItem.opacity = opacity
|
|
69
|
+
items.push(textItem)
|
|
70
|
+
|
|
71
|
+
} else if (style === 'corner') {
|
|
72
|
+
// 角落丝带
|
|
73
|
+
const ribbonWidth = width
|
|
74
|
+
const ribbonHeight = 50
|
|
75
|
+
|
|
76
|
+
// 主丝带
|
|
77
|
+
const ribbon = new paper.Path.Rectangle({
|
|
78
|
+
point: [x, y],
|
|
79
|
+
size: [ribbonWidth, ribbonHeight],
|
|
80
|
+
fillColor: new paper.Color(backgroundColor),
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
if (borderColor) {
|
|
84
|
+
ribbon.strokeColor = new paper.Color(borderColor)
|
|
85
|
+
ribbon.strokeWidth = borderWidth
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (shadow) {
|
|
89
|
+
ribbon.shadowColor = new paper.Color(shadow.color || '#000000')
|
|
90
|
+
ribbon.shadowBlur = shadow.blur || 8
|
|
91
|
+
ribbon.shadowOffset = new paper.Point(shadow.offsetX || 3, shadow.offsetY || 3)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (opacity !== 1) ribbon.opacity = opacity
|
|
95
|
+
items.push(ribbon)
|
|
96
|
+
|
|
97
|
+
// 折叠部分
|
|
98
|
+
const foldSize = 20
|
|
99
|
+
const fold = new paper.Path()
|
|
100
|
+
fold.add(new paper.Point(x, y + ribbonHeight))
|
|
101
|
+
fold.add(new paper.Point(x, y + ribbonHeight + foldSize))
|
|
102
|
+
fold.add(new paper.Point(x + foldSize, y + ribbonHeight))
|
|
103
|
+
fold.closed = true
|
|
104
|
+
fold.fillColor = new paper.Color(backgroundColor).multiply(0.8)
|
|
105
|
+
|
|
106
|
+
if (borderColor) {
|
|
107
|
+
fold.strokeColor = new paper.Color(borderColor)
|
|
108
|
+
fold.strokeWidth = borderWidth
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (opacity !== 1) fold.opacity = opacity
|
|
112
|
+
items.push(fold)
|
|
113
|
+
|
|
114
|
+
// 文字
|
|
115
|
+
const textItem = new paper.PointText({
|
|
116
|
+
point: [x + ribbonWidth / 2, y + ribbonHeight / 2 + fontSize / 3],
|
|
117
|
+
content: text,
|
|
118
|
+
fontSize,
|
|
119
|
+
fontFamily: fontFamily || 'sans-serif',
|
|
120
|
+
fillColor: new paper.Color(color),
|
|
121
|
+
justification: 'center',
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
if (opacity !== 1) textItem.opacity = opacity
|
|
125
|
+
items.push(textItem)
|
|
126
|
+
|
|
127
|
+
} else {
|
|
128
|
+
// 折叠丝带 (默认)
|
|
129
|
+
const ribbonHeight = 50
|
|
130
|
+
|
|
131
|
+
// 主丝带
|
|
132
|
+
const ribbon = new paper.Path.Rectangle({
|
|
133
|
+
point: [x, y],
|
|
134
|
+
size: [width, ribbonHeight],
|
|
135
|
+
fillColor: new paper.Color(backgroundColor),
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
if (borderColor) {
|
|
139
|
+
ribbon.strokeColor = new paper.Color(borderColor)
|
|
140
|
+
ribbon.strokeWidth = borderWidth
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (shadow) {
|
|
144
|
+
ribbon.shadowColor = new paper.Color(shadow.color || '#000000')
|
|
145
|
+
ribbon.shadowBlur = shadow.blur || 8
|
|
146
|
+
ribbon.shadowOffset = new paper.Point(shadow.offsetX || 3, shadow.offsetY || 3)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (opacity !== 1) ribbon.opacity = opacity
|
|
150
|
+
items.push(ribbon)
|
|
151
|
+
|
|
152
|
+
// 左右折叠三角
|
|
153
|
+
const foldSize = 15
|
|
154
|
+
const leftFold = new paper.Path()
|
|
155
|
+
leftFold.add(new paper.Point(x, y))
|
|
156
|
+
leftFold.add(new paper.Point(x - foldSize, y - foldSize))
|
|
157
|
+
leftFold.add(new paper.Point(x, y - foldSize))
|
|
158
|
+
leftFold.closed = true
|
|
159
|
+
leftFold.fillColor = new paper.Color(backgroundColor).multiply(0.8)
|
|
160
|
+
if (opacity !== 1) leftFold.opacity = opacity
|
|
161
|
+
items.push(leftFold)
|
|
162
|
+
|
|
163
|
+
const rightFold = new paper.Path()
|
|
164
|
+
rightFold.add(new paper.Point(x + width, y))
|
|
165
|
+
rightFold.add(new paper.Point(x + width + foldSize, y - foldSize))
|
|
166
|
+
rightFold.add(new paper.Point(x + width, y - foldSize))
|
|
167
|
+
rightFold.closed = true
|
|
168
|
+
rightFold.fillColor = new paper.Color(backgroundColor).multiply(0.8)
|
|
169
|
+
if (opacity !== 1) rightFold.opacity = opacity
|
|
170
|
+
items.push(rightFold)
|
|
171
|
+
|
|
172
|
+
// 文字
|
|
173
|
+
const textItem = new paper.PointText({
|
|
174
|
+
point: [x + width / 2, y + ribbonHeight / 2 + fontSize / 3],
|
|
175
|
+
content: text,
|
|
176
|
+
fontSize,
|
|
177
|
+
fontFamily: fontFamily || 'sans-serif',
|
|
178
|
+
fillColor: new paper.Color(color),
|
|
179
|
+
justification: 'center',
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
if (opacity !== 1) textItem.opacity = opacity
|
|
183
|
+
items.push(textItem)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
success: true,
|
|
188
|
+
type: 'ribbon',
|
|
189
|
+
items: items.map(i => i.id),
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
module.exports = createRibbon
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 印章组件 - 印章效果
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const paper = require('paper')
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 创建印章
|
|
9
|
+
*/
|
|
10
|
+
function createSeal(project, args) {
|
|
11
|
+
const {
|
|
12
|
+
x = 0,
|
|
13
|
+
y = 0,
|
|
14
|
+
size = 100,
|
|
15
|
+
text = '印章',
|
|
16
|
+
fontSize = 24,
|
|
17
|
+
fontFamily,
|
|
18
|
+
color = '#e74c3c',
|
|
19
|
+
borderColor,
|
|
20
|
+
style = 'circle', // circle, square, star, hexagon
|
|
21
|
+
borderWidth = 3,
|
|
22
|
+
opacity = 1,
|
|
23
|
+
} = args
|
|
24
|
+
|
|
25
|
+
const items = []
|
|
26
|
+
const centerX = x + size / 2
|
|
27
|
+
const centerY = y + size / 2
|
|
28
|
+
|
|
29
|
+
// 印章边框
|
|
30
|
+
let border
|
|
31
|
+
switch (style) {
|
|
32
|
+
case 'circle':
|
|
33
|
+
border = new paper.Path.Circle({
|
|
34
|
+
center: [centerX, centerY],
|
|
35
|
+
radius: size / 2 - borderWidth,
|
|
36
|
+
})
|
|
37
|
+
break
|
|
38
|
+
case 'square':
|
|
39
|
+
const squareSize = size - borderWidth * 2
|
|
40
|
+
border = new paper.Path.Rectangle({
|
|
41
|
+
point: [x + borderWidth, y + borderWidth],
|
|
42
|
+
size: [squareSize, squareSize],
|
|
43
|
+
radius: 4,
|
|
44
|
+
})
|
|
45
|
+
break
|
|
46
|
+
case 'star':
|
|
47
|
+
border = createStarPath(centerX, centerY, size / 2 - borderWidth, size / 2 - borderWidth - 10, 5)
|
|
48
|
+
break
|
|
49
|
+
case 'hexagon':
|
|
50
|
+
border = createPolygonPath(centerX, centerY, size / 2 - borderWidth, 6)
|
|
51
|
+
break
|
|
52
|
+
default:
|
|
53
|
+
border = new paper.Path.Circle({
|
|
54
|
+
center: [centerX, centerY],
|
|
55
|
+
radius: size / 2 - borderWidth,
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
border.strokeColor = new paper.Color(color)
|
|
60
|
+
border.strokeWidth = borderWidth
|
|
61
|
+
border.fillColor = null
|
|
62
|
+
if (opacity !== 1) border.opacity = opacity
|
|
63
|
+
items.push(border)
|
|
64
|
+
|
|
65
|
+
// 内边框
|
|
66
|
+
const innerBorder = border.clone()
|
|
67
|
+
innerBorder.scale(0.85, 0.85, new paper.Point(centerX, centerY))
|
|
68
|
+
innerBorder.strokeWidth = 1
|
|
69
|
+
if (opacity !== 1) innerBorder.opacity = opacity
|
|
70
|
+
items.push(innerBorder)
|
|
71
|
+
|
|
72
|
+
// 文字
|
|
73
|
+
const textItem = new paper.PointText({
|
|
74
|
+
point: [centerX, centerY + fontSize / 3],
|
|
75
|
+
content: text,
|
|
76
|
+
fontSize,
|
|
77
|
+
fontFamily: fontFamily || 'serif',
|
|
78
|
+
fillColor: new paper.Color(color),
|
|
79
|
+
justification: 'center',
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
if (opacity !== 1) textItem.opacity = opacity
|
|
83
|
+
items.push(textItem)
|
|
84
|
+
|
|
85
|
+
// 顶部文字(如果适用)
|
|
86
|
+
const topText = new paper.PointText({
|
|
87
|
+
point: [centerX, centerY - size / 4],
|
|
88
|
+
content: '★',
|
|
89
|
+
fontSize: 16,
|
|
90
|
+
fontFamily: fontFamily || 'serif',
|
|
91
|
+
fillColor: new paper.Color(color),
|
|
92
|
+
justification: 'center',
|
|
93
|
+
})
|
|
94
|
+
if (opacity !== 1) topText.opacity = opacity
|
|
95
|
+
items.push(topText)
|
|
96
|
+
|
|
97
|
+
// 底部星星装饰
|
|
98
|
+
const bottomStar = new paper.PointText({
|
|
99
|
+
point: [centerX, centerY + size / 3],
|
|
100
|
+
content: '★ ★ ★',
|
|
101
|
+
fontSize: 12,
|
|
102
|
+
fontFamily: fontFamily || 'serif',
|
|
103
|
+
fillColor: new paper.Color(color),
|
|
104
|
+
justification: 'center',
|
|
105
|
+
letterSpacing: 8,
|
|
106
|
+
})
|
|
107
|
+
if (opacity !== 1) bottomStar.opacity = opacity
|
|
108
|
+
items.push(bottomStar)
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
success: true,
|
|
112
|
+
type: 'seal',
|
|
113
|
+
items: items.map(i => i.id),
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* 创建五角星路径
|
|
119
|
+
*/
|
|
120
|
+
function createStarPath(cx, cy, outerR, innerR, points) {
|
|
121
|
+
const path = new paper.Path()
|
|
122
|
+
const angleStep = Math.PI / points
|
|
123
|
+
|
|
124
|
+
for (let i = 0; i < points * 2; i++) {
|
|
125
|
+
const r = i % 2 === 0 ? outerR : innerR
|
|
126
|
+
const angle = i * angleStep - Math.PI / 2
|
|
127
|
+
path.add(new paper.Point(cx + r * Math.cos(angle), cy + r * Math.sin(angle)))
|
|
128
|
+
}
|
|
129
|
+
path.closed = true
|
|
130
|
+
return path
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* 创建多边形路径
|
|
135
|
+
*/
|
|
136
|
+
function createPolygonPath(cx, cy, radius, sides) {
|
|
137
|
+
const path = new paper.Path()
|
|
138
|
+
for (let i = 0; i < sides; i++) {
|
|
139
|
+
const angle = (i * 2 * Math.PI / sides) - Math.PI / 2
|
|
140
|
+
path.add(new paper.Point(cx + radius * Math.cos(angle), cy + radius * Math.sin(angle)))
|
|
141
|
+
}
|
|
142
|
+
path.closed = true
|
|
143
|
+
return path
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
module.exports = createSeal
|
|
@@ -12,8 +12,8 @@ function createTable(project, canvas, params) {
|
|
|
12
12
|
x,
|
|
13
13
|
y,
|
|
14
14
|
width,
|
|
15
|
-
columns
|
|
16
|
-
rows
|
|
15
|
+
columns,
|
|
16
|
+
rows,
|
|
17
17
|
rowHeight = 36,
|
|
18
18
|
headerBg = '#f0f0f0',
|
|
19
19
|
headerColor = '#333333',
|
|
@@ -27,16 +27,24 @@ function createTable(project, canvas, params) {
|
|
|
27
27
|
|
|
28
28
|
const elements = []
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
// 确保 columns 是数组且不为空
|
|
31
|
+
if (!Array.isArray(columns) || columns.length === 0) {
|
|
31
32
|
return { success: true, elements, type: 'table' }
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
// 确保 rows 是数组
|
|
36
|
+
if (!Array.isArray(rows)) {
|
|
37
|
+
rows = []
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// 确保 width 有默认值
|
|
41
|
+
const tableWidth = width || 400
|
|
34
42
|
const totalHeight = rowHeight * (rows.length + 1)
|
|
35
43
|
|
|
36
44
|
// 绘制外边框
|
|
37
45
|
const outerBorder = new paper.Path.Rectangle({
|
|
38
46
|
point: [x, y],
|
|
39
|
-
size: [
|
|
47
|
+
size: [tableWidth, totalHeight]
|
|
40
48
|
})
|
|
41
49
|
outerBorder.fillColor = new paper.Color('transparent')
|
|
42
50
|
outerBorder.strokeColor = new paper.Color(borderColor)
|
|
@@ -49,7 +57,7 @@ function createTable(project, canvas, params) {
|
|
|
49
57
|
// 绘制表头背景
|
|
50
58
|
const headerBgRect = new paper.Path.Rectangle({
|
|
51
59
|
point: [x, y],
|
|
52
|
-
size: [
|
|
60
|
+
size: [tableWidth, rowHeight]
|
|
53
61
|
})
|
|
54
62
|
headerBgRect.fillColor = new paper.Color(headerBg)
|
|
55
63
|
headerBgRect.strokeColor = new paper.Color(borderColor)
|
|
@@ -62,7 +70,7 @@ function createTable(project, canvas, params) {
|
|
|
62
70
|
// 绘制表头
|
|
63
71
|
let currentX = x
|
|
64
72
|
columns.forEach((col, index) => {
|
|
65
|
-
const colWidth = col.width || (
|
|
73
|
+
const colWidth = col.width || (tableWidth / columns.length)
|
|
66
74
|
|
|
67
75
|
// 列分隔线
|
|
68
76
|
if (index > 0) {
|
|
@@ -103,7 +111,7 @@ function createTable(project, canvas, params) {
|
|
|
103
111
|
if (striped && rowIndex % 2 === 1) {
|
|
104
112
|
const stripeBg = new paper.Path.Rectangle({
|
|
105
113
|
point: [x, rowY],
|
|
106
|
-
size: [
|
|
114
|
+
size: [tableWidth, rowHeight]
|
|
107
115
|
})
|
|
108
116
|
stripeBg.fillColor = new paper.Color(stripeColor)
|
|
109
117
|
stripeBg.strokeColor = new paper.Color(borderColor)
|
|
@@ -129,7 +137,7 @@ function createTable(project, canvas, params) {
|
|
|
129
137
|
// 单元格
|
|
130
138
|
let cellX = x
|
|
131
139
|
columns.forEach((col, colIndex) => {
|
|
132
|
-
const colWidth = col.width || (
|
|
140
|
+
const colWidth = col.width || (tableWidth / columns.length)
|
|
133
141
|
const cellValue = row[colIndex] || ''
|
|
134
142
|
const cellText = new paper.PointText({
|
|
135
143
|
point: [cellX + colWidth / 2, rowY + rowHeight / 2 + fontSize / 3],
|
|
@@ -150,7 +158,7 @@ function createTable(project, canvas, params) {
|
|
|
150
158
|
return {
|
|
151
159
|
success: true,
|
|
152
160
|
elements,
|
|
153
|
-
width,
|
|
161
|
+
width: tableWidth,
|
|
154
162
|
height: totalHeight,
|
|
155
163
|
type: 'table'
|
|
156
164
|
}
|
|
@@ -6,21 +6,11 @@ const paper = require('paper')
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* 创建标签云
|
|
9
|
-
*
|
|
10
|
-
* @param {Object} project - Paper.js 项目
|
|
11
|
-
* @param {Object} canvas - 画布对象
|
|
12
|
-
* @param {Object} args - 组件参数
|
|
13
|
-
* @param {number} args.x - X坐标
|
|
14
|
-
* @param {number} args.y - Y坐标
|
|
15
|
-
* @param {Array} args.tags - 标签数组 [{text, color, bgColor}]
|
|
16
|
-
* @param {number} args.fontSize - 字体大小
|
|
17
|
-
* @param {number} args.padding - 标签内边距
|
|
18
|
-
* @param {number} args.gap - 标签间距
|
|
19
|
-
* @param {number} args.maxWidth - 最大宽度(自动换行)
|
|
20
9
|
*/
|
|
21
10
|
function createTagCloud(project, canvas, args) {
|
|
22
11
|
const {
|
|
23
|
-
x
|
|
12
|
+
x = 0,
|
|
13
|
+
y = 0,
|
|
24
14
|
tags = [],
|
|
25
15
|
fontSize = 14,
|
|
26
16
|
padding = 12,
|
|
@@ -29,12 +19,22 @@ function createTagCloud(project, canvas, args) {
|
|
|
29
19
|
} = args
|
|
30
20
|
|
|
31
21
|
const elements = []
|
|
22
|
+
|
|
23
|
+
// 确保 tags 是数组
|
|
24
|
+
if (!Array.isArray(tags) || tags.length === 0) {
|
|
25
|
+
return { success: true, elements, height: 0, type: 'tagCloud' }
|
|
26
|
+
}
|
|
27
|
+
|
|
32
28
|
let currentX = x
|
|
33
29
|
let currentY = y
|
|
34
30
|
let rowHeight = 0
|
|
35
31
|
|
|
36
32
|
for (const tag of tags) {
|
|
37
|
-
|
|
33
|
+
// 确保 tag.text 是字符串
|
|
34
|
+
const tagText = String(tag.text || '')
|
|
35
|
+
if (!tagText) continue
|
|
36
|
+
|
|
37
|
+
const textWidth = tagText.length * fontSize * 0.6
|
|
38
38
|
const tagWidth = textWidth + padding * 2
|
|
39
39
|
const tagHeight = fontSize + padding * 2
|
|
40
40
|
|
|
@@ -52,17 +52,23 @@ function createTagCloud(project, canvas, args) {
|
|
|
52
52
|
radius: tagHeight / 2,
|
|
53
53
|
})
|
|
54
54
|
tagBg.fillColor = new paper.Color(tag.bgColor || '#e0e7ff')
|
|
55
|
+
if (project && project.activeLayer) {
|
|
56
|
+
project.activeLayer.addChild(tagBg)
|
|
57
|
+
}
|
|
55
58
|
elements.push({ type: 'rectangle', id: tagBg.id })
|
|
56
59
|
|
|
57
60
|
// 绘制标签文字
|
|
58
|
-
const
|
|
61
|
+
const tagTextEl = new paper.PointText({
|
|
59
62
|
point: [currentX + tagWidth / 2, currentY + tagHeight / 2 + fontSize / 3],
|
|
60
|
-
content:
|
|
63
|
+
content: tagText,
|
|
61
64
|
fontSize: fontSize,
|
|
62
65
|
fillColor: new paper.Color(tag.color || '#4338ca'),
|
|
63
66
|
justification: 'center',
|
|
64
67
|
})
|
|
65
|
-
|
|
68
|
+
if (project && project.activeLayer) {
|
|
69
|
+
project.activeLayer.addChild(tagTextEl)
|
|
70
|
+
}
|
|
71
|
+
elements.push({ type: 'text', id: tagTextEl.id })
|
|
66
72
|
|
|
67
73
|
currentX += tagWidth + gap
|
|
68
74
|
rowHeight = Math.max(rowHeight, tagHeight)
|
|
@@ -71,7 +77,8 @@ function createTagCloud(project, canvas, args) {
|
|
|
71
77
|
return {
|
|
72
78
|
success: true,
|
|
73
79
|
elements,
|
|
74
|
-
height: rowHeight,
|
|
80
|
+
height: currentY - y + rowHeight,
|
|
81
|
+
type: 'tagCloud',
|
|
75
82
|
}
|
|
76
83
|
}
|
|
77
84
|
|
|
@@ -6,18 +6,6 @@ const paper = require('paper')
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* 创建时间线
|
|
9
|
-
*
|
|
10
|
-
* @param {Object} project - Paper.js 项目
|
|
11
|
-
* @param {Object} canvas - 画布对象
|
|
12
|
-
* @param {Object} args - 组件参数
|
|
13
|
-
* @param {number} args.x - X坐标
|
|
14
|
-
* @param {number} args.y - Y坐标
|
|
15
|
-
* @param {number} args.width - 总宽度
|
|
16
|
-
* @param {Array} args.items - 时间线项目 [{date, title, description}]
|
|
17
|
-
* @param {string} args.lineColor - 线条颜色
|
|
18
|
-
* @param {string} args.dotColor - 点颜色
|
|
19
|
-
* @param {string} args.activeColor - 激活颜色
|
|
20
|
-
* @param {number} args.dotSize - 点大小
|
|
21
9
|
*/
|
|
22
10
|
function createTimeline(project, canvas, args) {
|
|
23
11
|
const {
|
|
@@ -32,6 +20,12 @@ function createTimeline(project, canvas, args) {
|
|
|
32
20
|
} = args
|
|
33
21
|
|
|
34
22
|
const elements = []
|
|
23
|
+
|
|
24
|
+
// 确保 items 是数组
|
|
25
|
+
if (!Array.isArray(items) || items.length === 0) {
|
|
26
|
+
return { success: true, elements, height: 0, type: 'timeline' }
|
|
27
|
+
}
|
|
28
|
+
|
|
35
29
|
const centerX = x + 80
|
|
36
30
|
const contentX = x + 120
|
|
37
31
|
|
|
@@ -43,12 +37,17 @@ function createTimeline(project, canvas, args) {
|
|
|
43
37
|
strokeColor: new paper.Color(lineColor),
|
|
44
38
|
strokeWidth: 2,
|
|
45
39
|
})
|
|
40
|
+
if (project && project.activeLayer) {
|
|
41
|
+
project.activeLayer.addChild(mainLine)
|
|
42
|
+
}
|
|
46
43
|
elements.push({ type: 'line', id: mainLine.id })
|
|
47
44
|
}
|
|
48
45
|
|
|
49
46
|
// 绘制每个项目
|
|
50
47
|
for (let i = 0; i < items.length; i++) {
|
|
51
48
|
const item = items[i]
|
|
49
|
+
if (!item) continue
|
|
50
|
+
|
|
52
51
|
const itemY = y + i * gap
|
|
53
52
|
const isActive = item.active !== false
|
|
54
53
|
|
|
@@ -58,6 +57,9 @@ function createTimeline(project, canvas, args) {
|
|
|
58
57
|
radius: dotSize / 2,
|
|
59
58
|
})
|
|
60
59
|
dot.fillColor = new paper.Color(isActive ? dotColor : lineColor)
|
|
60
|
+
if (project && project.activeLayer) {
|
|
61
|
+
project.activeLayer.addChild(dot)
|
|
62
|
+
}
|
|
61
63
|
elements.push({ type: 'circle', id: dot.id })
|
|
62
64
|
|
|
63
65
|
// 绘制日期
|
|
@@ -69,6 +71,9 @@ function createTimeline(project, canvas, args) {
|
|
|
69
71
|
fillColor: new paper.Color('#94a3b8'),
|
|
70
72
|
justification: 'left',
|
|
71
73
|
})
|
|
74
|
+
if (project && project.activeLayer) {
|
|
75
|
+
project.activeLayer.addChild(dateText)
|
|
76
|
+
}
|
|
72
77
|
elements.push({ type: 'text', id: dateText.id })
|
|
73
78
|
}
|
|
74
79
|
|
|
@@ -80,6 +85,9 @@ function createTimeline(project, canvas, args) {
|
|
|
80
85
|
fillColor: new paper.Color(isActive ? '#1e293b' : '#94a3b8'),
|
|
81
86
|
justification: 'left',
|
|
82
87
|
})
|
|
88
|
+
if (project && project.activeLayer) {
|
|
89
|
+
project.activeLayer.addChild(titleText)
|
|
90
|
+
}
|
|
83
91
|
elements.push({ type: 'text', id: titleText.id })
|
|
84
92
|
|
|
85
93
|
// 绘制描述
|
|
@@ -91,6 +99,9 @@ function createTimeline(project, canvas, args) {
|
|
|
91
99
|
fillColor: new paper.Color('#64748b'),
|
|
92
100
|
justification: 'left',
|
|
93
101
|
})
|
|
102
|
+
if (project && project.activeLayer) {
|
|
103
|
+
project.activeLayer.addChild(descText)
|
|
104
|
+
}
|
|
94
105
|
elements.push({ type: 'text', id: descText.id })
|
|
95
106
|
}
|
|
96
107
|
}
|
|
@@ -99,6 +110,7 @@ function createTimeline(project, canvas, args) {
|
|
|
99
110
|
success: true,
|
|
100
111
|
elements,
|
|
101
112
|
height: items.length * gap,
|
|
113
|
+
type: 'timeline',
|
|
102
114
|
}
|
|
103
115
|
}
|
|
104
116
|
|