milestone相关前端控件的设计方案

网友投稿 667 2022-05-30

原来的需求是模拟visio里面做出来的时间线的效果,所以我就做成了下面那种方案;这几天闲逛,看到别人做的不错的设计,我这里记下来;

我初步看了一下前端代码绘制部分基于svg d3.js;

milestone相关前端控件的设计方案

下面我来说说我认为他的这种设计到底好在哪里,从用户视角:

采用明显的颜色来区分,已完成迭代,当前迭代,未开始迭代

虽然我那个设计中也采用了颜色进行状态区分,但是线条小,视觉上不如这个明显;

环形的进度显示相对于单纯的百分比数值显示更能聚焦人的注意力,

不仅记录进度还加入了相关的代码量和工作量记录,将用户可能关注的相关要素集中呈现,避免二次对照的过程;

当区段的长度相对小时,隐藏了代码量部分的显示,改成了鼠标浮动时显示完整信息;

鼠标浮动于当前时间点是,提示总体的一些进度和汇总信息;

还可以注意到一些这样细节,同一段的的斜杠前后的字体大小或者颜色的变化的设计,都一样或者过于整齐的设计容易让人产生视觉疲劳;

其他的一些点,状态图的信息提示栏提供了更详细的描述信息;

采用了更多的进度和趋势的图形辅助,更直观明了;

还有一个我认为不错的特点,右上角的播放循环展板的功能;

看了一下这个项目的前端公共依赖:

echarts.js

EventEmitter.min.js//EventEmitter v5.2.5

jquery-3.3.1.min.js//jQuery v3.3.1

jquery-ui.min.js//jQuery UI - v1.11.0

jquery.gridly.js//1.2.9

bootstrap.min.js//Bootstrap v3.3.7

Bootstrap: popover.js v3.2.0

Bootstrap: tooltip.js v3.2.0

bootstrap-slider.min.js//10.0.2

pnotify.js

bootstrap-table.js//1.12.1

jquery.dataTables.js//DataTables 1.10.4

dataTables.bootstrap.js

dataTables.rowsGroup.js//RowsGroup for DataTables v2.0.0

ColVis.min.js//1.0.8

DT_bootstrap.js

ckeditor.js//2003-2018

ckeditor/styles.js

ckeditor/lang/zh-cn.js

d3.js//3.2.8

jqPaginator.js

select2.min.js

bootstrap-multiselect.js//Bootstrap Multiselect v0.9.8

基本上是使用jquery+bootstrap的前端结构,并没有使用一些当前流行的前端框架,但是代码逻辑还是清晰的;

/*-------------------------------------------------------------------------------------------------*/

less教程

https://www.ibm.com/developerworks/cn/web/1207_zhaoch_lesscss/

交互设计文档设计的一些查询记录

https://cloud.tencent.com/developer/article/1165820

https://www.cnblogs.com/JoannaQ/p/3900463.html

https://www.ctolib.com/topics-36574.html

https://zhuanlan.zhihu.com/p/21577848

http://www.yzsekj.com/cn_asp/m_newsview.asp%3Ftypeid%3D60%26id%3D83

https://wemp.app/posts/7b00dafd-a935-4c9a-a6cb-0bc0587ce6de

/*--------------------------------------------------------------------------------------------------*/

/*------------------------------------分割线-----------------------------------------------------*/

/*-------------------------------------------------------------------------------------------------*/

基于angularjs和mxgraph的里程碑计划控件

控件效果:

控件实现:

首先下载 :https://github.com/jgraph/mxgraph 最新的版本

需要其中的mxgraph-master\javaScript\examples\grapheditor\www目录中的所有和src中的mxClient.js文件,

控件模板:

