Я одержим псевдо-декларативной стороной Angular. Создание HTML Turing-complete было гениальным ходом. Чтобы проверить теорию и найти что-то действительно полезное, я подумал, что сдую пыль с чего-то другого, что Мишко создал в прошлом …
Совершить пузыри!
Мишко Хевери написал приложение ActionScript, которое показало энтузиазм в тестировании разработчиков в команде. Ранее он работал в Adobe и был достаточно опытным в экосистеме Flash. Я уверен, что он забыл многое из этого, учитывая, насколько важным и трудоемким стал Angular. Об этом рассказывал бывший ThoughtWorker Джон Уолтер . Я думаю, что Джон даже помог Мишко развить его пару лет назад. У нас есть только скриншоты оригинального приложения:
Во всяком случае, мы воссоздали его в Angular как командную работу после работы. Честно говоря, это также инструмент обучения Angular для новичков в нем, и я переключаюсь между «владельцем продукта» и «угловым кодером» по мере необходимости. Это также послужило руководством для SVG.
Если у вас IE 10 или выше, вы можете поиграть с ним здесь (и на мобильном телефоне): http://paul-hammant.github.io/angular-commit-bubbles/commits.html
Флажки и кнопки работают. Они удаляют (или добавляют обратно) коммиттеры, так что вы можете найти лучшего исполнителя (или худшего, или обоих). Вы также можете нажать на пузырьки для наложения, показывая больше информации о коммите. Это только jpeg выше, так что не расстраивайтесь, если вы нажали на него. Настоящая сделка здесь
В реализации у нас есть преднамеренная нефункциональная цель: как будет выглядеть решение с наименьшим количеством возможных строк JavaScript. Источник здесь , но для вашего удобства здесь тоже:
<!DOCTYPE html> <html> <head> <meta content="text/html;charset=utf-8" http-equiv="Content-Type"> <meta content="utf-8" http-equiv="encoding"> <title>Commit Bubbles</title> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.min.js"></script> <script src="http://underscorejs.org/underscore-min.js"></script> <script src="http://vitalets.github.io/checklist-model/checklist-model.js"></script> <script src="http://momentjs.com/downloads/moment.min.js"></script> <script> var app = angular.module("app", ["checklist-model"]); app.controller('CommitBubbles', function ($scope) { $scope.c = { chartHeight: 680, topMargin: 100, colors: ["#FFA07A","#20B2AA","#778899","#B0C4DE","#F5F5DC","#00FF00","#000000","#32CD32","#FAF0E6","#0000FF","#FF00FF","#8A2BE2","#800000","#A52A2A","#66CDAA","#DEB887","#0000CD","#5F9EA0","#7FFF00","#9370DB","#D2691E","#FF7F50","#7B68EE","#6495ED","#48D1CC","#DC143C","#C71585","#00FFFF","#191970","#00008B","#F5FFFA","#008B8B","#FFE4E1","#B8860B","#A9A9A9","#006400","#000080","#BDB76B","#8B008B","#808000","#6B8E23","#FF8C00","#FFA500","#9932CC","#FF4500","#8B0000","#DA70D6","#E9967A","#EEE8AA","#8FBC8F","#98FB98","#483D8B","#AFEEEE","#2F4F4F","#DB7093","#00CED1","#9400D3","#FFDAB9","#FF1493","#CD853F","#00BFFF","#FFC0CB","#696969","#DDA0DD","#1E90FF","#B0E0E6","#B22222","#800080","#FFFAF0","#FF0000","#228B22","#BC8F8F","#FF00FF","#4169E1","#DCDCDC","#FA8072","#FFD700","#FAA460","#DAA520","#2E8B57","#808080","#008000","#A0522D","#ADFF2F","#C0C0C0","#87CEEB","#FF69B4","#6A5ACD","#CD5C5C","#708090","#4B0082","#00FF7F","#F0E68C","#4682B4","#E6E6FA","#D2B48C","#008080","#7CFC00","#D8BFD8","#FFFACD","#FF6347","#ADD8E6","#40E0D0","#F08080","#EE82EE","#F5DEB3","#FAFAD2","#90EE90","#D3D3D3","#FFFF00","#FFB6C1"] }; $scope.commits = [ { ts:1288202623006, hash:"1234567890", testPercentage:100, size:55, author:"John Doe" }, { ts:1288121623006, hash:"13432435645", testPercentage:30, size:81, author:"John Doe" }, { ts:1288128023006, hash:"12232435645", testPercentage:50, size:50, author:"Hector" }, { ts:1288202823006, hash:"12332343455", testPercentage:55, size:50, author:"Hector" }, { ts:1288323623006, hash:"2342342344", testPercentage:15, size:22, author:"Mildred" } ]; $scope.authors = _.uniq(_.pluck($scope.commits, 'author')); $scope.selected = { authors: $scope.authors.slice(0) }; $scope.from = _.min($scope.commits, "ts").ts; $scope.to = _.max($scope.commits, "ts").ts; $scope.timeSpan = moment.duration(moment($scope.from).diff(moment($scope.to))).humanize(); $scope.checkAllAuthors = function() { $scope.selected.authors = angular.copy($scope.authors); }; }); </script> </head> <body ng-app="app" ng-controller="CommitBubbles" bgcolor="#FFFFFF"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" width="1220" height="{{c.chartHeight + c.topMargin + 5}}" xmlns:dc="http://purl.org/dc/elements/1.1/"> <rect fill="#FEFCFF" x="100" y="{{c.topMargin}}" width="1100" height="{{c.chartHeight}}" ng-click="selected.commit = false"/> <g font-family="Verdana" font-size="16"> <text x="0" y="{{c.topMargin + 8}}">All Test</text> <text x="0" y="{{c.chartHeight/2 + 5 + c.topMargin}}">Equal</text> <text x="0" y="{{c.chartHeight + c.topMargin}}">All Prod</text> <text x="1140" y="{{c.chartHeight/2 + 17 + c.topMargin}}">Time ➤</text> </g> <g style="stroke:rgb(0,0,0);stroke-width:2"> <line x1="100" y1="{{c.chartHeight/2 + c.topMargin}}" x2="1200" y2="{{c.chartHeight/2 + c.topMargin}}" /> <line x1="100" y1="{{c.topMargin +2}}" x2="100" y2="{{c.chartHeight + c.topMargin+2}}"/> </g> <g font-family="Verdana" font-size="8" ng-repeat="i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]" style="stroke:rgb(0,0,0);stroke-width:0.5"> <line ng-show="i != 5" x1="100" stroke-dasharray="10,35" y1="{{c.chartHeight + 2 - (c.chartHeight/10 * i) + c.topMargin}}" x2="1200" y2="{{c.chartHeight - (c.chartHeight/10 * i) + c.topMargin}}" /> <text fill="white" x="70" y="{{c.chartHeight + 3 - (c.chartHeight/10 * i) + c.topMargin}}">{{100 - (10*i)}}:{{(10*i)}}</text> </g> <g stroke="black"> <circle ng-repeat="commit in commits" ng-show="selected.authors.indexOf(commit.author) > -1" cx="{{100 + (commit.ts - from) * 1100 / (to - from) }}" cy="{{c.chartHeight - (commit.testPercentage * c.chartHeight/100) + c.topMargin}}" r="{{commit.size * (c.chartHeight/600)}}" stroke-opacity="{{(selected.commit === commit) ? 1 : 0}}" fill="{{c.colors}}" fill-opacity="0.5" ng-click="selected.commit = commit"/> </g> <foreignObject class="node" x="0" y="0" width="1200" height="{{c.topMargin}}"> <body xmlns="http://www.w3.org/1999/xhtml"> <h2>{{timeSpan}} shown between {{from | date:'MM/dd/yy HH:mm'}} and {{to | date:'MM/dd/yy HH:mm'}}</h2> <div>Show authors: <label ng-repeat="author in authors" style="{{'color: ' + c.colors[$index] }}"> <input type="checkbox" checklist-model="selected.authors" checklist-value="author"> {{author}} </label> <button ng-click="checkAllAuthors()" style="margin: 0 0 5px 5px">All authors</button> <button ng-click="selected.authors.splice(0,selected.authors.length)" style="margin: 0 0 5px 5px">None</button> </div> </body> </foreignObject> <g font-family="Verdana" font-size="16" ng-show="selected.commit" ng-click="selected.commit = false"> <rect style="stroke:rgb(0,0,0);stroke-width:2" x="300" y="300" height="300" width="400" fill="white" opacity="0.7"/> <text x="320" y="330">Selected Commit</text> <text x="320" y="380">Hash: {{selected.commit.hash}}</text> <text x="320" y="430">Author: {{selected.commit.author}}</text> <text x="320" y="480">Date/Time: {{selected.commit.ts | date:'yyyy-MM-dd HH:mm:ss Z'}}</text> <text x="320" y="530">Size: {{selected.commit.size}}</text> <text x="320" y="580">Test Percentage: {{selected.commit.testPercentage}}</text> </g> </svg> </body> </html>
Если мы проигнорируем массив не конфликтующих цветов, некоторые константы и симуляцию четырех коммитов, которые встроены, а не извлекаются через $ resource, то есть только десять строк JavaScript. Подчеркивание помогло нам немного сократить количество строк. Недостатком является то, что html довольно тяжелый угловой атрибут.
Следующий?
Colleagues [a href=»http://www.grahambrooks.com»]Graham Brooks and Premanand Chandrasekaran are working to use it in a real (and larger system), and populate the commit info (at least for Subversion).
A D3 Alternative
Colleague Pawel Badenski forked my repo, and quickly made a D3 version of the same thing. I don’t want to give him too much publicity, so I’ll leave it at that
20% less lines of code, grumble grumble……