|
|
@@ -139,6 +139,7 @@ export default {
|
|
|
displayName: displayName,
|
|
|
isSelf: isSelf,
|
|
|
memberType: m.memberType || 'child',
|
|
|
+ relationshipType: m.relationshipType || '',
|
|
|
radius: radius,
|
|
|
x: initX,
|
|
|
y: initY,
|
|
|
@@ -380,18 +381,45 @@ export default {
|
|
|
for (var i = 0; i < nodes.length; i++) {
|
|
|
var node = nodes[i]
|
|
|
var r = node.radius
|
|
|
- ctx.beginPath()
|
|
|
- ctx.arc(node.x, node.y, r, 0, 2 * Math.PI)
|
|
|
+
|
|
|
if (node.isSelf) {
|
|
|
+ // 自我:双层圆环
|
|
|
+ ctx.beginPath()
|
|
|
+ ctx.arc(node.x, node.y, r, 0, 2 * Math.PI)
|
|
|
ctx.fillStyle = '#FFFFFF'
|
|
|
ctx.fill()
|
|
|
ctx.strokeStyle = this.themeColor
|
|
|
ctx.lineWidth = 3
|
|
|
ctx.stroke()
|
|
|
+ // 内环
|
|
|
+ ctx.beginPath()
|
|
|
+ ctx.arc(node.x, node.y, r * 0.7, 0, 2 * Math.PI)
|
|
|
+ ctx.strokeStyle = this.themeColor + '88'
|
|
|
+ ctx.lineWidth = 2
|
|
|
+ ctx.stroke()
|
|
|
+ } else if (node.relationshipType === 'spouse') {
|
|
|
+ // 配偶:心形
|
|
|
+ this.drawHeart(ctx, node.x, node.y, r)
|
|
|
+ ctx.fillStyle = this.themeColor + '22'
|
|
|
+ ctx.fill()
|
|
|
+ } else if (node.relationshipType === 'parent') {
|
|
|
+ // 父母:圆角方形
|
|
|
+ this.drawRoundedRect(ctx, node.x, node.y, r * 2, r * 2, r * 0.3)
|
|
|
+ ctx.fillStyle = this.themeColor + '22'
|
|
|
+ ctx.fill()
|
|
|
+ } else if (node.relationshipType === 'sibling') {
|
|
|
+ // 兄弟姐妹:八边形
|
|
|
+ this.drawPolygon(ctx, node.x, node.y, r, 8)
|
|
|
+ ctx.fillStyle = this.themeColor + '22'
|
|
|
+ ctx.fill()
|
|
|
} else {
|
|
|
+ // 孩子/默认:圆形
|
|
|
+ ctx.beginPath()
|
|
|
+ ctx.arc(node.x, node.y, r, 0, 2 * Math.PI)
|
|
|
ctx.fillStyle = this.themeColor + '22'
|
|
|
ctx.fill()
|
|
|
}
|
|
|
+
|
|
|
ctx.fillStyle = node.isSelf ? this.themeColor : '#4A5568'
|
|
|
ctx.font = 'bold ' + (r * 0.9) + 'px sans-serif'
|
|
|
ctx.textAlign = 'center'
|
|
|
@@ -424,18 +452,40 @@ export default {
|
|
|
for (var j = 0; j < nodes.length; j++) {
|
|
|
var node = nodes[j]
|
|
|
var r = node.radius
|
|
|
- ctx.beginPath()
|
|
|
- ctx.arc(node.x, node.y, r, 0, 2 * Math.PI)
|
|
|
+
|
|
|
if (node.isSelf) {
|
|
|
+ ctx.beginPath()
|
|
|
+ ctx.arc(node.x, node.y, r, 0, 2 * Math.PI)
|
|
|
ctx.setFillStyle('#FFFFFF')
|
|
|
ctx.fill()
|
|
|
ctx.setStrokeStyle(this.themeColor)
|
|
|
ctx.setLineWidth(3)
|
|
|
ctx.stroke()
|
|
|
+ // inner ring
|
|
|
+ ctx.beginPath()
|
|
|
+ ctx.arc(node.x, node.y, r * 0.7, 0, 2 * Math.PI)
|
|
|
+ ctx.setStrokeStyle(this.themeColor + '88')
|
|
|
+ ctx.setLineWidth(2)
|
|
|
+ ctx.stroke()
|
|
|
+ } else if (node.relationshipType === 'spouse') {
|
|
|
+ this.drawHeartLegacy(ctx, node.x, node.y, r)
|
|
|
+ ctx.setFillStyle(this.themeColor + '22')
|
|
|
+ ctx.fill()
|
|
|
+ } else if (node.relationshipType === 'parent') {
|
|
|
+ this.drawRoundedRectLegacy(ctx, node.x, node.y, r * 2, r * 2, r * 0.3)
|
|
|
+ ctx.setFillStyle(this.themeColor + '22')
|
|
|
+ ctx.fill()
|
|
|
+ } else if (node.relationshipType === 'sibling') {
|
|
|
+ this.drawPolygonLegacy(ctx, node.x, node.y, r, 8)
|
|
|
+ ctx.setFillStyle(this.themeColor + '22')
|
|
|
+ ctx.fill()
|
|
|
} else {
|
|
|
+ ctx.beginPath()
|
|
|
+ ctx.arc(node.x, node.y, r, 0, 2 * Math.PI)
|
|
|
ctx.setFillStyle(this.themeColor + '22')
|
|
|
ctx.fill()
|
|
|
}
|
|
|
+
|
|
|
ctx.setFillStyle(node.isSelf ? this.themeColor : '#4A5568')
|
|
|
ctx.setFont('bold ' + (r * 0.9) + 'px sans-serif')
|
|
|
ctx.setTextAlign('center')
|
|
|
@@ -554,6 +604,92 @@ export default {
|
|
|
self.canvasHeight = rect.height || 280
|
|
|
}
|
|
|
}).exec()
|
|
|
+ },
|
|
|
+
|
|
|
+ // ===== 形状绘制辅助方法 =====
|
|
|
+
|
|
|
+ drawHeart: function(ctx, cx, cy, size) {
|
|
|
+ ctx.beginPath()
|
|
|
+ var topX = cx
|
|
|
+ var topY = cy - size * 0.4
|
|
|
+ ctx.moveTo(topX, topY)
|
|
|
+ // 左曲线
|
|
|
+ ctx.bezierCurveTo(
|
|
|
+ cx - size * 0.9, cy - size * 0.7,
|
|
|
+ cx - size * 0.6, cy + size * 0.5,
|
|
|
+ cx, cy + size * 0.8
|
|
|
+ )
|
|
|
+ // 右曲线
|
|
|
+ ctx.bezierCurveTo(
|
|
|
+ cx + size * 0.6, cy + size * 0.5,
|
|
|
+ cx + size * 0.9, cy - size * 0.7,
|
|
|
+ cx, cy - size * 0.4
|
|
|
+ )
|
|
|
+ ctx.closePath()
|
|
|
+ },
|
|
|
+
|
|
|
+ drawRoundedRect: function(ctx, cx, cy, w, h, r) {
|
|
|
+ ctx.beginPath()
|
|
|
+ var x = cx - w / 2
|
|
|
+ var y = cy - h / 2
|
|
|
+ ctx.moveTo(x + r, y)
|
|
|
+ ctx.arcTo(x + w, y, x + w, y + h, r)
|
|
|
+ ctx.arcTo(x + w, y + h, x, y + h, r)
|
|
|
+ ctx.arcTo(x, y + h, x, y, r)
|
|
|
+ ctx.arcTo(x, y, x + w, y, r)
|
|
|
+ ctx.closePath()
|
|
|
+ },
|
|
|
+
|
|
|
+ drawPolygon: function(ctx, cx, cy, r, sides) {
|
|
|
+ ctx.beginPath()
|
|
|
+ var startAngle = -Math.PI / 2
|
|
|
+ for (var i = 0; i < sides; i++) {
|
|
|
+ var angle = startAngle + (2 * Math.PI * i) / sides
|
|
|
+ var px = cx + r * Math.cos(angle)
|
|
|
+ var py = cy + r * Math.sin(angle)
|
|
|
+ if (i === 0) {
|
|
|
+ ctx.moveTo(px, py)
|
|
|
+ } else {
|
|
|
+ ctx.lineTo(px, py)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ctx.closePath()
|
|
|
+ },
|
|
|
+
|
|
|
+ drawHeartLegacy: function(ctx, cx, cy, size) {
|
|
|
+ ctx.beginPath()
|
|
|
+ ctx.moveTo(cx, cy - size * 0.4)
|
|
|
+ ctx.bezierCurveTo(cx - size * 0.9, cy - size * 0.7, cx - size * 0.6, cy + size * 0.5, cx, cy + size * 0.8)
|
|
|
+ ctx.bezierCurveTo(cx + size * 0.6, cy + size * 0.5, cx + size * 0.9, cy - size * 0.7, cx, cy - size * 0.4)
|
|
|
+ ctx.closePath()
|
|
|
+ },
|
|
|
+
|
|
|
+ drawRoundedRectLegacy: function(ctx, cx, cy, w, h, r) {
|
|
|
+ ctx.beginPath()
|
|
|
+ var x = cx - w / 2
|
|
|
+ var y = cy - h / 2
|
|
|
+ ctx.moveTo(x + r, y)
|
|
|
+ ctx.arcTo(x + w, y, x + w, y + h, r)
|
|
|
+ ctx.arcTo(x + w, y + h, x, y + h, r)
|
|
|
+ ctx.arcTo(x, y + h, x, y, r)
|
|
|
+ ctx.arcTo(x, y, x + w, y, r)
|
|
|
+ ctx.closePath()
|
|
|
+ },
|
|
|
+
|
|
|
+ drawPolygonLegacy: function(ctx, cx, cy, r, sides) {
|
|
|
+ ctx.beginPath()
|
|
|
+ var startAngle = -Math.PI / 2
|
|
|
+ for (var i = 0; i < sides; i++) {
|
|
|
+ var angle = startAngle + (2 * Math.PI * i) / sides
|
|
|
+ var px = cx + r * Math.cos(angle)
|
|
|
+ var py = cy + r * Math.sin(angle)
|
|
|
+ if (i === 0) {
|
|
|
+ ctx.moveTo(px, py)
|
|
|
+ } else {
|
|
|
+ ctx.lineTo(px, py)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ctx.closePath()
|
|
|
}
|
|
|
}
|
|
|
}
|