mxBasePath = '/Resources/mx/'; STYLE_PATH = '/resources/mx/styles'; RESOURCES_PATH = '/resources/mx/resources'; STENCIL_PATH = '/resources/mx/stencils'; var mile_ui = null; function drawInit(xml){     var editorUiInit = EditorUi.prototype.init;     EditorUi.prototype.init = function(){      ....     }; mxResources.loadDefaultBundle = false; var bundle = mxResources.getDefaultBundle(RESOURCE_BASE, mxLanguage) || mxResources.getSpecialBundle(RESOURCE_BASE, mxLanguage); mxUtils.getAll([bundle, STYLE_PATH + '/default.xml'], function(xhr) { .... // Main mile_ui = new EditorUi(new Editor(urlParams['chrome'] == '0', themes),document.getElementById('eContainer')); updateDraw(xml); //sco["htm"]=$('#eContainer').html(); }, function() { .... }); } function updateDraw(xml){ mile_ui.editor.graph.model.beginUpdate();         try { var doc = mxUtils.parseXml(xml); mile_ui.editor.graph.resizeContainer = true; mile_ui.editor.setGraphXml(doc.documentElement); mile_ui.editor.graph.centerZoom = false; mile_ui.editor.graph.setTooltips(false); mile_ui.editor.graph.setEnabled(false); mile_ui.editor.graph.resizeContainer = false;         } catch (e) {             console.error(e);         } finally {             mile_ui.editor.graph.model.endUpdate();         } }     年     {{year}}     操作    月    {{month}}   {{tData.title}} 添加

更新
//这里要注意这里$index 如果放到里面回合checkbox扩展的相关功能冲突,$index始终为用tdata为参数始终为第一个的问题 //同时写在外层也会有触发两次的问题使用preventdefeat处理 显示计划
  显示实际
....
.....

控制器:

angular.module('xxx.milestone', []).component('mview', {     controller: ['$scope', '$http', '$window', '$stateParams', '$timeout','$compile', 'xxxService', function($scope, $http, $window, $stateParams, $timeout,$compile, xxxService) { var tid = 0;         var oldtid = tid; Object.defineProperty(this, 'tid', { get: function() {   return tid; }, set: function(newVal) { if(oldtid!=0 && oldtid == newVal){ return; } oldtid = newVal; tid = newVal; console.log('tid changed:', newVal); $scope.timelineId = tid; $scope.initData(); } });         var contextpath = window.Ruban.contextPath;         $scope.RangeYear = [];         $scope.RangeMonth = [];         $scope.timelineData = [];         $scope.addMile = {};         $scope.xml = "";         $scope.timelineId = 1;         $scope.initDraw = false;         $scope.ht = 300;         $scope.contentRestore = {};         $scope.initData = function () { var param = {                 "timelineId": $scope.timelineId             };             $scope.ht = $scope.timelineId.split(",").length * 300; var url = contextpath + 'api/private/xxxx/getTimeline.json'; xxxService.commonPostJQlike(url, param, function (response) {                 if(!response.data.success){                    window.location.href=contextpath +"xxxHome.html#!/error";                    return;                 }                 $scope.timelineData = response.data.data;                 $scope.xml = response.data.xml;             var bgDate = new Date($scope.timelineData[0].bg);             var edDate = new Date($scope.timelineData[0].ed);             $scope.RangeYear = [];             $scope.RangeMonth = [];             for(var i = bgDate.getFullYear();i < edDate.getFullYear();++i){             $scope.RangeYear.push(i);             for(var j=1;j<=12;++j){             $scope.RangeMonth.push(j);             }             }             if($scope.RangeMonth.indexOf(edDate.getFullYear())==-1){             $scope.RangeYear.push(edDate.getFullYear());             for(var j=1;j<=12;++j){             $scope.RangeMonth.push(j);             }             }             $timeout(function() {             if($scope.initDraw==false){//attan             drawInit($scope.xml);             $scope.initDraw = true;             }else{             //$('#eContainer').html($scope.contentRestore["htm"]);             drawInit($scope.xml);//updateDraw--pro in this scene             //这里不用updateDraw是因为当控件在ng-repeat中显示的时候,angularjs刷新子元素的一些过程导致开始的mxgraph绑定失效             }             date();             });                    });         }; $scope.addMileStone = function(e,cid) { e.preventDefault(); $scope.currentStone = $scope.timelineData[cid]; $scope.addMile = {}; $("#addMileModal").modal(); }; $scope.submitMileAdd = function() { $("#add_mile").attr("disabled", "disabled");     var req = {     "timelineId":$scope.currentStone.id,     "addMile.planDesc":$scope.addMile.planDesc,     "addMile.planDate":$scope.addMile.planDate         };     var url=contextpath+"api/private/xxxxx/addMileView.json";     xxxService.commonPostJson(url,req,function () {     ....     }); }; $scope.updateMileStone = function(e,cid) { e.preventDefault(); $scope.currentStone = $scope.timelineData[cid]; $timeout(function() {             date();//用于刷新新增的日期控件功能             });      $("#updateMileModal").modal(); }; $scope.submitMileUpdate = function() { $("#update_mile").attr("disabled", "disabled");     var req = {     "timelineId":$scope.currentStone.id,     "milestone":$scope.currentStone.milestone,     "title":$scope.currentStone.title         };     var url=contextpath+"api/private/xxxxx/updateMileView.json";     xxxService.commonPostJson(url,req,function () {     ....     }); }; $scope.showPlan  = function(e,cid) { e.preventDefault(); //console.log(cid); maybe syli double $scope.currentStone = $scope.timelineData[cid];     var req = {     "timelineId":$scope.currentStone.id,     "showplan":!$scope.currentStone.showplan         };     var url=contextpath+"api/private/xxxxx/updateMileView.json";     xxxService.commonPostJson(url,req,function () {     ....     }); }; $scope.showAct  = function(e,cid) { e.preventDefault(); $scope.currentStone = $scope.timelineData[cid];     var req = {     "timelineId":$scope.currentStone.id,     "showact":!$scope.currentStone.showact         };     var url=contextpath+"api/private/xxxx/updateMileView.json";     xxxService.commonPostJson(url,req,function () {     ....     }); }; }],     controllerAs: 'MilestoneController',     templateUrl: window.Ruban.contextPath+'pages/xxxx/milestone.html',     bindings: {         tid: '@'     } });

使用形式:

    //timelineId来自springcontrol绑定形式为以,分割的timelineId

后端的一些实现:

主要是使用dom4j写了一个MxGraphService的类来对显示到前端的mxgraph绘制对应的xml文件,

public static String formatXmlByInfo(List> drawParam);

//说明根据数据库中由timelineId查询到对应的里程碑信息来请求格式化绘图xml节点信息

public static List formatMileLine(int id[],int y);

//id 为用来递增为绘图图元的id,该函数用来格式化返回最基本的中间的时间线

public static List formatToday(int id[],int x,int y,int parent);

//返回指示当前日期的位置图元

public static List formatMilestone(int id[],int x,int y,Map info,String color,int parent);

//返回计划里程碑图元

public static List formatMilestoneD(int id[],int x,int y,Map info,String color,int parent);

//返回实际完成时间点图元

说明:上面的格式化过程其实很简单,具体是解析参数化过后的样本结构xml获得相应的xml节点返回,注意返回的xml Node需要clone以便添加到最终的根节点;

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:大神带你实现 NLP 从入门到获奖,还有免费算力可以薅!
下一篇:使用podspec创建iOS插件
相关文章