<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    TWaver - 專注UI技術(shù)

    http://twaver.servasoft.com/
    posts - 171, comments - 191, trackbacks - 0, articles - 2
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理
    最近有客戶提到自定義鏈路的需求,個(gè)人感覺非常有代表意義,現(xiàn)在共享出來給大家參考一下。先來看看需求:
    1. 鏈路要分成兩半,用兩種顏色填充。
    2. 填充百分比在不同值域時(shí),用不同顏色。
    3. 顯示刻度
    4. 有個(gè)開關(guān),可以控制鏈路變短,變短后,鏈路只畫開始和結(jié)束部分(相當(dāng)于原始鏈路的縮影),中間不畫
    5. 如果有多條鏈路,鏈路合并后兩端分別顯示這些鏈路中的最高填充百分比
    6. 合并前:

      合并后:


    7. 進(jìn)入子網(wǎng)后,節(jié)點(diǎn)上顯示和上層節(jié)點(diǎn)的連線信息
    8. 進(jìn)入子網(wǎng)前,節(jié)點(diǎn)2和子網(wǎng)內(nèi)節(jié)點(diǎn)4之間有鏈路:

      進(jìn)入子網(wǎng)后,節(jié)點(diǎn)4上也顯示此鏈路:

      先看看實(shí)現(xiàn)的效果,后面我們慢慢解釋如何定制鏈路:

    前5個(gè)需求可以通過自定義Link和LinkUI實(shí)現(xiàn),需要注意:
    1. 用Link#getBundleLinks獲取所有的捆綁鏈路
    2. 用LinkUI#drawLinePoints畫線
    完整代碼如下:

      1 // 自定義Link構(gòu)造函數(shù)
      2 demo.ScaleLink = function(id, from, to) {
      3     // 調(diào)用基類構(gòu)造函數(shù)
      4     demo.ScaleLink.superClass.constructor.call(this, id, from, to);
      5     // 設(shè)置鏈路寬度為10個(gè)像素
      6     this.setStyle('link.width', 10);
      7     //this.setStyle('link.color', 'rgba(0, 0, 0, 0)');
      8     // 設(shè)置Link類型為平行
      9     this.setStyle('link.type', 'parallel');
     10     // 設(shè)置鏈路捆綁的間距為40
     11     this.setStyle('link.bundle.offset', 40);
     12     // 設(shè)置刻度顏色
     13     this.setClient('scaleColor', 'black');
     14     // 設(shè)置刻度寬度
     15     this.setClient('scaleWidth', 1);
     16     // 設(shè)置刻度個(gè)數(shù)
     17     this.setClient('scaleNumbers', 4);
     18     // 設(shè)置是否變短
     19     this.setClient('shortened', false);
     20     // 設(shè)置變短后的長(zhǎng)度
     21     this.setClient('shortenLength', 100);
     22     // 設(shè)置分割線顏色
     23     this.setClient('splitterColor', 'black');
     24     // 設(shè)置起始填充百分比
     25     this.setClient('fromFillPercent', 0);
     26     // 設(shè)置結(jié)束填充百分比
     27     this.setClient('toFillPercent', 0);
     28 };
     29 // 設(shè)置自定義Link繼承twaver.Link
     30 twaver.Util.ext('demo.ScaleLink', twaver.Link, {
     31     // 重載獲取UI類方法,返回自定義UI類
     32     getCanvasUIClass : function () {
     33         return demo.ScaleLinkUI;
     34     },
     35     // 根據(jù)百分比獲取填充顏色
     36     getFillColor: function(percent) {
     37         if (percent < 0.25) {
     38             return 'green';
     39         }
     40         if (percent < 0.5) {
     41             return 'yellow';
     42         }
     43         if (percent < 0.75) {
     44             return 'magenta';
     45         }
     46         return 'red';
     47     },
     48     // 獲取起始填充顏色
     49     getFromFillColor: function () {
     50         return this.getFillColor(this.getFromFillPercent());
     51     },
     52     // 獲取結(jié)束填充顏色
     53     getToFillColor: function () {
     54         return this.getFillColor(this.getToFillPercent());
     55     },
     56     // 獲取起始百分比
     57     getFromFillPercent: function () {
     58         // 如果是鏈路捆綁代理,返回所有捆綁鏈路中填充百分比最大的值
     59         if (this.isBundleAgent()) {
     60             var fromAgent = this.getFromAgent(),
     61                 percentKey, maxPercent = 0, percent;
     62             this.getBundleLinks().forEachSiblingLink(function (link) {
     63                 percentKey = fromAgent === link.getFromAgent() ? 'fromFillPercent' : 'toFillPercent';
     64                 percent = link.getClient(percentKey);
     65                 maxPercent = percent > maxPercent ? percent : maxPercent;
     66             });
     67             return maxPercent;
     68         } else {
     69             return this.getClient('fromFillPercent');
     70         }
     71     },
     72     // 獲取結(jié)束百分比
     73     getToFillPercent: function () {
     74         // 如果是鏈路捆綁代理,返回所有捆綁鏈路中填充百分比最大的值
     75         if (this.isBundleAgent()) {
     76             var toAgent = this.getToAgent(),
     77                 percentKey, maxPercent = 0, percent;
     78             this.getBundleLinks().forEachSiblingLink(function (link) {
     79                 percentKey = toAgent === link.getToAgent() ? 'toFillPercent' : 'fromFillPercent';
     80                 percent = link.getClient(percentKey);
     81                 maxPercent = percent > maxPercent ? percent : maxPercent;
     82             });
     83             return maxPercent;
     84         } else {
     85             return this.getClient('toFillPercent');
     86         }
     87     },
     88     // 重載獲取網(wǎng)元名稱方法,判斷如果是鏈路捆綁代理,就返回起始和結(jié)束代理節(jié)點(diǎn)的名稱
     89     getName: function () {
     90         if (this.getClient('shortened')) {
     91             return null;
     92         } else if (this.isBundleAgent()) {
     93             return this.getFromAgent().getName() + '-' + this.getToAgent().getName();
     94         } else {
     95             return demo.ScaleLink.superClass.getName.call(this);
     96         }
     97     }
     98 });
     99 
    100 // 自定義LinkUI構(gòu)造函數(shù)
    101 demo.ScaleLinkUI = function(network, element){
    102     // 調(diào)用基類構(gòu)造函數(shù)
    103     demo.ScaleLinkUI.superClass.constructor.call(this, network, element);
    104 };
    105 // 設(shè)置自定義Link繼承twaver.canvas.LinkUI
    106 twaver.Util.ext('demo.ScaleLinkUI', twaver.canvas.LinkUI, {
    107     // 獲取Link角度
    108     getAngle: function () {
    109         return getAngle(this.getFromPoint(), this.getToPoint());
    110     },
    111     // 獲取Link中間點(diǎn)
    112     getMiddlePoint: function (from, to, percent) {
    113         return {
    114             x: from.x + (to.x - from.x) * percent,
    115             y: from.y + (to.y - from.y) * percent
    116         };
    117     },
    118     // 畫刻度線
    119     drawScaleLine: function (from, to, angle, length, ctx, percent, lineWidth, lineColor) {
    120         var point = this.getMiddlePoint(from, to, percent);
    121         var y = length/2 * Math.sin(angle),
    122             x = length/2 * Math.cos(angle);
    123         ctx.beginPath();
    124         ctx.lineWidth = lineWidth;
    125         ctx.strokeStyle = lineColor;
    126         ctx.moveTo(point.x + x, point.y + y);
    127         ctx.lineTo(point.x - x, point.y -y);
    128         ctx.stroke();
    129     },
    130     // 獲取是否將鏈路變短
    131     isShorten: function () {
    132         var link = this.getElement();
    133         return link.getClient('shortened') && this.getLineLength() > link.getClient('shortenLength') * 2;
    134     },
    135     // 重載畫鏈路函數(shù),用自定義邏輯畫鏈路
    136     paintBody: function (ctx) {
    137         var points = this.getLinkPoints(),
    138             link = this.getElement();
    139         if (!points || points.size() < 2) {
    140             return;
    141         }
    142 
    143         var lineLength = this.getLineLength(),
    144             shortenLength = link.getClient('shortenLength'),
    145             percent = shortenLength / lineLength,
    146             from = points.get(0),
    147             to = points.get(1),
    148             angle = this.getAngle() + Math.PI/2;
    149         if (this.isShorten()) {
    150             fromPoints = new twaver.List([from, this.getMiddlePoint(from, to, percent)]);
    151             toPoints = new twaver.List([this.getMiddlePoint(from, to, 1 - percent), to]);
    152             this._paintBody(ctx, fromPoints, angle);
    153             this._paintBody(ctx, toPoints, angle);
    154 
    155             // 畫文字
    156             ctx.textAlign = 'center';
    157             ctx.textBaseline = 'middle';
    158             ctx.fillStyle = 'black';
    159             var textCenter = {x: (fromPoints.get(0).x + fromPoints.get(1).x)/2, y: (fromPoints.get(0).y + fromPoints.get(1).y)/2};
    160             ctx.fillText(link.getName(), textCenter.x, textCenter.y);
    161 
    162             textCenter = {x: (toPoints.get(0).x + toPoints.get(1).x)/2, y: (toPoints.get(0).y + toPoints.get(1).y)/2};
    163             ctx.fillText(link.getName(), textCenter.x, textCenter.y);
    164 
    165             ctx.fillText(link.getToNode().getName(), fromPoints.get(1).x, fromPoints.get(1).y);
    166             ctx.fillText(link.getFromNode().getName(), toPoints.get(0).x, toPoints.get(0).y);
    167         } else {
    168             this._paintBody(ctx, points, angle);
    169         }
    170 
    171         // 畫起始箭頭
    172         if (link.getClient('arrow.from')) {
    173             twaver.Util.drawArrow(ctx, 12, 9, points, true, 'arrow.standard', true, 'gray', 0, 0, 1, 'black');
    174         }
    175         // 畫結(jié)束箭頭
    176         if (link.getClient('arrow.to')) {
    177             twaver.Util.drawArrow(ctx, 12, 9, points, false, 'arrow.standard', true, 'gray', 0, 0, 1, 'black');
    178         }
    179     },
    180     _paintBody: function (ctx, points, angle) {
    181         var link = this.getElement(),
    182             width = link.getStyle('link.width'),
    183             grow = width,
    184             outerColor = this.getOuterColor();
    185         if (outerColor) {
    186             var outerWidth = link.getStyle('outer.width');
    187             grow += outerWidth * 2;
    188         }
    189         var selectBorder = !this.getEditAttachment() && link.getStyle('select.style') === 'border' && this.getNetwork().isSelected(link);
    190         if (selectBorder) {
    191             var selectWidth = link.getStyle('select.width');
    192             grow += selectWidth * 2;
    193         }
    194         ctx.lineCap = link.getStyle('link.cap');
    195         ctx.lineJoin = link.getStyle('link.join');
    196         // 畫選中邊框
    197         if (selectBorder) {
    198             this.drawLinePoints(ctx, points, grow, link.getStyle('select.color'));
    199         }
    200         // 畫邊框
    201         if (outerColor) {
    202             this.drawLinePoints(ctx, points, width + outerWidth * 2, outerColor);
    203         }
    204         // 畫Link
    205         this.drawLinePoints(ctx, points, width, this.getInnerColor() || link.getStyle('link.color'));
    206 
    207         var fromFillPercent = link.getFromFillPercent(),
    208             toFillPercent = link.getToFillPercent(),
    209             fromFillColor = link.getFromFillColor(),
    210             toFillColor = link.getToFillColor(),
    211             from = points.get(0),
    212             to = points.get(1);
    213 
    214         var x = from.x + (to.x - from.x) / 2 * fromFillPercent,
    215             y = from.y + (to.y - from.y) / 2 * fromFillPercent;
    216         var middle = {x: x, y: y};
    217         var fromPoints = new twaver.List([from, middle]);
    218         // 畫起始填充色
    219         this.drawLinePoints(ctx, fromPoints, width, fromFillColor);
    220 
    221         from = points.get(1);
    222         to = points.get(0);
    223         x = from.x + (to.x - from.x) / 2 * toFillPercent;
    224         y = from.y + (to.y - from.y) / 2 * toFillPercent;
    225         middle = {x: x, y: y};
    226         var toPoints = new twaver.List([from, middle]);
    227         // 畫結(jié)束填充色
    228         this.drawLinePoints(ctx, toPoints, width, toFillColor);
    229 
    230         from = points.get(0);
    231         to = points.get(1);
    232         var scaleWidth = link.getClient('scaleWidth'),
    233             scaleColor = link.getClient('scaleColor');
    234         // 畫刻度
    235         for (var i = 1, n = link.getClient('scaleNumbers') * 2; i < n; i++) {
    236             this.drawScaleLine(from, to, angle, width/2, ctx, i/n, scaleWidth, scaleColor);
    237         }
    238         // 畫分隔線
    239         this.drawScaleLine(from, to, angle, width, ctx, 0.5, 3, link.getClient('splitterColor'));
    240     }
    241 });

    最后一個(gè)需求可以通過定制Node和NodeUI達(dá)到目的:

      1 // 自定義Node構(gòu)造函數(shù)
      2 demo.ScaleNode = function(id) {
      3     // 調(diào)用基類構(gòu)造函數(shù)
      4     demo.ScaleNode.superClass.constructor.call(this, id);
      5 };
      6 // 設(shè)置自定義Node繼承twaver.Node
      7 twaver.Util.ext('demo.ScaleNode', twaver.Node, {
      8     getCanvasUIClass: function () {
      9         return demo.ScaleNodeUI;
     10     }
     11 });
     12 
     13 // 自定義NodeUI構(gòu)造函數(shù)
     14 demo.ScaleNodeUI = function(network, element){
     15     // 調(diào)用基類構(gòu)造函數(shù)
     16     demo.ScaleNodeUI.superClass.constructor.call(this, network, element);
     17 };
     18 // 設(shè)置自定義NodeUI繼承twaver.canvas.NodeUI
     19 twaver.Util.ext('demo.ScaleNodeUI', twaver.canvas.NodeUI, {
     20     // 重載畫網(wǎng)元方法,畫上層鏈路
     21     paintBody: function (ctx) {
     22         demo.ScaleNodeUI.superClass.paintBody.call(this, ctx);
     23         var result = this.getAttachedLinks();
     24         if (!result) {
     25             return;
     26         }
     27         for (var position in result) {
     28             this.paintLink(ctx, result[position], position);
     29         }
     30     },
     31     // 畫鏈路
     32     paintLink: function (ctx, links, position) {
     33         var center = this.getElement().getCenterLocation(),
     34             count = links.length,
     35             half = count / 2,
     36             network = this.getNetwork(),
     37             gap = (count - 1) * -10,
     38             terminal, link, i, offset, shortenLength, angle, tempCenter, textWidth, textHeight = 20, textCenter;
     39         for (i=0; i<count; i++) {
     40             link = links[i];
     41             offset = link.getStyle('link.bundle.offset');
     42             shortenLength = link.getClient('shortenLength');
     43             textWidth = ctx.measureText(link.getName()).width;
     44             if (position === 'left') {
     45                 terminal = {x: center.x - offset - shortenLength, y: center.y + gap};
     46                 tempCenter = {x: center.x - offset, y: center.y + gap};
     47                 textCenter = {x: terminal.x - textWidth/2 - 10, y: terminal.y};
     48                 angle = Math.PI/2;
     49             } else if (position === 'right') {
     50                 terminal = {x: center.x + offset + shortenLength, y: center.y + gap};
     51                 tempCenter = {x: center.x + offset, y: center.y + gap};
     52                 textCenter = {x: terminal.x + textWidth/2 + 10, y: terminal.y};
     53                 angle = Math.PI/2;
     54             } else if (position === 'top') {
     55                 terminal = {x: center.x + gap, y: center.y - offset - shortenLength};
     56                 tempCenter = {x: center.x + gap, y: center.y - offset};
     57                 textCenter = {x: terminal.x, y: terminal.y - 10};
     58                 angle = 0;
     59             } else {
     60                 terminal = {x: center.x + gap, y: center.y + offset + shortenLength};
     61                 tempCenter = {x: center.x + gap, y: center.y + offset};
     62                 textCenter = {x: terminal.x, y: terminal.y + 10};
     63                 angle = 0;
     64             }
     65             gap += 20;
     66             var isFrom = link.getFromNode() === this.getElement(),
     67                 points;
     68             if (isFrom) {
     69                 points = new twaver.List([tempCenter, terminal]);
     70             } else {
     71                 points = new twaver.List([terminal, tempCenter]);
     72             }
     73             network.getElementUI(link)._paintBody(ctx, points, angle);
     74 
     75             ctx.textAlign = 'center';
     76             ctx.textBaseline = 'middle';
     77             ctx.fillStyle = 'black';
     78             // 另一端節(jié)點(diǎn)標(biāo)簽
     79             var name = isFrom ? link.getToNode().getName() : link.getFromNode().getName();
     80             ctx.fillText(name, textCenter.x, textCenter.y);
     81             textCenter = {x: (tempCenter.x + terminal.x)/2, y: (tempCenter.y + terminal.y)/2};
     82             // Link標(biāo)簽
     83             ctx.fillText(link.getName(), textCenter.x, textCenter.y);
     84 
     85             // 畫起始箭頭
     86             if (link.getClient('arrow.from')) {
     87                 twaver.Util.drawArrow(ctx, 12, 9, points, true, 'arrow.standard', true, 'gray', 0, 0, 1, 'black');
     88             }
     89             // 畫結(jié)束箭頭
     90             if (link.getClient('arrow.to')) {
     91                 twaver.Util.drawArrow(ctx, 12, 9, points, false, 'arrow.standard', true, 'gray', 0, 0, 1, 'black');
     92             }
     93         }
     94     },
     95     // 獲取不同方位的上層鏈路集合
     96     getAttachedLinks: function () {
     97         var currentSubNetwork = this.getNetwork().getCurrentSubNetwork();
     98         if (!currentSubNetwork || !this.getElement().getLinks()) {
     99             return null;
    100         }
    101         var result;
    102         this.getElement().getLinks().forEach(function (link) {
    103             var fromSubNetwork = twaver.Util.getSubNetwork(link.getFromNode()),
    104                 toSubNetwork = twaver.Util.getSubNetwork(link.getToNode());
    105             if (fromSubNetwork !== toSubNetwork) {
    106                 if (!result) {
    107                     result = {};
    108                 }
    109                 var fromCenter = link.getFromNode().getCenterLocation(),
    110                     toCenter = link.getToNode().getCenterLocation(),
    111                     angle = getAngle(fromCenter, toCenter),
    112                     isOut = currentSubNetwork === fromSubNetwork,
    113                     position;
    114                 if (isOut) {
    115                     if (fromCenter.x <= toCenter.x) {
    116                         if (angle >= -Math.PI/4 && angle <= Math.PI/4) {
    117                             position = 'right';
    118                         } else if (angle > Math.PI/4) {
    119                             position = 'bottom';
    120                         } else {
    121                             position = 'top';
    122                         }
    123                     } else {
    124                         if (angle >= -Math.PI/4 && angle <= Math.PI/4) {
    125                             position = 'left';
    126                         } else if (angle > Math.PI/4) {
    127                             position = 'top';
    128                         } else {
    129                             position = 'bottom';
    130                         }
    131                     }
    132                 } else {
    133                     if (fromCenter.x <= toCenter.x) {
    134                         if (angle >= -Math.PI/4 && angle <= Math.PI/4) {
    135                             position = 'left';
    136                         } else if (angle > Math.PI/4) {
    137                             position = 'top';
    138                         } else {
    139                             position = 'bottom';
    140                         }
    141                     } else {
    142                         if (angle >= -Math.PI/4 && angle <= Math.PI/4) {
    143                             position = 'right';
    144                         } else if (angle > Math.PI/4) {
    145                             position = 'bottom';
    146                         } else {
    147                             position = 'top';
    148                         }
    149                     }
    150                 }
    151                 if (!result[position]) {
    152                     result[position] = [];
    153                 }
    154                 result[position].push(link);
    155             }
    156         });
    157         return result;
    158     }
    159 });

     本文完整代碼見附件:見原文最下方

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲精品国精品久久99热一| 亚洲M码 欧洲S码SSS222| 日韩免费视频网站| 亚洲毛片av日韩av无码| 亚洲精品成人网站在线观看| 亚洲综合精品香蕉久久网97| 亚洲久悠悠色悠在线播放| 综合一区自拍亚洲综合图区 | 亚洲欧洲日产国产综合网| 亚洲图片一区二区| 亚洲天然素人无码专区| yellow视频免费看| 18pao国产成视频永久免费| 四虎成人免费网站在线| 久久亚洲国产成人精品无码区| 亚洲人成亚洲精品| 亚洲欧美综合精品成人导航| a毛片成人免费全部播放| 久久久久免费看成人影片| 啦啦啦在线免费视频| 国产亚洲成av片在线观看| 亚洲国产成人久久综合一区| 在线观看亚洲免费| 久草免费福利资源站| 日韩伦理片电影在线免费观看| 亚洲午夜久久久久妓女影院| 亚洲av无码国产综合专区| 日韩在线观看免费完整版视频| 国内永久免费crm系统z在线| 一个人免费观看www视频在线| 亚洲国产日韩成人综合天堂| 亚洲最大的视频网站| 一级视频在线免费观看| 曰曰鲁夜夜免费播放视频| 在线亚洲精品自拍| 亚洲色精品三区二区一区| 久久国产精品免费视频| 国产在线19禁免费观看国产| 中文字幕在线观看亚洲| 一个人看的www免费高清| 天天摸夜夜摸成人免费视频|