提交 | 用户 | 时间
|
722af2
|
1 |
package com.dl.flowable.flow; |
X |
2 |
|
|
3 |
import org.flowable.bpmn.model.AssociationDirection; |
|
4 |
import org.flowable.bpmn.model.GraphicInfo; |
|
5 |
import org.flowable.image.impl.DefaultProcessDiagramCanvas; |
|
6 |
import org.flowable.image.util.ReflectUtil; |
|
7 |
|
|
8 |
import javax.imageio.ImageIO; |
|
9 |
import java.awt.*; |
|
10 |
import java.awt.font.FontRenderContext; |
|
11 |
import java.awt.font.LineBreakMeasurer; |
|
12 |
import java.awt.font.TextAttribute; |
|
13 |
import java.awt.font.TextLayout; |
|
14 |
import java.awt.geom.Ellipse2D; |
|
15 |
import java.awt.geom.Rectangle2D; |
|
16 |
import java.awt.geom.RoundRectangle2D; |
|
17 |
import java.awt.image.BufferedImage; |
|
18 |
import java.io.IOException; |
|
19 |
import java.text.AttributedCharacterIterator; |
|
20 |
import java.text.AttributedString; |
|
21 |
|
|
22 |
/** |
|
23 |
* @author XuanXuan |
|
24 |
* @date 2021/4/4 23:58 |
|
25 |
*/ |
|
26 |
public class CustomProcessDiagramCanvas extends DefaultProcessDiagramCanvas { |
|
27 |
//定义走过流程连线颜色为绿色 |
|
28 |
protected static Color HIGHLIGHT_SequenceFlow_COLOR = Color.GREEN; |
|
29 |
//设置未走过流程的连接线颜色 |
|
30 |
protected static Color CONNECTION_COLOR = Color.BLACK; |
|
31 |
//设置flows连接线字体颜色red |
|
32 |
protected static Color LABEL_COLOR = new Color(0, 0, 0); |
|
33 |
//高亮显示task框颜色 |
|
34 |
protected static Color HIGHLIGHT_COLOR = Color.GREEN; |
|
35 |
protected static Color HIGHLIGHT_COLOR1 = Color.RED; |
|
36 |
|
|
37 |
public CustomProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) { |
|
38 |
super(width, height, minX, minY, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader); |
|
39 |
this.initialize(imageType); |
|
40 |
} |
|
41 |
|
|
42 |
/** |
|
43 |
* 重写绘制连线的方式,设置绘制颜色 |
|
44 |
* @param xPoints |
|
45 |
* @param yPoints |
|
46 |
* @param conditional |
|
47 |
* @param isDefault |
|
48 |
* @param connectionType |
|
49 |
* @param associationDirection |
|
50 |
* @param highLighted |
|
51 |
* @param scaleFactor |
|
52 |
*/ |
|
53 |
@Override |
|
54 |
public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, String connectionType, AssociationDirection associationDirection, boolean highLighted, double scaleFactor) { |
|
55 |
Paint originalPaint = this.g.getPaint(); |
|
56 |
Stroke originalStroke = this.g.getStroke(); |
|
57 |
this.g.setPaint(CONNECTION_COLOR); |
|
58 |
if (connectionType.equals("association")) { |
|
59 |
this.g.setStroke(ASSOCIATION_STROKE); |
|
60 |
} else if (highLighted) { |
|
61 |
this.g.setPaint(HIGHLIGHT_SequenceFlow_COLOR); |
|
62 |
this.g.setStroke(HIGHLIGHT_FLOW_STROKE); |
|
63 |
} |
|
64 |
|
|
65 |
for (int i = 1; i < xPoints.length; ++i) { |
|
66 |
int sourceX = xPoints[i - 1]; |
|
67 |
int sourceY = yPoints[i - 1]; |
|
68 |
int targetX = xPoints[i]; |
|
69 |
int targetY = yPoints[i]; |
|
70 |
java.awt.geom.Line2D.Double line = new java.awt.geom.Line2D.Double((double) sourceX, (double) sourceY, (double) targetX, (double) targetY); |
|
71 |
this.g.draw(line); |
|
72 |
} |
|
73 |
|
|
74 |
java.awt.geom.Line2D.Double line; |
|
75 |
if (isDefault) { |
|
76 |
line = new java.awt.geom.Line2D.Double((double) xPoints[0], (double) yPoints[0], (double) xPoints[1], (double) yPoints[1]); |
|
77 |
this.drawDefaultSequenceFlowIndicator(line, scaleFactor); |
|
78 |
} |
|
79 |
|
|
80 |
if (conditional) { |
|
81 |
line = new java.awt.geom.Line2D.Double((double) xPoints[0], (double) yPoints[0], (double) xPoints[1], (double) yPoints[1]); |
|
82 |
this.drawConditionalSequenceFlowIndicator(line, scaleFactor); |
|
83 |
} |
|
84 |
|
|
85 |
if (associationDirection.equals(AssociationDirection.ONE) || associationDirection.equals(AssociationDirection.BOTH)) { |
|
86 |
line = new java.awt.geom.Line2D.Double((double) xPoints[xPoints.length - 2], (double) yPoints[xPoints.length - 2], (double) xPoints[xPoints.length - 1], (double) yPoints[xPoints.length - 1]); |
|
87 |
this.drawArrowHead(line, scaleFactor); |
|
88 |
} |
|
89 |
|
|
90 |
if (associationDirection.equals(AssociationDirection.BOTH)) { |
|
91 |
line = new java.awt.geom.Line2D.Double((double) xPoints[1], (double) yPoints[1], (double) xPoints[0], (double) yPoints[0]); |
|
92 |
this.drawArrowHead(line, scaleFactor); |
|
93 |
} |
|
94 |
|
|
95 |
this.g.setPaint(originalPaint); |
|
96 |
this.g.setStroke(originalStroke); |
|
97 |
} |
|
98 |
|
|
99 |
/** |
|
100 |
* 设置字体大小图标颜色 |
|
101 |
* @param imageType |
|
102 |
*/ |
|
103 |
@Override |
|
104 |
public void initialize(String imageType) { |
|
105 |
if ("png".equalsIgnoreCase(imageType)) { |
|
106 |
this.processDiagram = new BufferedImage(this.canvasWidth, this.canvasHeight, 2); |
|
107 |
} else { |
|
108 |
this.processDiagram = new BufferedImage(this.canvasWidth, this.canvasHeight, 1); |
|
109 |
} |
|
110 |
|
|
111 |
this.g = this.processDiagram.createGraphics(); |
|
112 |
if (!"png".equalsIgnoreCase(imageType)) { |
|
113 |
this.g.setBackground(new Color(255, 255, 255, 0)); |
|
114 |
this.g.clearRect(0, 0, this.canvasWidth, this.canvasHeight); |
|
115 |
} |
|
116 |
|
|
117 |
this.g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); |
|
118 |
//修改图标颜色,修改图标字体大小 |
|
119 |
this.g.setPaint(Color.black); |
|
120 |
Font font = new Font(this.activityFontName, 10, 14); |
|
121 |
this.g.setFont(font); |
|
122 |
this.fontMetrics = this.g.getFontMetrics(); |
|
123 |
//修改连接线字体大小 |
|
124 |
LABEL_FONT = new Font(this.labelFontName, 10, 15); |
|
125 |
ANNOTATION_FONT = new Font(this.annotationFontName, 0, 11); |
|
126 |
|
|
127 |
try { |
|
128 |
USERTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/userTask.png", this.customClassLoader)); |
|
129 |
SCRIPTTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/scriptTask.png", this.customClassLoader)); |
|
130 |
SERVICETASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/serviceTask.png", this.customClassLoader)); |
|
131 |
RECEIVETASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/receiveTask.png", this.customClassLoader)); |
|
132 |
SENDTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/sendTask.png", this.customClassLoader)); |
|
133 |
MANUALTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/manualTask.png", this.customClassLoader)); |
|
134 |
BUSINESS_RULE_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/businessRuleTask.png", this.customClassLoader)); |
|
135 |
SHELL_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/shellTask.png", this.customClassLoader)); |
|
136 |
DMN_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/dmnTask.png", this.customClassLoader)); |
|
137 |
CAMEL_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/camelTask.png", this.customClassLoader)); |
|
138 |
MULE_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/muleTask.png", this.customClassLoader)); |
|
139 |
HTTP_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/httpTask.png", this.customClassLoader)); |
|
140 |
TIMER_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/timer.png", this.customClassLoader)); |
|
141 |
COMPENSATE_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/compensate-throw.png", this.customClassLoader)); |
|
142 |
COMPENSATE_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/compensate.png", this.customClassLoader)); |
|
143 |
ERROR_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/error-throw.png", this.customClassLoader)); |
|
144 |
ERROR_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/error.png", this.customClassLoader)); |
|
145 |
MESSAGE_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/message-throw.png", this.customClassLoader)); |
|
146 |
MESSAGE_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/message.png", this.customClassLoader)); |
|
147 |
SIGNAL_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/signal-throw.png", this.customClassLoader)); |
|
148 |
SIGNAL_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/signal.png", this.customClassLoader)); |
|
149 |
} catch (IOException var4) { |
|
150 |
LOGGER.warn("Could not load image for process diagram creation: {}", var4.getMessage()); |
|
151 |
} |
|
152 |
|
|
153 |
} |
|
154 |
|
|
155 |
/** |
|
156 |
* 设置连接线字体 |
|
157 |
* @param text |
|
158 |
* @param graphicInfo |
|
159 |
* @param centered |
|
160 |
*/ |
|
161 |
@Override |
|
162 |
public void drawLabel(String text, GraphicInfo graphicInfo, boolean centered) { |
|
163 |
float interline = 1.0f; |
|
164 |
|
|
165 |
// text |
|
166 |
if (text != null && text.length() > 0) { |
|
167 |
Paint originalPaint = g.getPaint(); |
|
168 |
Font originalFont = g.getFont(); |
|
169 |
|
|
170 |
g.setPaint(LABEL_COLOR); |
|
171 |
g.setFont(LABEL_FONT); |
|
172 |
|
|
173 |
int wrapWidth = 100; |
|
174 |
int textY = (int) graphicInfo.getY(); |
|
175 |
|
|
176 |
// TODO: use drawMultilineText() |
|
177 |
AttributedString as = new AttributedString(text); |
|
178 |
as.addAttribute(TextAttribute.FOREGROUND, g.getPaint()); |
|
179 |
as.addAttribute(TextAttribute.FONT, g.getFont()); |
|
180 |
AttributedCharacterIterator aci = as.getIterator(); |
|
181 |
FontRenderContext frc = new FontRenderContext(null, true, false); |
|
182 |
LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc); |
|
183 |
|
|
184 |
while (lbm.getPosition() < text.length()) { |
|
185 |
TextLayout tl = lbm.nextLayout(wrapWidth); |
|
186 |
textY += tl.getAscent(); |
|
187 |
|
|
188 |
Rectangle2D bb = tl.getBounds(); |
|
189 |
double tX = graphicInfo.getX(); |
|
190 |
|
|
191 |
if (centered) { |
|
192 |
tX += (int) (graphicInfo.getWidth() / 2 - bb.getWidth() / 2); |
|
193 |
} |
|
194 |
tl.draw(g, (float) tX, textY); |
|
195 |
textY += tl.getDescent() + tl.getLeading() + (interline - 1.0f) * tl.getAscent(); |
|
196 |
} |
|
197 |
|
|
198 |
// restore originals |
|
199 |
g.setFont(originalFont); |
|
200 |
g.setPaint(originalPaint); |
|
201 |
} |
|
202 |
} |
|
203 |
|
|
204 |
/** |
|
205 |
* 高亮显示task框完成的 |
|
206 |
* @param x |
|
207 |
* @param y |
|
208 |
* @param width |
|
209 |
* @param height |
|
210 |
*/ |
|
211 |
@Override |
|
212 |
public void drawHighLight(int x, int y, int width, int height) { |
|
213 |
Paint originalPaint = g.getPaint(); |
|
214 |
Stroke originalStroke = g.getStroke(); |
|
215 |
|
|
216 |
g.setPaint(HIGHLIGHT_COLOR); |
|
217 |
g.setStroke(THICK_TASK_BORDER_STROKE); |
|
218 |
|
|
219 |
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20); |
|
220 |
g.draw(rect); |
|
221 |
|
|
222 |
g.setPaint(originalPaint); |
|
223 |
g.setStroke(originalStroke); |
|
224 |
} |
|
225 |
|
|
226 |
/** |
|
227 |
* 自定义task框当前的位置 |
|
228 |
* @param x |
|
229 |
* @param y |
|
230 |
* @param width |
|
231 |
* @param height |
|
232 |
*/ |
|
233 |
public void drawHighLightNow(int x, int y, int width, int height) { |
|
234 |
Paint originalPaint = g.getPaint(); |
|
235 |
Stroke originalStroke = g.getStroke(); |
|
236 |
|
|
237 |
g.setPaint(HIGHLIGHT_COLOR1); |
|
238 |
g.setStroke(THICK_TASK_BORDER_STROKE); |
|
239 |
|
|
240 |
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20); |
|
241 |
g.draw(rect); |
|
242 |
|
|
243 |
g.setPaint(originalPaint); |
|
244 |
g.setStroke(originalStroke); |
|
245 |
} |
|
246 |
|
|
247 |
/** |
|
248 |
* 自定义结束节点 |
|
249 |
* @param x |
|
250 |
* @param y |
|
251 |
* @param width |
|
252 |
* @param height |
|
253 |
*/ |
|
254 |
public void drawHighLightEnd(int x, int y, int width, int height) { |
|
255 |
Paint originalPaint = g.getPaint(); |
|
256 |
Stroke originalStroke = g.getStroke(); |
|
257 |
|
|
258 |
g.setPaint(HIGHLIGHT_COLOR); |
|
259 |
g.setStroke(THICK_TASK_BORDER_STROKE); |
|
260 |
|
|
261 |
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20); |
|
262 |
g.draw(rect); |
|
263 |
|
|
264 |
g.setPaint(originalPaint); |
|
265 |
g.setStroke(originalStroke); |
|
266 |
} |
|
267 |
|
|
268 |
/** |
|
269 |
* task框自定义文字 |
|
270 |
* @param name |
|
271 |
* @param graphicInfo |
|
272 |
* @param thickBorder |
|
273 |
* @param scaleFactor |
|
274 |
*/ |
|
275 |
@Override |
|
276 |
protected void drawTask(String name, GraphicInfo graphicInfo, boolean thickBorder, double scaleFactor) { |
|
277 |
|
|
278 |
Paint originalPaint = g.getPaint(); |
|
279 |
int x = (int) graphicInfo.getX(); |
|
280 |
int y = (int) graphicInfo.getY(); |
|
281 |
int width = (int) graphicInfo.getWidth(); |
|
282 |
int height = (int) graphicInfo.getHeight(); |
|
283 |
|
|
284 |
// Create a new gradient paint for every task box, gradient depends on x and y and is not relative |
|
285 |
g.setPaint(TASK_BOX_COLOR); |
|
286 |
|
|
287 |
int arcR = 6; |
|
288 |
if (thickBorder) { |
|
289 |
arcR = 3; |
|
290 |
} |
|
291 |
|
|
292 |
// shape |
|
293 |
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, arcR, arcR); |
|
294 |
g.fill(rect); |
|
295 |
g.setPaint(TASK_BORDER_COLOR); |
|
296 |
|
|
297 |
if (thickBorder) { |
|
298 |
Stroke originalStroke = g.getStroke(); |
|
299 |
g.setStroke(THICK_TASK_BORDER_STROKE); |
|
300 |
g.draw(rect); |
|
301 |
g.setStroke(originalStroke); |
|
302 |
} else { |
|
303 |
g.draw(rect); |
|
304 |
} |
|
305 |
|
|
306 |
g.setPaint(originalPaint); |
|
307 |
// text |
|
308 |
if (scaleFactor == 1.0 && name != null && name.length() > 0) { |
|
309 |
int boxWidth = width - (2 * TEXT_PADDING); |
|
310 |
int boxHeight = height - 16 - ICON_PADDING - ICON_PADDING - MARKER_WIDTH - 2 - 2; |
|
311 |
int boxX = x + width / 2 - boxWidth / 2; |
|
312 |
int boxY = y + height / 2 - boxHeight / 2 + ICON_PADDING + ICON_PADDING - 2 - 2; |
|
313 |
|
|
314 |
drawMultilineCentredText(name, boxX, boxY, boxWidth, boxHeight); |
|
315 |
} |
|
316 |
} |
|
317 |
|
|
318 |
protected static Color EVENT_COLOR = new Color(255, 255, 255); |
|
319 |
|
|
320 |
/** |
|
321 |
* 重写开始事件 |
|
322 |
* @param graphicInfo |
|
323 |
* @param image |
|
324 |
* @param scaleFactor |
|
325 |
*/ |
|
326 |
@Override |
|
327 |
public void drawStartEvent(GraphicInfo graphicInfo, BufferedImage image, double scaleFactor) { |
|
328 |
Paint originalPaint = g.getPaint(); |
|
329 |
g.setPaint(EVENT_COLOR); |
|
330 |
Ellipse2D circle = new Ellipse2D.Double(graphicInfo.getX(), graphicInfo.getY(), |
|
331 |
graphicInfo.getWidth(), graphicInfo.getHeight()); |
|
332 |
g.fill(circle); |
|
333 |
g.setPaint(EVENT_BORDER_COLOR); |
|
334 |
g.draw(circle); |
|
335 |
g.setPaint(originalPaint); |
|
336 |
if (image != null) { |
|
337 |
// calculate coordinates to center image |
|
338 |
int imageX = (int) Math.round(graphicInfo.getX() + (graphicInfo.getWidth() / 2) - (image.getWidth() / (2 * scaleFactor))); |
|
339 |
int imageY = (int) Math.round(graphicInfo.getY() + (graphicInfo.getHeight() / 2) - (image.getHeight() / (2 * scaleFactor))); |
|
340 |
g.drawImage(image, imageX, imageY, |
|
341 |
(int) (image.getWidth() / scaleFactor), (int) (image.getHeight() / scaleFactor), null); |
|
342 |
} |
|
343 |
|
|
344 |
} |
|
345 |
|
|
346 |
/** |
|
347 |
* 重写结束事件 |
|
348 |
* @param graphicInfo |
|
349 |
* @param scaleFactor |
|
350 |
*/ |
|
351 |
@Override |
|
352 |
public void drawNoneEndEvent(GraphicInfo graphicInfo, double scaleFactor) { |
|
353 |
Paint originalPaint = g.getPaint(); |
|
354 |
Stroke originalStroke = g.getStroke(); |
|
355 |
g.setPaint(EVENT_COLOR); |
|
356 |
Ellipse2D circle = new Ellipse2D.Double(graphicInfo.getX(), graphicInfo.getY(), |
|
357 |
graphicInfo.getWidth(), graphicInfo.getHeight()); |
|
358 |
g.fill(circle); |
|
359 |
g.setPaint(EVENT_BORDER_COLOR); |
|
360 |
// g.setPaint(HIGHLIGHT_COLOR); |
|
361 |
if (scaleFactor == 1.0) { |
|
362 |
g.setStroke(END_EVENT_STROKE); |
|
363 |
} else { |
|
364 |
g.setStroke(new BasicStroke(2.0f)); |
|
365 |
} |
|
366 |
g.draw(circle); |
|
367 |
g.setStroke(originalStroke); |
|
368 |
g.setPaint(originalPaint); |
|
369 |
} |
|
370 |
} |