graph.eachNode(function (node) { var startAngle = node.layout.startAngle / Math.PI * 180 * sign; var endAngle = node.layout.endAngle / Math.PI * 180 * sign; var angle = (startAngle * -sign + endAngle * -sign) / 2; angle %= 360; if (angle < 0) { // Constrain to [0,360] angle += 360; } var isRightSide = angle <= 90 || angle >= 270; angle = angle * Math.PI / 180; var v = [ Math.cos(angle), -Math.sin(angle) ]; var distance = 0; if (mainSerie.ribbonType) { distance = mainSerie.showScaleText ? 35 + labelDistance : labelDistance; } else { distance = labelDistance + node.layout.size; } var start = vec2.scale([], v, radius[1] + distance); vec2.add(start, start, center); var labelShape = { zlevel: serie.zlevel, z: serie.z + 1, hoverable: false, style: { text: node.data.label == null ? node.id : node.data.label, textAlign: isRightSide ? 'left' : 'right' } }; if (rotateLabel) { labelShape.rotation = isRightSide ? angle : Math.PI + angle; if (isRightSide) { labelShape.style.x = radius[1] + distance; } else { labelShape.style.x = -radius[1] - distance; } labelShape.style.y = 0; labelShape.position = center.slice(); } else { labelShape.style.x = start[0]; labelShape.style.y = start[1]; } // zrender/Text并没有textColor属性,ctx fillStyle使用的是color labelShape.style.color = this.deepQuery([ node.data, mainSerie ], 'itemStyle.normal.label.textStyle.color') || '#000000'; labelShape.style.textFont = this.getFont(this.deepQuery([ node.data, mainSerie ], 'itemStyle.normal.label.textStyle')); labelShape = new TextShape(labelShape); this.shapeList.push(labelShape); node.labelShape = labelShape; }, this);
return function (startPointSet, endPointSet, mp0, mp1) { vec2.set(cp0, 0, 0); vec2.set(cp1, 0, 0); var len = startPointSet.length; // Calculate the centroid of start points set for (var i = 0; i < len; i++) { vec2.add(cp0, cp0, startPointSet[i]); } vec2.scale(cp0, cp0, 1 / len); // Calculate the centroid of end points set len = endPointSet.length; for (var i = 0; i < len; i++) { vec2.add(cp1, cp1, endPointSet[i]); } vec2.scale(cp1, cp1, 1 / len); this._limitTurningAngle( startPointSet, cp0, cp1, mp0 ); this._limitTurningAngle( endPointSet, cp1, cp0, mp1 ); }
return function (pointSet, p0, p1, out) { // Limit the max turning angle var maxTurningAngleCos = Math.cos(this.maxTurningAngle); var maxTurningAngleTan = Math.tan(this.maxTurningAngle); vec2.sub(v10, p0, p1); vec2.normalize(v10, v10); // Simply copy the centroid point if no need to turn the angle vec2.copy(out, p0); var maxMovement = 0; for (var i = 0; i < pointSet.length; i++) { var p = pointSet[i]; vec2.sub(vTmp, p, p0); var len = vec2.len(vTmp); vec2.scale(vTmp, vTmp, 1 / len); var turningAngleCos = vec2.dot(vTmp, v10); // Turning angle is to large if (turningAngleCos < maxTurningAngleCos) { // Calculat p's project point on vector p1-p0 // and distance to the vector vec2.scaleAndAdd( project, p0, v10, len * turningAngleCos ); var distance = v2Dist(project, p); // Use the max turning angle to calculate the new meet point var d = distance / maxTurningAngleTan; vec2.scaleAndAdd(tmpOut, project, v10, -d); var movement = v2DistSquare(tmpOut, p0); if (movement > maxMovement) { maxMovement = movement; vec2.copy(out, tmpOut); } } } };
ForceLayout.prototype.update = function() { var nNodes = this.nodes.length; this.updateBBox(); this._k = 0.4 * this.scaling * Math.sqrt(this.width * this.height / nNodes); if (this.barnesHutOptimize) { this._rootRegion.setBBox( this.bbox[0], this.bbox[1], this.bbox[2], this.bbox[3] ); this._rootRegion.beforeUpdate(); for (var i = 0; i < nNodes; i++) { this._rootRegion.addNode(this.nodes[i]); } this._rootRegion.afterUpdate(); } else { // Update center of mass of whole graph var mass = 0; var centerOfMass = this._rootRegion.centerOfMass; vec2.set(centerOfMass, 0, 0); for (var i = 0; i < nNodes; i++) { var node = this.nodes[i]; mass += node.mass; vec2.scaleAndAdd(centerOfMass, centerOfMass, node.position, node.mass); } vec2.scale(centerOfMass, centerOfMass, 1 / mass); } // Reset forces for (var i = 0; i < nNodes; i++) { var node = this.nodes[i]; vec2.copy(node.forcePrev, node.force); vec2.copy(node.speedPrev, node.speed); vec2.set(node.force, 0, 0); } // Compute forces // Repulsion for (var i = 0; i < nNodes; i++) { var na = this.nodes[i]; if (this.barnesHutOptimize) { this.applyRegionToNodeRepulsion(this._rootRegion, na); } else { for (var j = i + 1; j < nNodes; j++) { var nb = this.nodes[j]; this.applyNodeToNodeRepulsion(na, nb, false); } } // Gravity if (this.gravity > 0) { this.applyNodeGravity(na); } } // Attraction for (var i = 0; i < this.edges.length; i++) { this.applyEdgeAttraction(this.edges[i]); } // Apply forces // var speed = vec2.create(); var v = vec2.create(); for (var i = 0; i < nNodes; i++) { var node = this.nodes[i]; var speed = node.speed; // var swing = vec2.dist(node.force, node.forcePrev); // // var swing = 30; // vec2.scale(node.force, node.force, 1 / (1 + Math.sqrt(swing))); vec2.scale(node.force, node.force, 1 / 30); // contraint force var df = vec2.len(node.force) + 0.1; var scale = Math.min(df, 500.0) / df; vec2.scale(node.force, node.force, scale); vec2.add(speed, speed, node.force); vec2.scale(speed, speed, this.temperature); // Prevent swinging // Limited the increase of speed up to 100% each step // TODO adjust by nodes number vec2.sub(v, speed, node.speedPrev); var swing = vec2.len(v); if (swing > 0) { vec2.scale(v, v, 1 / swing); var base = vec2.len(node.speedPrev); if (base > 0) { swing = Math.min(swing / base, this.maxSpeedIncrease) * base; vec2.scaleAndAdd(speed, node.speedPrev, v, swing); } } // constraint speed var ds = vec2.len(speed); var scale = Math.min(ds, 100.0) / (ds + 0.1); vec2.scale(speed, speed, scale); vec2.add(node.position, node.position, speed); } };
function _update(stepTime) { var len = nodePositions.length; var v12 = []; // 计算节点之间斥力 var k2 = k*k; // Reset force for (var i = 0; i < len; i++) { nodeForces[i][0] = 0; nodeForces[i][1] = 0; } for (var i = 0; i < len; i++) { for (var j = i+1; j < len; j++){ var w1 = nodeWeights[i]; var w2 = nodeWeights[j]; var p1 = nodePositions[i]; var p2 = nodePositions[j]; // 节点1到2的向量 vec2.sub(v12, p2, p1); var d = vec2.length(v12); // 距离大于500忽略斥力 if(d > 500){ continue; } if(d < 5){ d = 5; } vec2.scale(v12, v12, 1/d); var forceFactor = 1 * (w1 + w2) * k2 / d; vec2.scale(v12, v12, forceFactor); //节点1受到的力 vec2.sub(nodeForces[i], nodeForces[i], v12); //节点2受到的力 vec2.add(nodeForces[j], nodeForces[j], v12); } } // 计算节点之间引力 for (var i = 0, l = linksRawData.length; i < l; i++) { var link = linksRawData[i]; var w = linkWeights[i]; var s = link.source; var t = link.target; var p1 = nodePositions[s]; var p2 = nodePositions[t]; vec2.sub(v12, p2, p1); var d2 = vec2.lengthSquare(v12); vec2.normalize(v12, v12); var forceFactor = w * d2 / k; // 节点1受到的力 vec2.scale(v12, v12, forceFactor); vec2.add(nodeForces[s], nodeForces[s], v12); // 节点2受到的力 vec2.sub(nodeForces[t], nodeForces[t], v12); } // 到质心的向心力 for (var i = 0, l = nodesRawData.length; i < l; i++){ var p = nodePositions[i]; vec2.sub(v12, centroid, p); var d2 = vec2.lengthSquare(v12); vec2.normalize(v12, v12); // 100是可调参数 var forceFactor = d2 / 100 * centripetal; vec2.scale(v12, v12, forceFactor); vec2.add(nodeForces[i], nodeForces[i], v12); } // 计算加速度 for (var i = 0, l = nodeAccelerations.length; i < l; i++) { vec2.scale( nodeAccelerations[i], nodeForces[i], 1 / nodeMasses[i] ); } var velocity = []; var tmp = []; // 计算位置(verlet积分) for (var i = 0, l = nodePositions.length; i < l; i++) { if (nodesRawData[i].fixed) { // 拖拽同步 nodePositions[i][0] = mouseX + dx; nodePositions[i][1] = mouseY + dy; nodePrePositions[i][0] = mouseX + dx; nodePrePositions[i][1] = mouseY + dy; nodeShapes[i].position[0] = mouseX + dx; nodeShapes[i].position[1] = mouseY + dy; continue; } var p = nodePositions[i]; var __P = nodePrePositions[i]; vec2.sub(velocity, p, __P); __P[0] = p[0]; __P[1] = p[1]; vec2.add( velocity, velocity, vec2.scale(tmp, nodeAccelerations[i], stepTime) ); // Damping vec2.scale(velocity, velocity, temperature); // 防止速度太大 velocity[0] = Math.max(Math.min(velocity[0], 100), -100); velocity[1] = Math.max(Math.min(velocity[1], 100), -100); vec2.add(p, p, velocity); nodeShapes[i].position[0] = p[0] ; nodeShapes[i].position[1] = p[1] ; if(isNaN(p[0]) || isNaN(p[1])){ throw new Error('NaN'); } } }
_buildScales : function ( values, unitPostfix, angles, unitValue ) { for (var i = 0; i < angles.length; i++) { var subStartAngle = angles[i][0]; var subEndAngle = angles[i][1]; var scaleAngle = subStartAngle; while (scaleAngle < subEndAngle) { var thelta = ((this.clockWise ? (360 - scaleAngle) : scaleAngle) + this.startAngle) / 180 * Math.PI; var v = [ Math.cos(thelta), -Math.sin(thelta) ]; var start = vec2.scale([], v, this.outerRadius + 1); vec2.add(start, start, this.center); var end = vec2.scale([], v, this.outerRadius + this.scaleLineLength); vec2.add(end, end, this.center); var scaleShape = { zlevel : this._zlevelBase - 1, hoverable : false, style : { xStart : start[0], yStart : start[1], xEnd : end[0], yEnd : end[1], lineCap : 'round', brushType : 'stroke', strokeColor : '#666', lineWidth: 1 } }; scaleShape = new LineShape(scaleShape); this.shapeList.push(scaleShape); scaleAngle += this.scaleUnitAngle; } if (!this.showScaleText) { continue; } var scaleTextAngle = subStartAngle; var step = unitValue * 5 * this.scaleUnitAngle; var scaleValues = NDArray.range(0, values[i], step).toArray(); while (scaleTextAngle < subEndAngle) { var thelta = this.clockWise ? (360 - scaleTextAngle) : scaleTextAngle; thelta = (thelta + this.startAngle) % 360; var isRightSide = thelta <= 90 || thelta >= 270; var textShape = { zlevel : this._zlevelBase - 1, hoverable : false, style : { x : isRightSide ? this.outerRadius + this.scaleLineLength + 4 : -this.outerRadius - this.scaleLineLength - 4, y : 0, text : Math.round(scaleValues.shift()*10)/10 + unitPostfix, textAlign : isRightSide ? 'left' : 'right' }, position : this.center.slice(), rotation : isRightSide ? [thelta / 180 * Math.PI, 0, 0] : [ (thelta + 180) / 180 * Math.PI, 0, 0 ] }; textShape = new TextShape(textShape); this.shapeList.push(textShape); scaleTextAngle += this.scaleUnitAngle * 5; } } },
_buildSectors : function (angles, data) { var len = this.groups.length; var len2 = this.chordSeries.length; var timeout; var showLabel = this.query( this.chordSerieSample, 'itemStyle.normal.label.show' ); var labelColor = this.query( this.chordSerieSample, 'itemStyle.normal.label.color' ); var rotateLabel = this.query( this.chordSerieSample, 'itemStyle.normal.label.rotate' ); var labelDistance = this.query( this.chordSerieSample, 'itemStyle.normal.label.distance' ); var self = this; function createMouseOver(idx) { return function () { if (timeout) { clearTimeout(timeout); } timeout = setTimeout(function (){ for (var i = 0; i < len; i++) { self.sectorShapes[i].style.opacity = i === idx ? 1 : 0.1; self.zr.modShape(self.sectorShapes[i].id); for (var j = 0; j < len; j++) { for (var k = 0; k < len2; k++) { var chordShape = self.chordShapes[i][j][k]; if (chordShape) { chordShape.style.opacity = (i === idx || j === idx) ? 0.5 : 0.03; self.zr.modShape(chordShape.id); } } } } self.zr.refresh(); }, 50); }; } function createMouseOut() { return function () { if (timeout) { clearTimeout(timeout); } timeout = setTimeout(function (){ for (var i = 0; i < len; i++) { self.sectorShapes[i].style.opacity = 1.0; self.zr.modShape(self.sectorShapes[i].id); for (var j = 0; j < len; j++) { for (var k = 0; k < len2; k++) { var chordShape = self.chordShapes[i][j][k]; if (chordShape) { chordShape.style.opacity = 0.5; self.zr.modShape(chordShape.id); } } } } self.zr.refresh(); }, 50); }; } for (var i = 0; i < len; i++) { var group = this.groups[i]; var angle = angles[i]; var _start = (this.clockWise ? (360 - angle[1]) : angle[0]) + this.startAngle; var _end = (this.clockWise ? (360 - angle[0]) : angle[1]) + this.startAngle; var sector = { zlevel : this._zlevelBase, style : { x : this.center[0], y : this.center[1], r0 : this.innerRadius, r : this.outerRadius, startAngle : _start, endAngle : _end, brushType : 'fill', opacity: 1, color : this.getColor(group.name) }, clickable: true, highlightStyle : { brushType : 'fill' } }; sector.style.lineWidth = this.deepQuery( [group, this.chordSerieSample], 'itemStyle.normal.lineStyle.width' ); sector.highlightStyle.lineWidth = this.deepQuery( [group, this.chordSerieSample], 'itemStyle.emphasis.lineStyle.width' ); sector.style.strokeColor = this.deepQuery( [group, this.chordSerieSample], 'itemStyle.normal.lineStyle.color' ); sector.highlightStyle.strokeColor = this.deepQuery( [group, this.chordSerieSample], 'itemStyle.emphasis.lineStyle.color' ); if (sector.style.lineWidth > 0) { sector.style.brushType = 'both'; } if (sector.highlightStyle.lineWidth > 0) { sector.highlightStyle.brushType = 'both'; } ecData.pack( sector, this.chordSeries[0], 0, data[i], i, group.name ); if (showLabel) { var halfAngle = [_start + _end] / 2; halfAngle %= 360; // Constrain to [0,360] var isRightSide = halfAngle <= 90 || halfAngle >= 270; halfAngle = halfAngle * Math.PI / 180; var v = [Math.cos(halfAngle), -Math.sin(halfAngle)]; var distance = this.showScaleText ? 35 + labelDistance : labelDistance; var start = vec2.scale([], v, this.outerRadius + distance); vec2.add(start, start, this.center); var labelShape = { zlevel : this._zlevelBase - 1, hoverable : false, style : { text : group.name, textAlign : isRightSide ? 'left' : 'right', color : labelColor } }; if (rotateLabel) { labelShape.rotation = isRightSide ? halfAngle : Math.PI + halfAngle; if (isRightSide) { labelShape.style.x = this.outerRadius + distance; } else { labelShape.style.x = -this.outerRadius - distance; } labelShape.style.y = 0; labelShape.position = this.center; } else { labelShape.style.x = start[0]; labelShape.style.y = start[1]; } labelShape.style.textColor = this.deepQuery( [group, this.chordSerieSample], 'itemStyle.normal.label.textStyle.color' ) || '#fff'; labelShape.style.textFont = this.getFont(this.deepQuery( [group, this.chordSerieSample], 'itemStyle.normal.label.textStyle' )); labelShape = new TextShape(labelShape); this.shapeList.push(labelShape); } sector.onmouseover = createMouseOver(i); sector.onmouseout = createMouseOut(); sector = new SectorShape(sector); this.shapeList.push(sector); this.sectorShapes.push(sector); } },
function _update(stepTime) { var len = nodePositions.length; var v12 = []; // 计算节点之间斥力 var k2 = k*k; // Reset force for (var i = 0; i < len; i++) { nodeForces[i][0] = 0; nodeForces[i][1] = 0; } for (var i = 0; i < len; i++) { for (var j = i+1; j < len; j++){ var w1 = nodeWeights[i]; var w2 = nodeWeights[j]; var p1 = nodePositions[i]; var p2 = nodePositions[j]; // 节点1到2的向量 vec2.sub(v12, p2, p1); var d = vec2.length(v12); // 距离大于500忽略斥力 if(d > 500){ continue; } if(d < 5){ d = 5; } vec2.scale(v12, v12, 1 / d); var forceFactor = 1 * (w1 + w2) * k2 / d; //节点1受到的力 vec2.scaleAndAdd( nodeForces[i], nodeForces[i], v12, -forceFactor ); //节点2受到的力 vec2.scaleAndAdd( nodeForces[j], nodeForces[j], v12, forceFactor ); } } // 计算节点之间引力 for (var i = 0, l = filteredLinks.length; i < l; i++) { var link = filteredLinks[i]; var w = linkWeights[i]; var s = link.source; var t = link.target; var p1 = nodePositions[s]; var p2 = nodePositions[t]; vec2.sub(v12, p2, p1); var d2 = vec2.lengthSquare(v12); if (d2 === 0) { continue; } var forceFactor = w * d2 / k / Math.sqrt(d2); // 节点1受到的力 vec2.scaleAndAdd( nodeForces[s], nodeForces[s], v12, forceFactor ); // 节点2受到的力 vec2.scaleAndAdd( nodeForces[t], nodeForces[t], v12, -forceFactor ); } // 到质心的向心力 for (var i = 0, l = filteredNodes.length; i < l; i++){ var p = nodePositions[i]; vec2.sub(v12, centroid, p); var d2 = vec2.lengthSquare(v12); var forceFactor = d2 * centripetal / (100 * Math.sqrt(d2)); vec2.scaleAndAdd( nodeForces[i], nodeForces[i], v12, forceFactor ); } var velocity = []; // 计算位置(verlet积分) for (var i = 0, l = nodePositions.length; i < l; i++) { var name = filteredNodes[i].name; if (filteredNodes[i].fixed) { // 拖拽同步 vec2.set(nodePositions[i], mouseX, mouseY); vec2.set(nodePrePositions[i], mouseX, mouseY); vec2.set(nodeShapes[i].position, mouseX, mouseY); if (filteredNodes[i].initial !== undefined) { vec2.set(filteredNodes[i].initial, mouseX, mouseY); } if (nodeInitialPos[name] !== undefined) { vec2.set(nodeInitialPos[name], mouseX, mouseY); } continue; } var p = nodePositions[i]; var __P = nodePrePositions[i]; vec2.sub(velocity, p, __P); __P[0] = p[0]; __P[1] = p[1]; vec2.scaleAndAdd( velocity, velocity, nodeForces[i], stepTime / nodeMasses[i] ); // Damping vec2.scale(velocity, velocity, temperature); // 防止速度太大 velocity[0] = Math.max(Math.min(velocity[0], 100), -100); velocity[1] = Math.max(Math.min(velocity[1], 100), -100); vec2.add(p, p, velocity); vec2.copy(nodeShapes[i].position, p); if (name) { if (nodeInitialPos[name] === undefined) { nodeInitialPos[name] = vec2.create(); } vec2.copy(nodeInitialPos[name], p); } else { if (filteredNodes[i].initial === undefined) { filteredNodes[i].initial = vec2.create(); } vec2.copy(filteredNodes[i].initial, p); } // if(isNaN(p[0]) || isNaN(p[1])){ // throw new Error('NaN'); // } } }
graph.eachNode(function (node) { var startAngle = node.layout.startAngle / Math.PI * 180; var endAngle = node.layout.endAngle / Math.PI * 180; var scaleAngle = startAngle; while (true) { if ((clockWise && scaleAngle > endAngle) || (!clockWise && scaleAngle < endAngle) ) { break; } var theta = scaleAngle / 180 * Math.PI; var v = [Math.cos(theta), Math.sin(theta)]; var start = vec2.scale([], v, radius[1] + 1); vec2.add(start, start, center); var end = vec2.scale([], v, radius[1] + this.scaleLineLength); vec2.add(end, end, center); var scaleShape = new LineShape({ zlevel: serie.zlevel, z: serie.z - 1, hoverable: false, style: { xStart: start[0], yStart: start[1], xEnd: end[0], yEnd: end[1], lineCap: 'round', brushType: 'stroke', strokeColor: '#666', lineWidth: 1 } }); this.shapeList.push(scaleShape); scaleAngle += sign * this.scaleUnitAngle; } if (!serie.showScaleText) { return; } var scaleTextAngle = startAngle; var step = unitValue * 5 * this.scaleUnitAngle; var scaleValue = 0; while (true) { if ((clockWise && scaleTextAngle > endAngle) || (!clockWise && scaleTextAngle < endAngle) ) { break; } var theta = scaleTextAngle; theta = theta % 360; if (theta < 0) { theta += 360; } var isRightSide = theta <= 90 || theta >= 270; var textShape = new TextShape({ zlevel: serie.zlevel, z: serie.z - 1, hoverable: false, style: { x: isRightSide ? radius[1] + this.scaleLineLength + 4 : -radius[1] - this.scaleLineLength - 4, y: 0, text: Math.round(scaleValue * 10) / 10 + unitPostfix, textAlign: isRightSide ? 'left' : 'right' }, position: center.slice(), rotation: isRightSide ? [-theta / 180 * Math.PI, 0, 0] : [ -(theta + 180) / 180 * Math.PI, 0, 0 ] }); this.shapeList.push(textShape); scaleValue += step * unitScale; scaleTextAngle += sign * this.scaleUnitAngle * 5; } }, this);
function _buildSectors(angles, data) { var len = groups.length; var len2 = chordSeries.length; var timeout; var showLabel = self.query( chordSerieSample, 'itemStyle.normal.label.show' ); var labelColor = self.query( chordSerieSample, 'itemStyle.normal.label.color' ); function createMouseOver(idx) { return function() { if (timeout) { clearTimeout(timeout); } timeout = setTimeout(function(){ for (var i = 0; i < len; i++) { sectorShapes[i].style.opacity = i === idx ? 1 : 0.1; zr.modShape( sectorShapes[i].id, sectorShapes[i] ); for (var j = 0; j < len; j++) { for (var k = 0; k < len2; k++) { var chordShape = chordShapes[i][j][k]; if (chordShape) { chordShape.style.opacity = (i === idx || j === idx) ? 0.5 : 0.03; zr.modShape(chordShape.id, chordShape); } } } } zr.refresh(); }, 50); }; } function createMouseOut() { return function() { if (timeout) { clearTimeout(timeout); } timeout = setTimeout(function(){ for (var i = 0; i < len; i++) { sectorShapes[i].style.opacity = 1.0; zr.modShape(sectorShapes[i].id, sectorShapes[i]); for (var j = 0; j < len; j++) { for (var k = 0; k < len2; k++) { var chordShape = chordShapes[i][j][k]; if (chordShape) { chordShape.style.opacity = 0.5; zr.modShape(chordShape.id, chordShape); } } } } zr.refresh(); }, 50); }; } for (var i = 0; i < len; i++) { var group = groups[i]; var angle = angles[i]; var _start = (clockWise ? (360 - angle[1]) : angle[0]) + startAngle; var _end = (clockWise ? (360 - angle[0]) : angle[1]) + startAngle; var sector = { id : zr.newShapeId(self.type), shape : 'sector', zlevel : _zlevelBase, style : { x : center[0], y : center[1], r0 : innerRadius, r : outerRadius, startAngle : _start, endAngle : _end, brushType : 'fill', opacity: 1, color : getColor(group.name) }, highlightStyle : { brushType : 'fill' } }; sector.style.lineWidth = self.deepQuery( [group, chordSerieSample], 'itemStyle.normal.lineStyle.width' ); sector.highlightStyle.lineWidth = self.deepQuery( [group, chordSerieSample], 'itemStyle.emphasis.lineStyle.width' ); sector.style.strokeColor = self.deepQuery( [group, chordSerieSample], 'itemStyle.normal.lineStyle.color' ); sector.highlightStyle.strokeColor = self.deepQuery( [group, chordSerieSample], 'itemStyle.emphasis.lineStyle.color' ); if (sector.style.lineWidth > 0) { sector.style.brushType = 'both'; } if (sector.highlightStyle.lineWidth > 0) { sector.highlightStyle.brushType = 'both'; } ecData.pack( sector, chordSeries[0], 0, data[i], 0, group.name ); if (showLabel) { var halfAngle = [_start + _end] / 2; halfAngle %= 360; // Constrain to [0,360] var isRightSide = halfAngle <= 90 || halfAngle >= 270; halfAngle = halfAngle * Math.PI / 180; var v = [Math.cos(halfAngle), -Math.sin(halfAngle)]; var distance = showScaleText ? 45 : 20; var start = vec2.scale([], v, outerRadius + distance); vec2.add(start, start, center); var labelShape = { shape : 'text', id : zr.newShapeId(self.type), zlevel : _zlevelBase - 1, hoverable : false, style : { x : start[0], y : start[1], text : group.name, textAlign : isRightSide ? 'left' : 'right', color : labelColor } }; labelShape.style.textColor = self.deepQuery( [group, chordSerieSample], 'itemStyle.normal.label.textStyle.color' ) || '#fff'; labelShape.style.textFont = self.getFont(self.deepQuery( [group, chordSerieSample], 'itemStyle.normal.label.textStyle' )); zr.addShape(labelShape); self.shapeList.push(labelShape); } sector.onmouseover = createMouseOver(i); sector.onmouseout = createMouseOut(); self.shapeList.push(sector); sectorShapes.push(sector); zr.addShape(sector); } }
define("echarts/chart/chord",["require","./base","zrender/shape/Text","zrender/shape/Line","zrender/shape/Sector","../util/shape/Ribbon","../util/shape/Icon","zrender/shape/BezierCurve","../config","../util/ecData","zrender/tool/util","zrender/tool/vector","../data/Graph","../layout/Chord","../chart"],function(require){"use strict";function e(e,i,a,r,o){t.call(this,e,i,a,r,o),this.scaleLineLength=4,this.scaleUnitAngle=4,this.refresh(r)}var t=require("./base"),i=require("zrender/shape/Text"),a=require("zrender/shape/Line"),r=require("zrender/shape/Sector"),o=require("../util/shape/Ribbon"),s=require("../util/shape/Icon"),n=require("zrender/shape/BezierCurve"),l=require("../config");l.chord={zlevel:0,z:2,clickable:!0,radius:["65%","75%"],center:["50%","50%"],padding:2,sort:"none",sortSub:"none",startAngle:90,clockWise:!0,ribbonType:!0,minRadius:10,maxRadius:20,symbol:"circle",showScale:!1,showScaleText:!1,itemStyle:{normal:{borderWidth:0,borderColor:"#000",label:{show:!0,rotate:!1,distance:5},chordStyle:{width:1,color:"black",borderWidth:1,borderColor:"#999",opacity:.5}},emphasis:{borderWidth:0,borderColor:"#000",chordStyle:{width:1,color:"black",borderWidth:1,borderColor:"#999"}}}};var h=require("../util/ecData"),d=require("zrender/tool/util"),p=require("zrender/tool/vector"),c=require("../data/Graph"),g=require("../layout/Chord");return e.prototype={type:l.CHART_TYPE_CHORD,_init:function(){var e=this.series;this.selectedMap={};for(var t={},i={},a=0,r=e.length;r>a;a++)if(e[a].type===this.type){var o=this.isSelected(e[a].name);if(this.selectedMap[e[a].name]=o,o)this.buildMark(a);this.reformOption(e[a]),t[e[a].name]=e[a]}for(var a=0,r=e.length;r>a;a++)if(e[a].type===this.type)if(e[a].insertToSerie){var s=t[e[a].insertToSerie];e[a]._referenceSerie=s}else i[e[a].name]=[e[a]];for(var a=0,r=e.length;r>a;a++)if(e[a].type===this.type)if(e[a].insertToSerie){for(var n=e[a]._referenceSerie;n&&n._referenceSerie;)n=n._referenceSerie;if(i[n.name]&&this.selectedMap[e[a].name])i[n.name].push(e[a])}for(var l in i)this._buildChords(i[l]);this.addShapeList()},_getNodeCategory:function(e,t){return e.categories&&e.categories[t.category||0]},_getNodeQueryTarget:function(e,t){var i=this._getNodeCategory(e,t);return[t,i,e]},_getEdgeQueryTarget:function(e,t,i){return i=i||"normal",[t.itemStyle&&t.itemStyle[i],e.itemStyle[i].chordStyle]},_buildChords:function(e){for(var t=[],i=e[0],a=function(e){return e.layout.size>0},r=function(e){return function(t){return e.getEdge(t.node2,t.node1)}},o=0;o<e.length;o++){var s=e[o];if(this.selectedMap[s.name]){var n;if(s.data&&s.matrix)n=this._getSerieGraphFromDataMatrix(s,i);else if(s.nodes&&s.links)n=this._getSerieGraphFromNodeLinks(s,i);if(n.filterNode(a,this),s.ribbonType)n.filterEdge(r(n));t.push(n),n.__serie=s}}if(t.length){var l=t[0];if(!i.ribbonType){var h=i.minRadius,d=i.maxRadius,p=1/0,c=-1/0;l.eachNode(function(e){c=Math.max(e.layout.size,c),p=Math.min(e.layout.size,p)});var u=(d-h)/(c-p);l.eachNode(function(e){var t=this._getNodeQueryTarget(i,e),a=this.query(t,"symbolSize");if(c===p)e.layout.size=a||p;else e.layout.size=a||(e.layout.size-p)*u+h},this)}var f=new g;if(f.clockWise=i.clockWise,f.startAngle=i.startAngle*Math.PI/180,!f.clockWise)f.startAngle=-f.startAngle;f.padding=i.padding*Math.PI/180,f.sort=i.sort,f.sortSub=i.sortSub,f.directed=i.ribbonType,f.run(t);var y=this.query(i,"itemStyle.normal.label.show");if(i.ribbonType){if(this._buildSectors(i,0,l,i,t),y)this._buildLabels(i,0,l,i,t);for(var o=0,m=0;o<e.length;o++)if(this.selectedMap[e[o].name])this._buildRibbons(e,o,t[m++],i);if(i.showScale)this._buildScales(i,0,l)}else{if(this._buildNodeIcons(i,0,l,i,t),y)this._buildLabels(i,0,l,i,t);for(var o=0,m=0;o<e.length;o++)if(this.selectedMap[e[o].name])this._buildEdgeCurves(e,o,t[m++],i,l)}this._initHoverHandler(e,t)}},_getSerieGraphFromDataMatrix:function(e,t){for(var i=[],a=0,r=[],o=0;o<e.matrix.length;o++)r[o]=e.matrix[o].slice();for(var s=e.data||e.nodes,o=0;o<s.length;o++){var n={},l=s[o];l.rawIndex=o;for(var h in l)if("name"===h)n.id=l.name;else n[h]=l[h];var d=this._getNodeCategory(t,l),p=d?d.name:l.name;if(this.selectedMap[p]=this.isSelected(p),this.selectedMap[p])i.push(n),a++;else{r.splice(a,1);for(var g=0;g<r.length;g++)r[g].splice(a,1)}}var u=c.fromMatrix(i,r,!0);return u.eachNode(function(e){e.layout={size:e.data.outValue},e.rawIndex=e.data.rawIndex}),u.eachEdge(function(e){e.layout={weight:e.data.weight}}),u},_getSerieGraphFromNodeLinks:function(e,t){for(var i=new c(!0),a=e.data||e.nodes,r=0,o=a.length;o>r;r++){var s=a[r];if(s&&!s.ignore){var n=this._getNodeCategory(t,s),l=n?n.name:s.name;if(this.selectedMap[l]=this.isSelected(l),this.selectedMap[l]){var h=i.addNode(s.name,s);h.rawIndex=r}}else;}for(var r=0,o=e.links.length;o>r;r++){var d=e.links[r],p=d.source,g=d.target;if("number"==typeof p)if(p=a[p])p=p.name;if("number"==typeof g)if(g=a[g])g=g.name;var u=i.addEdge(p,g,d);if(u)u.rawIndex=r}return i.eachNode(function(e){var i=e.data.value;if(null==i)if(i=0,t.ribbonType)for(var a=0;a<e.outEdges.length;a++)i+=e.outEdges[a].data.weight||0;else for(var a=0;a<e.edges.length;a++)i+=e.edges[a].data.weight||0;e.layout={size:i}}),i.eachEdge(function(e){e.layout={weight:null==e.data.weight?1:e.data.weight}}),i},_initHoverHandler:function(e,t){var i=e[0],a=t[0],r=this;a.eachNode(function(e){e.shape.onmouseover=function(){a.eachNode(function(e){if(e.shape.style.opacity=.1,e.labelShape)e.labelShape.style.opacity=.1,e.labelShape.modSelf();e.shape.modSelf()});for(var i=0;i<t.length;i++)for(var o=0;o<t[i].edges.length;o++){var s=t[i].edges[o],n=r._getEdgeQueryTarget(t[i].__serie,s.data);s.shape.style.opacity=.1*r.deepQuery(n,"opacity"),s.shape.modSelf()}if(e.shape.style.opacity=1,e.labelShape)e.labelShape.style.opacity=1;for(var i=0;i<t.length;i++){var l=t[i].getNodeById(e.id);if(l)for(var o=0;o<l.outEdges.length;o++){var s=l.outEdges[o],n=r._getEdgeQueryTarget(t[i].__serie,s.data);s.shape.style.opacity=r.deepQuery(n,"opacity");var h=t[0].getNodeById(s.node2.id);if(h){if(h.shape)h.shape.style.opacity=1;if(h.labelShape)h.labelShape.style.opacity=1}}}r.zr.refreshNextFrame()},e.shape.onmouseout=function(){a.eachNode(function(e){if(e.shape.style.opacity=1,e.labelShape)e.labelShape.style.opacity=1,e.labelShape.modSelf();e.shape.modSelf()});for(var e=0;e<t.length;e++)for(var o=0;o<t[e].edges.length;o++){var s=t[e].edges[o],n=[s.data,i];s.shape.style.opacity=r.deepQuery(n,"itemStyle.normal.chordStyle.opacity"),s.shape.modSelf()}r.zr.refreshNextFrame()}})},_buildSectors:function(e,t,i,a){var o=this.parseCenter(this.zr,a.center),s=this.parseRadius(this.zr,a.radius),n=a.clockWise,l=n?1:-1;i.eachNode(function(i){var d=this._getNodeCategory(a,i.data),p=d?this.getColor(d.name):this.getColor(i.id),c=i.layout.startAngle/Math.PI*180*l,g=i.layout.endAngle/Math.PI*180*l,u=new r({zlevel:this.getZlevelBase(),z:this.getZBase(),style:{x:o[0],y:o[1],r0:s[0],r:s[1],startAngle:c,endAngle:g,brushType:"fill",opacity:1,color:p,clockWise:n},clickable:a.clickable,highlightStyle:{brushType:"fill"}});if(u.style.lineWidth=this.deepQuery([i.data,a],"itemStyle.normal.borderWidth"),u.highlightStyle.lineWidth=this.deepQuery([i.data,a],"itemStyle.emphasis.borderWidth"),u.style.strokeColor=this.deepQuery([i.data,a],"itemStyle.normal.borderColor"),u.highlightStyle.strokeColor=this.deepQuery([i.data,a],"itemStyle.emphasis.borderColor"),u.style.lineWidth>0)u.style.brushType="both";if(u.highlightStyle.lineWidth>0)u.highlightStyle.brushType="both";h.pack(u,e,t,i.data,i.rawIndex,i.id,i.category),this.shapeList.push(u),i.shape=u},this)},_buildNodeIcons:function(e,t,i,a){var r=this.parseCenter(this.zr,a.center),o=this.parseRadius(this.zr,a.radius),n=o[1];i.eachNode(function(i){var o=i.layout.startAngle,l=i.layout.endAngle,d=(o+l)/2,p=n*Math.cos(d),c=n*Math.sin(d),g=this._getNodeQueryTarget(a,i.data),u=this._getNodeCategory(a,i.data),f=this.deepQuery(g,"itemStyle.normal.color");if(!f)f=u?this.getColor(u.name):this.getColor(i.id);var y=new s({zlevel:this.getZlevelBase(),z:this.getZBase()+1,style:{x:-i.layout.size,y:-i.layout.size,width:2*i.layout.size,height:2*i.layout.size,iconType:this.deepQuery(g,"symbol"),color:f,brushType:"both",lineWidth:this.deepQuery(g,"itemStyle.normal.borderWidth"),strokeColor:this.deepQuery(g,"itemStyle.normal.borderColor")},highlightStyle:{color:this.deepQuery(g,"itemStyle.emphasis.color"),lineWidth:this.deepQuery(g,"itemStyle.emphasis.borderWidth"),strokeColor:this.deepQuery(g,"itemStyle.emphasis.borderColor")},clickable:a.clickable,position:[p+r[0],c+r[1]]});h.pack(y,e,t,i.data,i.rawIndex,i.id,i.category),this.shapeList.push(y),i.shape=y},this)},_buildLabels:function(e,t,a,r){var o=this.query(r,"itemStyle.normal.label.color"),s=this.query(r,"itemStyle.normal.label.rotate"),n=this.query(r,"itemStyle.normal.label.distance"),l=this.parseCenter(this.zr,r.center),h=this.parseRadius(this.zr,r.radius),d=r.clockWise,c=d?1:-1;a.eachNode(function(e){var t=e.layout.startAngle/Math.PI*180*c,a=e.layout.endAngle/Math.PI*180*c,d=(t*-c+a*-c)/2;if(d%=360,0>d)d+=360;var g=90>=d||d>=270;d=d*Math.PI/180;var u=[Math.cos(d),-Math.sin(d)],f=0;if(r.ribbonType)f=r.showScaleText?35+n:n;else f=n+e.layout.size;var y=p.scale([],u,h[1]+f);p.add(y,y,l);var m={zlevel:this.getZlevelBase(),z:this.getZBase()+1,hoverable:!1,style:{text:null==e.data.label?e.id:e.data.label,textAlign:g?"left":"right",color:o||"#000000"}};if(s){if(m.rotation=g?d:Math.PI+d,g)m.style.x=h[1]+f;else m.style.x=-h[1]-f;m.style.y=0,m.position=l.slice()}else m.style.x=y[0],m.style.y=y[1];m.style.textColor=this.deepQuery([e.data,r],"itemStyle.normal.label.textStyle.color")||"#fff",m.style.textFont=this.getFont(this.deepQuery([e.data,r],"itemStyle.normal.label.textStyle")),m=new i(m),this.shapeList.push(m),e.labelShape=m},this)},_buildRibbons:function(e,t,i,a){var r=e[t],s=this.parseCenter(this.zr,a.center),n=this.parseRadius(this.zr,a.radius);i.eachEdge(function(l,d){var p,c=i.getEdge(l.node2,l.node1);if(c&&!l.shape){if(c.shape)return void(l.shape=c.shape);var g=l.layout.startAngle/Math.PI*180,u=l.layout.endAngle/Math.PI*180,f=c.layout.startAngle/Math.PI*180,y=c.layout.endAngle/Math.PI*180;if(1===e.length)if(l.layout.weight<=c.layout.weight)p=this.getColor(l.node1.id);else p=this.getColor(l.node2.id);else p=this.getColor(r.name);var m,b,v=this._getEdgeQueryTarget(r,l.data),x=this._getEdgeQueryTarget(r,l.data,"emphasis"),_=new o({zlevel:this.getZlevelBase(),z:this.getZBase(),style:{x:s[0],y:s[1],r:n[0],source0:g,source1:u,target0:f,target1:y,brushType:"both",opacity:this.deepQuery(v,"opacity"),color:p,lineWidth:this.deepQuery(v,"borderWidth"),strokeColor:this.deepQuery(v,"borderColor"),clockWise:a.clockWise},clickable:a.clickable,highlightStyle:{brushType:"both",opacity:this.deepQuery(x,"opacity"),lineWidth:this.deepQuery(x,"borderWidth"),strokeColor:this.deepQuery(x,"borderColor")}});if(l.layout.weight<=c.layout.weight)m=c.node1,b=c.node2;else m=l.node1,b=l.node2;h.pack(_,r,t,l.data,null==l.rawIndex?d:l.rawIndex,l.data.name||m.id+"-"+b.id,m.id,b.id),this.shapeList.push(_),l.shape=_}},this)},_buildEdgeCurves:function(e,t,i,a,r){var o=e[t],s=this.parseCenter(this.zr,a.center);i.eachEdge(function(e,i){var a=r.getNodeById(e.node1.id),l=r.getNodeById(e.node2.id),d=a.shape,p=l.shape,c=this._getEdgeQueryTarget(o,e.data),g=this._getEdgeQueryTarget(o,e.data,"emphasis"),u=new n({zlevel:this.getZlevelBase(),z:this.getZBase(),style:{xStart:d.position[0],yStart:d.position[1],xEnd:p.position[0],yEnd:p.position[1],cpX1:s[0],cpY1:s[1],lineWidth:this.deepQuery(c,"width"),strokeColor:this.deepQuery(c,"color"),opacity:this.deepQuery(c,"opacity")},highlightStyle:{lineWidth:this.deepQuery(g,"width"),strokeColor:this.deepQuery(g,"color"),opacity:this.deepQuery(g,"opacity")}});h.pack(u,o,t,e.data,null==e.rawIndex?i:e.rawIndex,e.data.name||e.node1.id+"-"+e.node2.id,e.node1.id,e.node2.id),this.shapeList.push(u),e.shape=u},this)},_buildScales:function(e,t,r){var o,s,n=e.clockWise,l=this.parseCenter(this.zr,e.center),h=this.parseRadius(this.zr,e.radius),d=n?1:-1,c=0,g=-1/0;if(e.showScaleText)if(r.eachNode(function(e){var t=e.data.value;if(t>g)g=t;c+=t}),g>1e10)o="b",s=1e-9;else if(g>1e7)o="m",s=1e-6;else if(g>1e4)o="k",s=.001;else o="",s=1;var u=c/(360-e.padding);r.eachNode(function(t){for(var r=t.layout.startAngle/Math.PI*180,c=t.layout.endAngle/Math.PI*180,g=r;;){if(n&&g>c||!n&&c>g)break;var f=g/180*Math.PI,y=[Math.cos(f),Math.sin(f)],m=p.scale([],y,h[1]+1);p.add(m,m,l);var b=p.scale([],y,h[1]+this.scaleLineLength);p.add(b,b,l);var v=new a({zlevel:this.getZlevelBase(),z:this.getZBase()-1,hoverable:!1,style:{xStart:m[0],yStart:m[1],xEnd:b[0],yEnd:b[1],lineCap:"round",brushType:"stroke",strokeColor:"#666",lineWidth:1}});this.shapeList.push(v),g+=d*this.scaleUnitAngle}if(e.showScaleText)for(var x=r,_=5*u*this.scaleUnitAngle,S=0;;){if(n&&x>c||!n&&c>x)break;var f=x;if(f%=360,0>f)f+=360;var C=90>=f||f>=270,k=new i({zlevel:this.getZlevelBase(),z:this.getZBase()-1,hoverable:!1,style:{x:C?h[1]+this.scaleLineLength+4:-h[1]-this.scaleLineLength-4,y:0,text:Math.round(10*S)/10+o,textAlign:C?"left":"right"},position:l.slice(),rotation:C?[-f/180*Math.PI,0,0]:[-(f+180)/180*Math.PI,0,0]});this.shapeList.push(k),S+=_*s,x+=d*this.scaleUnitAngle*5}},this)},refresh:function(e){if(e)this.option=e,this.series=e.series;if(this.legend=this.component.legend,this.legend)this.getColor=function(e){return this.legend.getColor(e)},this.isSelected=function(e){return this.legend.isSelected(e)};else{var t={},i=0;this.getColor=function(e){if(t[e])return t[e];if(!t[e])t[e]=this.zr.getColor(i++);return t[e]},this.isSelected=function(){return!0}}this.backupShapeList(),this._init()},reformOption:function(e){var t=d.merge;e=t(t(e||{},this.ecTheme.chord),l.chord),e.itemStyle.normal.label.textStyle=this.getTextStyle(e.itemStyle.normal.label.textStyle)}},d.inherits(e,t),require("../chart").define("chord",e),e});
Intro.prototype._circle = function (cb) { var self = this; var graphMain = this._kgraph.getComponentByType('GRAPH'); var zr = graphMain.getZR(); var layer = zr.painter.getLayer(0); var graph = graphMain.getGraph(); var width = zr.getWidth(); var height = zr.getHeight(); var circles = graphMain.getCircles(); if (!circles.length) { cb(); return; } var circle = circles[0]; var center = vec2.create(); // 定位到circle中间 for (var i = 0; i < circle.nodes.length; i++) { var pos = circle.nodes[i].entity.el.position; circle.nodes[i].entity.setZLevel(10); vec2.add(center, center, pos); } vec2.scale(center, center, 1 / circle.nodes.length); var edge; var rightMost = -Infinity; // 查找到定位最右的边 for (var i = 0; i < circle.edges.length; i++) { var e = circle.edges[i]; e.entity.setZLevel(10); var x = (e.entity.el.style.xStart + e.entity.el.style.xEnd) / 2; if (x > rightMost) { rightMost = x; edge = e; } } graphMain.moveTo(width / 2 - center[0], height / 2 - center[1], showTip); function showTip() { var y = (edge.entity.el.style.yStart + edge.entity.el.style.yEnd) / 2; self._$tip.style.display = 'block'; self._$tip.className = 'bkg-tip bkg-tip-circle'; self._$tip.style.left = rightMost + layer.position[0] + 10 +'px'; self._$tip.style.top = y + layer.position[1] - self._$tip.clientHeight +'px'; } return function () { self._$tip.style.display = 'none'; for (var i = 0; i < circle.nodes.length; i++) { circle.nodes[i].entity.setZLevel(1); } for (var i = 0; i < circle.edges.length; i++) { circle.edges[i].entity.setZLevel(0); } zr.refreshNextFrame(); } };
function _buildScales( values, unitPostfix, angles, center, radius, unitValue ) { for (var i = 0; i < angles.length; i++) { var startAngle = angles[i][0]; var endAngle = angles[i][1]; var scaleAngle = startAngle; while (scaleAngle < endAngle) { var v = [ Math.cos((scaleAngle - 90) / 180 * Math.PI), Math.sin((scaleAngle - 90) / 180 * Math.PI) ]; var start = vec2.scale([], v, radius + 1); vec2.add(start, start, center); var end = vec2.scale([], v, radius + scaleLineLength); vec2.add(end, end, center); var scaleShape = { shape : 'line', id : zr.newShapeId(self.type), zlevel : _zlevelBase - 1, hoverable : false, style : { xStart : start[0], yStart : start[1], xEnd : end[0], yEnd : end[1], lineCap : 'round', brushType : 'stroke', strokeColor : '#666' } }; self.shapeList.push(scaleShape); zr.addShape(scaleShape); scaleAngle += scaleUnitAngle; } var scaleTextAngle = startAngle; var step = unitValue * 5 * scaleUnitAngle; var scaleValues = NDArray.range(0, values[i], step).toArray(); while (scaleTextAngle < endAngle) { var scaleTextAngleFixed = scaleTextAngle - 90; var isRightSide = scaleTextAngleFixed <= 90 && scaleTextAngleFixed >= -90; var textShape = { shape : 'text', id : zr.newShapeId(self.type), zlevel : _zlevelBase - 1, hoverable : false, style : { x : isRightSide ? radius + scaleLineLength + 2 : -radius - scaleLineLength - 34, y : 0, text : Math.round(scaleValues.shift()*10)/10 + unitPostfix }, position : center.slice(), rotation : isRightSide ? [-scaleTextAngleFixed / 180 * Math.PI, 0, 0] : [ -(scaleTextAngleFixed + 180) / 180 * Math.PI, 0, 0 ] }; self.shapeList.push(textShape); zr.addShape(textShape); scaleTextAngle += scaleUnitAngle * 5; } } }