import 'package:flutter/material.dart'; import 'dart:ui' as ui; import '../../../common/models/index.dart'; import '../../../common/utils/index.dart'; class SelectNode { final NodePaintElement node; final RRectPaintElement selectRect; SelectNode(this.node, this.selectRect); } /// /// 网络图片异步加载 /// typedef RefreshImage = Function(String, String); class MindMapPainter extends CustomPainter { final LinePaintElement? linePaintElement; final NodePaintElement root ; final RRectPaintElement? selectRect; final Map mindMapImages; final Map priorityImages; final Map progressImages; final ui.Image? linkIconImage; ui.Paint myPaint = ui.Paint(); MindMapPainter({ required this.root, required this.linePaintElement, required this.selectRect, required this.priorityImages, required this.progressImages, required this.linkIconImage, required this.mindMapImages }); @override void paint(Canvas canvas, Size size) { paintNodeInner(canvas, root); paintLines(canvas); if (selectRect != null) { myPaint.style = selectRect!.style.style; myPaint.color = selectRect!.style.color; myPaint.strokeWidth = selectRect!.style.strokeWidth; canvas.drawRRect(selectRect!.rrect, myPaint); } } /// /// 画节点内部元素 /// void paintNodeInner(Canvas canvas, NodePaintElement node) { final elements = node.paintElements; // 背景 if(elements.containsKey(NodeElement.background)) { RRectPaintElement? back = elements[NodeElement.background] as RRectPaintElement?; if (back != null) { myPaint.style = back.style.style; myPaint.color = back.style.color; canvas.drawRRect(back.rrect, myPaint); } } if(elements.containsKey(NodeElement.border)) { RRectPaintElement? border = elements[NodeElement.border] as RRectPaintElement?; if (border != null) { myPaint.style = border.style.style; myPaint.color = border.style.color; myPaint.strokeWidth = border.style.strokeWidth; canvas.drawRRect(border.rrect, myPaint); } } // 画图片 if(elements.containsKey(NodeElement.image)) { ImagePaintElement? imagePaint = elements[NodeElement.image] as ImagePaintElement?; if (imagePaint != null) { var url = node.data.image; if (node.data.imageId != null && node.data.imageId != 'null' && node.data.imageId?.isNotEmpty == true) { url = O2ApiManager.instance.getFileURL(node.data.imageId!); } if(url != null && url.isNotEmpty && mindMapImages.containsKey(url)) { final image = mindMapImages[url]; myPaint.style = imagePaint .style.style; myPaint.color = imagePaint.style.color; // print('paint image ,url:$url'); canvas.drawImageRect( image!, Rect.fromLTWH(0.0, 0.0, image.width.toDouble(), image.height.toDouble()), imagePaint.rect, myPaint); } } } // 优先级 if(elements.containsKey(NodeElement.priority)) { ImagePaintElement? image = elements[NodeElement.priority] as ImagePaintElement?; if (image != null) { myPaint.style = image.style.style; myPaint.color = image.style.color; var iconImage = priorityImages[node.data.priority]; canvas.drawImageRect( iconImage!, Rect.fromLTWH(0.0, 0.0, iconImage.width.toDouble(), iconImage.height.toDouble()), image.rect, myPaint); } } // 进度 if(elements.containsKey(NodeElement.progress)) { ImagePaintElement? image = elements[NodeElement.progress] as ImagePaintElement?; if (image != null) { myPaint.style = image.style.style; myPaint.color = image.style.color; var iconImage = progressImages[node.data.progress]; canvas.drawImageRect( iconImage!, Rect.fromLTWH(0.0, 0.0, iconImage.width.toDouble(), iconImage.height.toDouble()), image.rect, myPaint); } } // 文字 TextPaintElement? text = elements[NodeElement.text] as TextPaintElement?; if (text != null) { text.painter.paint(canvas, text.offset!); } // 超链接 if(elements.containsKey(NodeElement.hyperlink)) { ImagePaintElement? image = elements[NodeElement.hyperlink] as ImagePaintElement?; if (image != null && linkIconImage != null) { myPaint.style = image.style.style; myPaint.color = image.style.color; canvas.drawImageRect( linkIconImage!, Rect.fromLTWH(0.0, 0.0, linkIconImage!.width.toDouble(), linkIconImage!.height.toDouble()), image.rect, myPaint); } } if(node.children!=null && node.children?.isNotEmpty == true) { for(var i=0;i turnPoint.dy ? 0.5 * pi : -0.5 * pi; // final Path path = Path() // ..moveTo(line.start.dx, line.start.dy) // ..lineTo(bifurcationPoint.dx, bifurcationPoint.dy) // ..lineTo(turnPoint.dx, turnPoint.dy) // ..addArc(rect, startAngle, sweepAngle) // ..lineTo(line.end.dx, line.end.dy); //// ..quadraticBezierTo(bezierControlX, bezierControlY, line.end.dx, line.end.dy); // canvas.drawPath(path, myPaint); canvas.drawLine(line.start, bifurcationPoint, myPaint); canvas.drawLine(bifurcationPoint, turnPoint, myPaint); canvas.drawLine(turnPoint, line.end, myPaint); } } } @override bool shouldRepaint(CustomPainter oldDelegate) { // if(oldDelegate is MindMapPainter) { // // todo 这里有问题 每次oldDelegate里面的数据都没有变化 // final thisMap = json.encode(this.root.toJson()); // final oldMap = json.encode(oldDelegate.root.toJson()); // final check = checkIsImageCacheChanged(oldDelegate.mindMapImages); // print('check:$check , size:${this.mindMapImages.length} , old:${oldDelegate.mindMapImages.length}'); // if(thisMap == oldMap // && this.selectRect == oldDelegate.selectRect // && !check // && !checkLinesChanged(oldDelegate.linePaintElement)) { // return false; // } // } return this != oldDelegate; } /// /// 图片资源是否有变化 /// bool checkIsImageCacheChanged(Map oldMap) { if (mindMapImages.length != oldMap.length) { return true; } for(var url in mindMapImages.keys) { bool isInOldMap = false; for(var oldUrl in oldMap.keys) { if (url == oldUrl) { isInOldMap = true; } } if (!isInOldMap) { return true; } } return false; } bool checkLinesChanged(LinePaintElement oldlinePaint) { if(linePaintElement?.lines.length != oldlinePaint.lines.length) { return true; } if(linePaintElement?.style.style != oldlinePaint.style.style || linePaintElement?.style.color != oldlinePaint.style.color || linePaintElement?.style.strokeWidth != oldlinePaint.style.strokeWidth) { return true; } var list = linePaintElement?.lines ?? []; var oldlist = oldlinePaint.lines; for(var line in list) { bool isInOld = false; for(var oldline in oldlist) { if(line.start == oldline.start && line.end == oldline.end) { isInOld = true; } } if(!isInOld) { return true; } } return false; } }