From 2cb34c273ce4ea99fc60bd29386c55b718e81954 Mon Sep 17 00:00:00 2001 From: David Evans Date: Mon, 6 Nov 2017 21:46:40 +0000 Subject: [PATCH] Tidy up chunky theme, add theme name autocomplete [#17] --- readme_images.htm | 2 +- scripts/interface/Interface.js | 3 ++ scripts/interface/Interface_spec.js | 6 ++- scripts/readme_images.js | 16 +++---- scripts/sequence/CodeMirrorHints.js | 24 +++++++++- scripts/sequence/CodeMirrorMode.js | 37 ++++++++++++--- scripts/sequence/Renderer.js | 6 +++ scripts/sequence/components/Connect.js | 13 ++++-- scripts/sequence/themes/Chunky.js | 62 ++++++++++++++------------ 9 files changed, 119 insertions(+), 50 deletions(-) diff --git a/readme_images.htm b/readme_images.htm index 421275b..0da590f 100644 --- a/readme_images.htm +++ b/readme_images.htm @@ -14,7 +14,7 @@ form-action 'none'; "> -Sequence Diagram +Readme Image Generator diff --git a/scripts/interface/Interface.js b/scripts/interface/Interface.js index a77bc58..7ab0d19 100644 --- a/scripts/interface/Interface.js +++ b/scripts/interface/Interface.js @@ -109,6 +109,9 @@ define([ const code = new CodeMirror(container, { value, mode: 'sequence', + globals: { + themes: this.renderer.getThemeNames(), + }, lineNumbers: true, showTrailingSpace: true, extraKeys: { diff --git a/scripts/interface/Interface_spec.js b/scripts/interface/Interface_spec.js index 909a125..f4fd6f4 100644 --- a/scripts/interface/Interface_spec.js +++ b/scripts/interface/Interface_spec.js @@ -24,7 +24,11 @@ defineDescribe('Interface', ['./Interface'], (Interface) => { agents: [], stages: [], }); - renderer = jasmine.createSpyObj('renderer', ['render', 'svg']); + renderer = jasmine.createSpyObj('renderer', [ + 'render', + 'svg', + 'getThemeNames', + ]); renderer.svg.and.returnValue(document.createElement('svg')); container = jasmine.createSpyObj('container', ['appendChild']); exporter = jasmine.createSpyObj('exporter', ['getSVGURL']); diff --git a/scripts/readme_images.js b/scripts/readme_images.js index 85fee0a..d7ca8ac 100644 --- a/scripts/readme_images.js +++ b/scripts/readme_images.js @@ -17,6 +17,8 @@ return o; } + const PNG_RESOLUTION = 4; + const FAVICON_SRC = ( 'theme chunky\n' + 'define ABC as A, DEF as B\n' + @@ -47,7 +49,7 @@ results.push({ file: 'favicon.png', code: FAVICON_SRC, - height: 64, + size: {width: 16, height: 16}, }); return results; } @@ -61,8 +63,6 @@ } } - const PNG_RESOLUTION = 4; - /* jshint -W072 */ // Allow several required modules requirejs([ 'sequence/Parser', @@ -91,7 +91,7 @@ status.appendChild(statusText); document.body.appendChild(status); - function renderSample({file, code, height}) { + function renderSample({file, code, size}) { const renderer = new Renderer({themes}); const exporter = new Exporter(); @@ -124,11 +124,11 @@ const parsed = parser.parse(code); const sequence = generator.generate(parsed); renderer.render(sequence); - let resolution = PNG_RESOLUTION; - if(height) { - resolution = height / renderer.height; + if(size) { + renderer.width = size.width; + renderer.height = size.height; } - exporter.getPNGURL(renderer, resolution, (url) => { + exporter.getPNGURL(renderer, PNG_RESOLUTION, (url) => { raster.setAttribute('src', url); downloadPNG.setAttribute('href', url); }); diff --git a/scripts/sequence/CodeMirrorHints.js b/scripts/sequence/CodeMirrorHints.js index 7b1da23..c15e329 100644 --- a/scripts/sequence/CodeMirrorHints.js +++ b/scripts/sequence/CodeMirrorHints.js @@ -1,4 +1,4 @@ -define(() => { +define(['core/ArrayUtilities'], (array) => { 'use strict'; const TRIMMER = /^([ \t]*)(.*)$/; @@ -32,6 +32,26 @@ define(() => { }; } + function getGlobals({global, prefix = '', suffix = ''}, globals) { + const identified = globals[global]; + if(!identified) { + return []; + } + return identified.map((item) => (prefix + item + suffix)); + } + + function populateGlobals(suggestions, globals = {}) { + for(let i = 0; i < suggestions.length;) { + if(typeof suggestions[i] === 'object') { + const identified = getGlobals(suggestions[i], globals); + array.mergeSets(suggestions, identified); + suggestions.splice(i, 1); + } else { + ++ i; + } + } + } + function getHints(cm, options) { const cur = cm.getCursor(); const token = cm.getTokenAt(cur); @@ -52,6 +72,8 @@ define(() => { comp = comp.concat(token.state.knownAgent); } + populateGlobals(comp, cm.options.globals); + const ranges = makeRanges(cm, cur.line, from, token.end); let selfValid = false; const list = (comp diff --git a/scripts/sequence/CodeMirrorMode.js b/scripts/sequence/CodeMirrorMode.js index e897d9a..7ea91a4 100644 --- a/scripts/sequence/CodeMirrorMode.js +++ b/scripts/sequence/CodeMirrorMode.js @@ -26,11 +26,21 @@ define(['core/ArrayUtilities'], (array) => { ',': {type: 'operator', suggest: true, then: {'': 1}}, '\n': end, }}; - const agentListToEnd = {type: 'variable', suggest: 'Agent', then: { + const agentListToText = {type: 'variable', suggest: 'Agent', then: { '': 0, ',': {type: 'operator', suggest: true, then: {'': 1}}, ':': {type: 'operator', suggest: true, then: {'': textToEnd}}, }}; + const agentList2ToText = {type: 'variable', suggest: 'Agent', then: { + '': 0, + ',': {type: 'operator', suggest: true, then: {'': agentListToText}}, + ':': CM_ERROR, + }}; + const singleAgentToText = {type: 'variable', suggest: 'Agent', then: { + '': 0, + ',': CM_ERROR, + ':': {type: 'operator', suggest: true, then: {'': textToEnd}}, + }}; const agentToOptText = {type: 'variable', suggest: 'Agent', then: { '': 0, ':': {type: 'operator', suggest: true, then: { @@ -46,12 +56,12 @@ define(['core/ArrayUtilities'], (array) => { suggest: [side + ' of ', side + ': '], then: { 'of': {type: 'keyword', suggest: true, then: { - '': agentListToEnd, + '': agentListToText, }}, ':': {type: 'operator', suggest: true, then: { '': textToEnd, }}, - '': agentListToEnd, + '': agentListToText, }, }; } @@ -122,7 +132,17 @@ define(['core/ArrayUtilities'], (array) => { '': textToEnd, }}, 'theme': {type: 'keyword', suggest: true, then: { - '': textToEnd, + '': { + type: 'string', + suggest: { + global: 'themes', + suffix: '\n', + }, + then: { + '': 0, + '\n': end, + }, + }, }}, 'terminators': {type: 'keyword', suggest: true, then: { 'none': {type: 'keyword', suggest: true, then: {}}, @@ -166,17 +186,17 @@ define(['core/ArrayUtilities'], (array) => { }}, 'note': {type: 'keyword', suggest: true, then: { 'over': {type: 'keyword', suggest: true, then: { - '': agentListToEnd, + '': agentListToText, }}, 'left': makeSideNote('left'), 'right': makeSideNote('right'), 'between': {type: 'keyword', suggest: true, then: { - '': agentListToEnd, + '': agentList2ToText, }}, }}, 'state': {type: 'keyword', suggest: 'state over ', then: { 'over': {type: 'keyword', suggest: true, then: { - '': agentListToEnd, + '': singleAgentToText, }}, }}, 'text': {type: 'keyword', suggest: true, then: { @@ -204,6 +224,9 @@ define(['core/ArrayUtilities'], (array) => { } function cmGetVarSuggestions(state, previous, current) { + if(typeof current.suggest === 'object' && current.suggest.global) { + return [current.suggest]; + } if( typeof current.suggest !== 'string' || previous.suggest === current.suggest diff --git a/scripts/sequence/Renderer.js b/scripts/sequence/Renderer.js index ba24a34..6c0f160 100644 --- a/scripts/sequence/Renderer.js +++ b/scripts/sequence/Renderer.js @@ -589,6 +589,12 @@ define([ this.sizer.detach(); } + getThemeNames() { + return (Array.from(this.themes.keys()) + .filter((name) => (name !== '')) + ); + } + getAgentX(name) { return this.agentInfos.get(name).x; } diff --git a/scripts/sequence/components/Connect.js b/scripts/sequence/components/Connect.js index 3ed83c6..340e5eb 100644 --- a/scripts/sequence/components/Connect.js +++ b/scripts/sequence/components/Connect.js @@ -24,12 +24,17 @@ define([ function getArrowShort(theme) { const arrow = theme.connect.arrow; - const h = arrow.height / 2; - const w = arrow.width; + const join = arrow.attrs['stroke-linejoin'] || 'miter'; const t = arrow.attrs['stroke-width'] * 0.5; const lineStroke = theme.agentLineAttrs['stroke-width'] * 0.5; - const arrowDistance = t * Math.sqrt((w * w) / (h * h) + 1); - return lineStroke + arrowDistance; + if(join === 'round') { + return lineStroke + t; + } else { + const h = arrow.height / 2; + const w = arrow.width; + const arrowDistance = t * Math.sqrt((w * w) / (h * h) + 1); + return lineStroke + arrowDistance; + } } class Connect extends BaseComponent { diff --git a/scripts/sequence/themes/Chunky.js b/scripts/sequence/themes/Chunky.js index af6154a..80a39a0 100644 --- a/scripts/sequence/themes/Chunky.js +++ b/scripts/sequence/themes/Chunky.js @@ -4,7 +4,7 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => { const LINE_HEIGHT = 1.3; const SETTINGS = { - titleMargin: 10, + titleMargin: 12, outerMargin: 5, agentMargin: 8, actionMargin: 5, @@ -40,6 +40,7 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => { 'fill': 'none', 'stroke': '#000000', 'stroke-width': 3, + 'stroke-linecap': 'round', }, }, bar: { @@ -48,6 +49,8 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => { 'stroke': '#000000', 'stroke-width': 3, 'height': 4, + 'rx': 2, + 'ry': 2, }, }, fade: { @@ -60,7 +63,7 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => { }, connect: { - loopbackRadius: 6, + loopbackRadius: 8, lineAttrs: { 'solid': { 'fill': 'none', @@ -71,7 +74,7 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => { 'fill': 'none', 'stroke': '#000000', 'stroke-width': 3, - 'stroke-dasharray': '4, 2', + 'stroke-dasharray': '10, 4', }, }, arrow: { @@ -79,13 +82,14 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => { height: 12, attrs: { 'fill': '#000000', - 'stroke-width': 0, - 'stroke-linejoin': 'miter', + 'stroke': '#000000', + 'stroke-width': 3, + 'stroke-linejoin': 'round', }, }, label: { padding: 6, - margin: {top: 2, bottom: 1}, + margin: {top: 2, bottom: 3}, attrs: { 'font-family': 'sans-serif', 'font-size': 8, @@ -100,10 +104,10 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => { }, mask: { padding: { - top: 0, - left: 3, - right: 3, - bottom: 1, + top: 1, + left: 5, + right: 5, + bottom: 3, }, }, }, @@ -116,28 +120,28 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => { boxAttrs: { 'fill': 'none', 'stroke': '#000000', - 'stroke-width': 1.5, - 'rx': 2, - 'ry': 2, + 'stroke-width': 4, + 'rx': 5, + 'ry': 5, }, section: { padding: { top: 3, - bottom: 2, + bottom: 4, }, mode: { padding: { - top: 1, - left: 3, - right: 3, - bottom: 0, + top: 2, + left: 5, + right: 5, + bottom: 1, }, boxAttrs: { 'fill': '#FFFFFF', 'stroke': '#000000', - 'stroke-width': 3, - 'rx': 2, - 'ry': 2, + 'stroke-width': 2, + 'rx': 3, + 'ry': 3, }, labelAttrs: { 'font-family': 'sans-serif', @@ -149,7 +153,7 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => { }, label: { padding: { - top: 1, + top: 2, left: 5, right: 3, bottom: 0, @@ -165,8 +169,8 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => { separator: { attrs: { 'stroke': '#000000', - 'stroke-width': 1.5, - 'stroke-dasharray': '4, 2', + 'stroke-width': 2, + 'stroke-dasharray': '5, 3', }, }, }, @@ -187,12 +191,13 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => { }, 'note': { margin: {top: 0, left: 5, right: 5, bottom: 0}, - padding: {top: 5, left: 5, right: 10, bottom: 5}, + padding: {top: 3, left: 3, right: 10, bottom: 3}, overlap: {left: 10, right: 10}, boxRenderer: SVGShapes.renderNote.bind(null, { 'fill': '#FFFFFF', 'stroke': '#000000', - 'stroke-width': 1, + 'stroke-width': 2, + 'stroke-linejoin': 'round', }, { 'fill': 'none', 'stroke': '#000000', @@ -206,12 +211,12 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => { }, 'state': { margin: {top: 0, left: 5, right: 5, bottom: 0}, - padding: {top: 7, left: 7, right: 7, bottom: 7}, + padding: {top: 5, left: 7, right: 7, bottom: 5}, overlap: {left: 10, right: 10}, boxRenderer: SVGShapes.renderBox.bind(null, { 'fill': '#FFFFFF', 'stroke': '#000000', - 'stroke-width': 1, + 'stroke-width': 3, 'rx': 10, 'ry': 10, }), @@ -225,6 +230,7 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => { titleAttrs: { 'font-family': 'sans-serif', + 'font-weight': 'bolder', 'font-size': 20, 'line-height': LINE_HEIGHT, 'text-anchor': 'middle',