123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- /*
- * 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 textContain = require("zrender/lib/contain/text");
- var _number = require("../../util/number");
- var parsePercent = _number.parsePercent;
- /*
- * 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.
- */
- // FIXME emphasis label position is not same with normal label position
- var RADIAN = Math.PI / 180;
- function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight, viewLeft, viewTop, farthestX) {
- list.sort(function (a, b) {
- return a.y - b.y;
- });
- function shiftDown(start, end, delta, dir) {
- for (var j = start; j < end; j++) {
- if (list[j].y + delta > viewTop + viewHeight) {
- break;
- }
- list[j].y += delta;
- if (j > start && j + 1 < end && list[j + 1].y > list[j].y + list[j].height) {
- shiftUp(j, delta / 2);
- return;
- }
- }
- shiftUp(end - 1, delta / 2);
- }
- function shiftUp(end, delta) {
- for (var j = end; j >= 0; j--) {
- if (list[j].y - delta < viewTop) {
- break;
- }
- list[j].y -= delta;
- if (j > 0 && list[j].y > list[j - 1].y + list[j - 1].height) {
- break;
- }
- }
- }
- function changeX(list, isDownList, cx, cy, r, dir) {
- var lastDeltaX = dir > 0 ? isDownList // right-side
- ? Number.MAX_VALUE // down
- : 0 // up
- : isDownList // left-side
- ? Number.MAX_VALUE // down
- : 0; // up
- for (var i = 0, l = list.length; i < l; i++) {
- if (list[i].labelAlignTo !== 'none') {
- continue;
- }
- var deltaY = Math.abs(list[i].y - cy);
- var length = list[i].len;
- var length2 = list[i].len2;
- var deltaX = deltaY < r + length ? Math.sqrt((r + length + length2) * (r + length + length2) - deltaY * deltaY) : Math.abs(list[i].x - cx);
- if (isDownList && deltaX >= lastDeltaX) {
- // right-down, left-down
- deltaX = lastDeltaX - 10;
- }
- if (!isDownList && deltaX <= lastDeltaX) {
- // right-up, left-up
- deltaX = lastDeltaX + 10;
- }
- list[i].x = cx + deltaX * dir;
- lastDeltaX = deltaX;
- }
- }
- var lastY = 0;
- var delta;
- var len = list.length;
- var upList = [];
- var downList = [];
- for (var i = 0; i < len; i++) {
- if (list[i].position === 'outer' && list[i].labelAlignTo === 'labelLine') {
- var dx = list[i].x - farthestX;
- list[i].linePoints[1][0] += dx;
- list[i].x = farthestX;
- }
- delta = list[i].y - lastY;
- if (delta < 0) {
- shiftDown(i, len, -delta, dir);
- }
- lastY = list[i].y + list[i].height;
- }
- if (viewHeight - lastY < 0) {
- shiftUp(len - 1, lastY - viewHeight);
- }
- for (var i = 0; i < len; i++) {
- if (list[i].y >= cy) {
- downList.push(list[i]);
- } else {
- upList.push(list[i]);
- }
- }
- changeX(upList, false, cx, cy, r, dir);
- changeX(downList, true, cx, cy, r, dir);
- }
- function avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight, viewLeft, viewTop) {
- var leftList = [];
- var rightList = [];
- var leftmostX = Number.MAX_VALUE;
- var rightmostX = -Number.MAX_VALUE;
- for (var i = 0; i < labelLayoutList.length; i++) {
- if (isPositionCenter(labelLayoutList[i])) {
- continue;
- }
- if (labelLayoutList[i].x < cx) {
- leftmostX = Math.min(leftmostX, labelLayoutList[i].x);
- leftList.push(labelLayoutList[i]);
- } else {
- rightmostX = Math.max(rightmostX, labelLayoutList[i].x);
- rightList.push(labelLayoutList[i]);
- }
- }
- adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight, viewLeft, viewTop, rightmostX);
- adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight, viewLeft, viewTop, leftmostX);
- for (var i = 0; i < labelLayoutList.length; i++) {
- var layout = labelLayoutList[i];
- if (isPositionCenter(layout)) {
- continue;
- }
- var linePoints = layout.linePoints;
- if (linePoints) {
- var isAlignToEdge = layout.labelAlignTo === 'edge';
- var realTextWidth = layout.textRect.width;
- var targetTextWidth;
- if (isAlignToEdge) {
- if (layout.x < cx) {
- targetTextWidth = linePoints[2][0] - layout.labelDistance - viewLeft - layout.labelMargin;
- } else {
- targetTextWidth = viewLeft + viewWidth - layout.labelMargin - linePoints[2][0] - layout.labelDistance;
- }
- } else {
- if (layout.x < cx) {
- targetTextWidth = layout.x - viewLeft - layout.bleedMargin;
- } else {
- targetTextWidth = viewLeft + viewWidth - layout.x - layout.bleedMargin;
- }
- }
- if (targetTextWidth < layout.textRect.width) {
- layout.text = textContain.truncateText(layout.text, targetTextWidth, layout.font);
- if (layout.labelAlignTo === 'edge') {
- realTextWidth = textContain.getWidth(layout.text, layout.font);
- }
- }
- var dist = linePoints[1][0] - linePoints[2][0];
- if (isAlignToEdge) {
- if (layout.x < cx) {
- linePoints[2][0] = viewLeft + layout.labelMargin + realTextWidth + layout.labelDistance;
- } else {
- linePoints[2][0] = viewLeft + viewWidth - layout.labelMargin - realTextWidth - layout.labelDistance;
- }
- } else {
- if (layout.x < cx) {
- linePoints[2][0] = layout.x + layout.labelDistance;
- } else {
- linePoints[2][0] = layout.x - layout.labelDistance;
- }
- linePoints[1][0] = linePoints[2][0] + dist;
- }
- linePoints[1][1] = linePoints[2][1] = layout.y;
- }
- }
- }
- function isPositionCenter(layout) {
- // Not change x for center label
- return layout.position === 'center';
- }
- function _default(seriesModel, r, viewWidth, viewHeight, viewLeft, viewTop) {
- var data = seriesModel.getData();
- var labelLayoutList = [];
- var cx;
- var cy;
- var hasLabelRotate = false;
- var minShowLabelRadian = (seriesModel.get('minShowLabelAngle') || 0) * RADIAN;
- data.each(function (idx) {
- var layout = data.getItemLayout(idx);
- var itemModel = data.getItemModel(idx);
- var labelModel = itemModel.getModel('label'); // Use position in normal or emphasis
- var labelPosition = labelModel.get('position') || itemModel.get('emphasis.label.position');
- var labelDistance = labelModel.get('distanceToLabelLine');
- var labelAlignTo = labelModel.get('alignTo');
- var labelMargin = parsePercent(labelModel.get('margin'), viewWidth);
- var bleedMargin = labelModel.get('bleedMargin');
- var font = labelModel.getFont();
- var labelLineModel = itemModel.getModel('labelLine');
- var labelLineLen = labelLineModel.get('length');
- labelLineLen = parsePercent(labelLineLen, viewWidth);
- var labelLineLen2 = labelLineModel.get('length2');
- labelLineLen2 = parsePercent(labelLineLen2, viewWidth);
- if (layout.angle < minShowLabelRadian) {
- return;
- }
- var midAngle = (layout.startAngle + layout.endAngle) / 2;
- var dx = Math.cos(midAngle);
- var dy = Math.sin(midAngle);
- var textX;
- var textY;
- var linePoints;
- var textAlign;
- cx = layout.cx;
- cy = layout.cy;
- var text = seriesModel.getFormattedLabel(idx, 'normal') || data.getName(idx);
- var textRect = textContain.getBoundingRect(text, font, textAlign, 'top');
- var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner';
- if (labelPosition === 'center') {
- textX = layout.cx;
- textY = layout.cy;
- textAlign = 'center';
- } else {
- var x1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dx : layout.r * dx) + cx;
- var y1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dy : layout.r * dy) + cy;
- textX = x1 + dx * 3;
- textY = y1 + dy * 3;
- if (!isLabelInside) {
- // For roseType
- var x2 = x1 + dx * (labelLineLen + r - layout.r);
- var y2 = y1 + dy * (labelLineLen + r - layout.r);
- var x3 = x2 + (dx < 0 ? -1 : 1) * labelLineLen2;
- var y3 = y2;
- if (labelAlignTo === 'edge') {
- // Adjust textX because text align of edge is opposite
- textX = dx < 0 ? viewLeft + labelMargin : viewLeft + viewWidth - labelMargin;
- } else {
- textX = x3 + (dx < 0 ? -labelDistance : labelDistance);
- }
- textY = y3;
- linePoints = [[x1, y1], [x2, y2], [x3, y3]];
- }
- textAlign = isLabelInside ? 'center' : labelAlignTo === 'edge' ? dx > 0 ? 'right' : 'left' : dx > 0 ? 'left' : 'right';
- }
- var labelRotate;
- var rotate = labelModel.get('rotate');
- if (typeof rotate === 'number') {
- labelRotate = rotate * (Math.PI / 180);
- } else {
- labelRotate = rotate ? dx < 0 ? -midAngle + Math.PI : -midAngle : 0;
- }
- hasLabelRotate = !!labelRotate;
- layout.label = {
- x: textX,
- y: textY,
- position: labelPosition,
- height: textRect.height,
- len: labelLineLen,
- len2: labelLineLen2,
- linePoints: linePoints,
- textAlign: textAlign,
- verticalAlign: 'middle',
- rotation: labelRotate,
- inside: isLabelInside,
- labelDistance: labelDistance,
- labelAlignTo: labelAlignTo,
- labelMargin: labelMargin,
- bleedMargin: bleedMargin,
- textRect: textRect,
- text: text,
- font: font
- }; // Not layout the inside label
- if (!isLabelInside) {
- labelLayoutList.push(layout.label);
- }
- });
- if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) {
- avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight, viewLeft, viewTop);
- }
- }
- module.exports = _default;
|