/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var _number = require("../../util/number"); var parsePercent = _number.parsePercent; var zrUtil = require("zrender/lib/core/util"); /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var PI2 = Math.PI * 2; var RADIAN = Math.PI / 180; function _default(seriesType, ecModel, api, payload) { ecModel.eachSeriesByType(seriesType, function (seriesModel) { var center = seriesModel.get('center'); var radius = seriesModel.get('radius'); if (!zrUtil.isArray(radius)) { radius = [0, radius]; } if (!zrUtil.isArray(center)) { center = [center, center]; } var width = api.getWidth(); var height = api.getHeight(); var size = Math.min(width, height); var cx = parsePercent(center[0], width); var cy = parsePercent(center[1], height); var r0 = parsePercent(radius[0], size / 2); var r = parsePercent(radius[1], size / 2); var startAngle = -seriesModel.get('startAngle') * RADIAN; var minAngle = seriesModel.get('minAngle') * RADIAN; var virtualRoot = seriesModel.getData().tree.root; var treeRoot = seriesModel.getViewRoot(); var rootDepth = treeRoot.depth; var sort = seriesModel.get('sort'); if (sort != null) { initChildren(treeRoot, sort); } var validDataCount = 0; zrUtil.each(treeRoot.children, function (child) { !isNaN(child.getValue()) && validDataCount++; }); var sum = treeRoot.getValue(); // Sum may be 0 var unitRadian = Math.PI / (sum || validDataCount) * 2; var renderRollupNode = treeRoot.depth > 0; var levels = treeRoot.height - (renderRollupNode ? -1 : 1); var rPerLevel = (r - r0) / (levels || 1); var clockwise = seriesModel.get('clockwise'); var stillShowZeroSum = seriesModel.get('stillShowZeroSum'); // In the case some sector angle is smaller than minAngle var restAngle = PI2; var valueSumLargerThanMinAngle = 0; var dir = clockwise ? 1 : -1; /** * Render a tree * @return increased angle */ var renderNode = function (node, startAngle) { if (!node) { return; } var endAngle = startAngle; // Render self if (node !== virtualRoot) { // Tree node is virtual, so it doesn't need to be drawn var value = node.getValue(); var angle = sum === 0 && stillShowZeroSum ? unitRadian : value * unitRadian; if (angle < minAngle) { angle = minAngle; restAngle -= minAngle; } else { valueSumLargerThanMinAngle += value; } endAngle = startAngle + dir * angle; var depth = node.depth - rootDepth - (renderRollupNode ? -1 : 1); var rStart = r0 + rPerLevel * depth; var rEnd = r0 + rPerLevel * (depth + 1); var itemModel = node.getModel(); if (itemModel.get('r0') != null) { rStart = parsePercent(itemModel.get('r0'), size / 2); } if (itemModel.get('r') != null) { rEnd = parsePercent(itemModel.get('r'), size / 2); } node.setLayout({ angle: angle, startAngle: startAngle, endAngle: endAngle, clockwise: clockwise, cx: cx, cy: cy, r0: rStart, r: rEnd }); } // Render children if (node.children && node.children.length) { // currentAngle = startAngle; var siblingAngle = 0; zrUtil.each(node.children, function (node) { siblingAngle += renderNode(node, startAngle + siblingAngle); }); } return endAngle - startAngle; }; // Virtual root node for roll up if (renderRollupNode) { var rStart = r0; var rEnd = r0 + rPerLevel; var angle = Math.PI * 2; virtualRoot.setLayout({ angle: angle, startAngle: startAngle, endAngle: startAngle + angle, clockwise: clockwise, cx: cx, cy: cy, r0: rStart, r: rEnd }); } renderNode(treeRoot, startAngle); }); } /** * Init node children by order and update visual * * @param {TreeNode} node root node * @param {boolean} isAsc if is in ascendant order */ function initChildren(node, isAsc) { var children = node.children || []; node.children = sort(children, isAsc); // Init children recursively if (children.length) { zrUtil.each(node.children, function (child) { initChildren(child, isAsc); }); } } /** * Sort children nodes * * @param {TreeNode[]} children children of node to be sorted * @param {string | function | null} sort sort method * See SunburstSeries.js for details. */ function sort(children, sortOrder) { if (typeof sortOrder === 'function') { return children.sort(sortOrder); } else { var isAsc = sortOrder === 'asc'; return children.sort(function (a, b) { var diff = (a.getValue() - b.getValue()) * (isAsc ? 1 : -1); return diff === 0 ? (a.dataIndex - b.dataIndex) * (isAsc ? -1 : 1) : diff; }); } } module.exports = _default;