From cba803abaf8ad2e8b3b198c6c495cf8c0147faa3 Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Mon, 1 Jan 2024 23:26:14 +0000 Subject: [PATCH 01/18] add: point styling for quadrant chart (incomplete) --- .../quadrant-chart/parser/quadrant.jison | 19 ++++++++++++++++ .../quadrant-chart/quadrantBuilder.ts | 19 ++++++++++++++-- .../src/diagrams/quadrant-chart/quadrantDb.ts | 22 +++++++++++++++++-- .../quadrant-chart/quadrantRenderer.ts | 4 +++- 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison index 255b30a035..a78aebf1e0 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison +++ b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison @@ -11,6 +11,10 @@ %x point_start %x point_x %x point_y +%x point_radius +%x point_color +%x stroke_color +%x stroke_width %% \%\%(?!\{)[^\n]* /* skip comments */ [^\}]\%\%[^\n]* /* skip comments */ @@ -48,6 +52,14 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multiline");} \s*\]" "* {this.popState();} \s*\,\s* {this.popState(); this.begin('point_y');} (1)|(0(.\d+)?) {this.popState(); return 'point_y';} +\s*radius\:\s* {this.begin('point_radius');} +\d+ {this.popState(); return 'point_radius';} +\s*color\:\s* {this.begin('point_color');} +\#([a-fA-F0-9]{6}|[a-fA-F0-9]{3}) {this.popState(); return 'point_color';} +\s*stroke_color\:\s* {this.begin('stroke_color');} +\#([a-fA-F0-9]{6}|[a-fA-F0-9]{3}) {this.popState(); return 'stroke_color';} +\s*stroke_width\:\s* {this.begin('stroke_width');} +\d+px {this.popState(); return 'stroke_width';} " "*"quadrantChart"" "* return 'QUADRANT'; @@ -104,6 +116,13 @@ statement points : text point_start point_x point_y {yy.addPoint($1, $3, $4);} + | text point_start point_x point_y point_radius {yy.addPoint($1, $3, $4, $5);} + | text point_start point_x point_y point_color {yy.addPoint($1, $3, $4, "", $5);} + | text point_start point_x point_y stroke_color {yy.addPoint($1, $3, $4, "", "", $5);} + | text point_start point_x point_y stroke_width {yy.addPoint($1, $3, $4, "", "", "", $5);} + | text point_start point_x point_y point_radius point_color {yy.addPoint($1, $3, $4, $5, $6);} + | text point_start point_x point_y point_radius point_color stroke_color {yy.addPoint($1, $3, $4, $5, $6, $7);} + | text point_start point_x point_y point_radius point_color stroke_color stroke_width {yy.addPoint($1, $3, $4, $5, $6, $7, $8);} ; axisDetails diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts index 380a79f190..e5ced4e82c 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts @@ -12,6 +12,10 @@ export type TextHorizontalPos = 'top' | 'middle' | 'bottom'; export interface QuadrantPointInputType extends Point { text: string; + radius: number; + color: string; + strokeColor: string; + strokeWidth: string; } export interface QuadrantTextType extends Point { @@ -27,6 +31,8 @@ export interface QuadrantPointType extends Point { fill: string; radius: number; text: QuadrantTextType; + strokeColor: string; + strokeWidth: string; } export interface QuadrantQuadrantsType extends Point { @@ -473,8 +479,11 @@ export class QuadrantBuilder { const props: QuadrantPointType = { x: xAxis(point.x), y: yAxis(point.y), - fill: this.themeConfig.quadrantPointFill, - radius: this.config.pointRadius, + fill: + point.color !== undefined && point.color !== '' + ? point.color + : this.themeConfig.quadrantPointFill, + radius: point.radius !== undefined && point.radius ? point.radius : this.config.pointRadius, text: { text: point.text, fill: this.themeConfig.quadrantPointTextFill, @@ -485,6 +494,12 @@ export class QuadrantBuilder { fontSize: this.config.pointLabelFontSize, rotation: 0, }, + strokeColor: + point.strokeColor !== undefined && point.strokeColor !== '' + ? point.strokeColor + : this.themeConfig.quadrantPointFill, + strokeWidth: + point.strokeWidth !== undefined && point.strokeWidth !== '' ? point.strokeWidth : '0px', }; return props; }); diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts index c3a79c911e..dff877cfbc 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts @@ -53,8 +53,26 @@ function setYAxisBottomText(textObj: LexTextObj) { quadrantBuilder.setData({ yAxisBottomText: textSanitizer(textObj.text) }); } -function addPoint(textObj: LexTextObj, x: number, y: number) { - quadrantBuilder.addPoints([{ x, y, text: textSanitizer(textObj.text) }]); +function addPoint( + textObj: LexTextObj, + x: number, + y: number, + radius: number, + color: string, + stroke_color: string, + stroke_width: string +) { + quadrantBuilder.addPoints([ + { + x, + y, + text: textSanitizer(textObj.text), + radius, + color, + strokeColor: stroke_color, + strokeWidth: stroke_width, + }, + ]); } function setWidth(width: number) { diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantRenderer.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantRenderer.ts index d272dccd4a..c2295da4d4 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantRenderer.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantRenderer.ts @@ -152,7 +152,9 @@ export const draw = (txt: string, id: string, _version: string, diagObj: Diagram .attr('cx', (data: QuadrantPointType) => data.x) .attr('cy', (data: QuadrantPointType) => data.y) .attr('r', (data: QuadrantPointType) => data.radius) - .attr('fill', (data: QuadrantPointType) => data.fill); + .attr('fill', (data: QuadrantPointType) => data.fill) + .attr('stroke', (data: QuadrantPointType) => data.strokeColor) + .attr('stroke-width', (data: QuadrantPointType) => data.strokeWidth); dataPoints .append('text') From 8ab00442ea2e61cb52414183720856c3b0261042 Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Tue, 2 Jan 2024 01:53:03 +0000 Subject: [PATCH 02/18] add: tests --- .../rendering/quadrantChart.spec.js | 23 ++++ .../parser/quadrant.jison.spec.ts | 128 ++++++++++++++++++ 2 files changed, 151 insertions(+) diff --git a/cypress/integration/rendering/quadrantChart.spec.js b/cypress/integration/rendering/quadrantChart.spec.js index 1be1f7deff..fa2410da08 100644 --- a/cypress/integration/rendering/quadrantChart.spec.js +++ b/cypress/integration/rendering/quadrantChart.spec.js @@ -226,4 +226,27 @@ describe('Quadrant Chart', () => { ); cy.get('svg'); }); + + it('it should render data points with styles', () => { + imgSnapshotTest( + ` + quadrantChart + title Reach and engagement of campaigns + x-axis Reach --> + y-axis Engagement --> + quadrant-1 We should expand + quadrant-2 Need to promote + quadrant-3 Re-evaluate + quadrant-4 May be improved + Campaign A: [0.3, 0.6] radius: 20 + Campaign B: [0.45, 0.23] color: #ff0000 + Campaign C: [0.57, 0.69] stroke_color: #ff00ff + Campaign D: [0.78, 0.34] stroke_width: 3px + Campaign E: [0.40, 0.34] radius: 20 color: #ff0000 stroke_color: #ff00ff stroke_width: 3px + Campaign F: [0.35, 0.78] + `, + {} + ); + cy.get('svg'); + }); }); diff --git a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts index d10cb21340..ea9b118f38 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts @@ -266,4 +266,132 @@ describe('Testing quadrantChart jison file', () => { expect(mockDB.addPoint).toHaveBeenCalledWith({ text: 'IBM', type: 'text' }, '0.51', '0.40'); expect(mockDB.addPoint).toHaveBeenCalledWith({ text: 'Incorta', type: 'text' }, '0.20', '0.30'); }); + + it('should be able to parse the whole chart with point styling with all params', () => { + const str = `quadrantChart + title Analytics and Business Intelligence Platforms + x-axis "Completeness of Vision ❤" --> "x-axis-2" + y-axis Ability to Execute --> "y-axis-2" + quadrant-1 Leaders + quadrant-2 Challengers + quadrant-3 Niche + quadrant-4 Visionaries + Microsoft: [0.75, 0.75] radius: 10 color: #ff0000 stroke_color: #ff00ff stroke_width: 10px + Salesforce: [0.55, 0.60] radius: 10 color: #ff0000 stroke_color: #ff00ff stroke_width: 10px + IBM: [0.51, 0.40] radius: 10 color: #ff0000 stroke_color: #ff00ff stroke_width: 10px + Incorta: [0.20, 0.30] radius: 10 color: #ff0000 stroke_color: #ff00ff stroke_width: 10px`; + + expect(parserFnConstructor(str)).not.toThrow(); + expect(mockDB.setXAxisLeftText).toHaveBeenCalledWith({ + text: 'Completeness of Vision ❤', + type: 'text', + }); + expect(mockDB.setXAxisRightText).toHaveBeenCalledWith({ text: 'x-axis-2', type: 'text' }); + expect(mockDB.setYAxisTopText).toHaveBeenCalledWith({ text: 'y-axis-2', type: 'text' }); + expect(mockDB.setYAxisBottomText).toHaveBeenCalledWith({ + text: 'Ability to Execute', + type: 'text', + }); + expect(mockDB.setQuadrant1Text).toHaveBeenCalledWith({ text: 'Leaders', type: 'text' }); + expect(mockDB.setQuadrant2Text).toHaveBeenCalledWith({ text: 'Challengers', type: 'text' }); + expect(mockDB.setQuadrant3Text).toHaveBeenCalledWith({ text: 'Niche', type: 'text' }); + expect(mockDB.setQuadrant4Text).toHaveBeenCalledWith({ text: 'Visionaries', type: 'text' }); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'Microsoft', type: 'text' }, + '0.75', + '0.75', + '10', + '#ff0000', + '#ff00ff', + '10px' + ); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'Salesforce', type: 'text' }, + '0.55', + '0.60', + '10', + '#ff0000', + '#ff00ff', + '10px' + ); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'IBM', type: 'text' }, + '0.51', + '0.40', + '10', + '#ff0000', + '#ff00ff', + '10px' + ); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'Incorta', type: 'text' }, + '0.20', + '0.30', + '10', + '#ff0000', + '#ff00ff', + '10px' + ); + }); + + it('should be able to parse the whole chart with point styling', () => { + const str = `quadrantChart + title Analytics and Business Intelligence Platforms + x-axis "Completeness of Vision ❤" --> "x-axis-2" + y-axis Ability to Execute --> "y-axis-2" + quadrant-1 Leaders + quadrant-2 Challengers + quadrant-3 Niche + quadrant-4 Visionaries + Microsoft: [0.75, 0.75] radius: 10 + Salesforce: [0.55, 0.60] color: #ff0000 + IBM: [0.51, 0.40] stroke_color: #ff00ff + Incorta: [0.20, 0.30] stroke_width: 10px`; + + expect(parserFnConstructor(str)).not.toThrow(); + expect(mockDB.setXAxisLeftText).toHaveBeenCalledWith({ + text: 'Completeness of Vision ❤', + type: 'text', + }); + expect(mockDB.setXAxisRightText).toHaveBeenCalledWith({ text: 'x-axis-2', type: 'text' }); + expect(mockDB.setYAxisTopText).toHaveBeenCalledWith({ text: 'y-axis-2', type: 'text' }); + expect(mockDB.setYAxisBottomText).toHaveBeenCalledWith({ + text: 'Ability to Execute', + type: 'text', + }); + expect(mockDB.setQuadrant1Text).toHaveBeenCalledWith({ text: 'Leaders', type: 'text' }); + expect(mockDB.setQuadrant2Text).toHaveBeenCalledWith({ text: 'Challengers', type: 'text' }); + expect(mockDB.setQuadrant3Text).toHaveBeenCalledWith({ text: 'Niche', type: 'text' }); + expect(mockDB.setQuadrant4Text).toHaveBeenCalledWith({ text: 'Visionaries', type: 'text' }); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'Microsoft', type: 'text' }, + '0.75', + '0.75', + '10' + ); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'Salesforce', type: 'text' }, + '0.55', + '0.60', + '', + '#ff0000' + ); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'IBM', type: 'text' }, + '0.51', + '0.40', + '', + '', + '#ff00ff' + ); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'Incorta', type: 'text' }, + '0.20', + '0.30', + '', + '', + '', + '10px' + ); + }); }); From 9cca389031faf93a163c14215808059fb419f8e4 Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Thu, 11 Jan 2024 23:27:48 +0000 Subject: [PATCH 03/18] fix:styles can be in random order and are optional --- .../quadrant-chart/parser/quadrant.jison | 25 +---- .../parser/quadrant.jison.spec.ts | 102 ++++++++++++------ .../quadrant-chart/quadrantBuilder.ts | 8 +- .../src/diagrams/quadrant-chart/quadrantDb.ts | 41 ++++--- 4 files changed, 105 insertions(+), 71 deletions(-) diff --git a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison index a78aebf1e0..e3ce4c0316 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison +++ b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison @@ -11,10 +11,7 @@ %x point_start %x point_x %x point_y -%x point_radius -%x point_color -%x stroke_color -%x stroke_width +%x styles_string %% \%\%(?!\{)[^\n]* /* skip comments */ [^\}]\%\%[^\n]* /* skip comments */ @@ -49,17 +46,10 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multiline");} \s*\:\s*\[\s* {this.begin("point_start"); return 'point_start';} (1)|(0(.\d+)?) {this.begin('point_x'); return 'point_x';} -\s*\]" "* {this.popState();} +\s*\]" "* {this.popState(); this.begin('styles_string')} +.* {this.popState(); return 'styles_string';} \s*\,\s* {this.popState(); this.begin('point_y');} (1)|(0(.\d+)?) {this.popState(); return 'point_y';} -\s*radius\:\s* {this.begin('point_radius');} -\d+ {this.popState(); return 'point_radius';} -\s*color\:\s* {this.begin('point_color');} -\#([a-fA-F0-9]{6}|[a-fA-F0-9]{3}) {this.popState(); return 'point_color';} -\s*stroke_color\:\s* {this.begin('stroke_color');} -\#([a-fA-F0-9]{6}|[a-fA-F0-9]{3}) {this.popState(); return 'stroke_color';} -\s*stroke_width\:\s* {this.begin('stroke_width');} -\d+px {this.popState(); return 'stroke_width';} " "*"quadrantChart"" "* return 'QUADRANT'; @@ -115,14 +105,7 @@ statement ; points - : text point_start point_x point_y {yy.addPoint($1, $3, $4);} - | text point_start point_x point_y point_radius {yy.addPoint($1, $3, $4, $5);} - | text point_start point_x point_y point_color {yy.addPoint($1, $3, $4, "", $5);} - | text point_start point_x point_y stroke_color {yy.addPoint($1, $3, $4, "", "", $5);} - | text point_start point_x point_y stroke_width {yy.addPoint($1, $3, $4, "", "", "", $5);} - | text point_start point_x point_y point_radius point_color {yy.addPoint($1, $3, $4, $5, $6);} - | text point_start point_x point_y point_radius point_color stroke_color {yy.addPoint($1, $3, $4, $5, $6, $7);} - | text point_start point_x point_y point_radius point_color stroke_color stroke_width {yy.addPoint($1, $3, $4, $5, $6, $7, $8);} + : text point_start point_x point_y styles_string {yy.addPoint($1, $3, $4, $5);} ; axisDetails diff --git a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts index ea9b118f38..67ac117c56 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts @@ -267,7 +267,7 @@ describe('Testing quadrantChart jison file', () => { expect(mockDB.addPoint).toHaveBeenCalledWith({ text: 'Incorta', type: 'text' }, '0.20', '0.30'); }); - it('should be able to parse the whole chart with point styling with all params', () => { + it('should be able to parse the whole chart with point styling with all params or some params', () => { const str = `quadrantChart title Analytics and Business Intelligence Platforms x-axis "Completeness of Vision ❤" --> "x-axis-2" @@ -276,10 +276,10 @@ describe('Testing quadrantChart jison file', () => { quadrant-2 Challengers quadrant-3 Niche quadrant-4 Visionaries - Microsoft: [0.75, 0.75] radius: 10 color: #ff0000 stroke_color: #ff00ff stroke_width: 10px - Salesforce: [0.55, 0.60] radius: 10 color: #ff0000 stroke_color: #ff00ff stroke_width: 10px - IBM: [0.51, 0.40] radius: 10 color: #ff0000 stroke_color: #ff00ff stroke_width: 10px - Incorta: [0.20, 0.30] radius: 10 color: #ff0000 stroke_color: #ff00ff stroke_width: 10px`; + Microsoft: [0.75, 0.75] radius: 10 + Salesforce: [0.55, 0.60] radius: 10, color: #ff0000 + IBM: [0.51, 0.40] radius: 10, color: #ff0000, stroke_color: #ff00ff + Incorta: [0.20, 0.30] radius: 10 ,color: #ff0000 ,stroke_color: #ff00ff ,stroke_width: 10px`; expect(parserFnConstructor(str)).not.toThrow(); expect(mockDB.setXAxisLeftText).toHaveBeenCalledWith({ @@ -300,41 +300,28 @@ describe('Testing quadrantChart jison file', () => { { text: 'Microsoft', type: 'text' }, '0.75', '0.75', - '10', - '#ff0000', - '#ff00ff', - '10px' + 'radius: 10' ); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'Salesforce', type: 'text' }, '0.55', '0.60', - '10', - '#ff0000', - '#ff00ff', - '10px' + 'radius: 10, color: #ff0000' ); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'IBM', type: 'text' }, '0.51', '0.40', - '10', - '#ff0000', - '#ff00ff', - '10px' + 'radius: 10, color: #ff0000, stroke_color: #ff00ff' ); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'Incorta', type: 'text' }, '0.20', '0.30', - '10', - '#ff0000', - '#ff00ff', - '10px' + 'radius: 10 ,color: #ff0000 ,stroke_color: #ff00ff ,stroke_width: 10px' ); }); - - it('should be able to parse the whole chart with point styling', () => { + it('should be able to parse the whole chart with point styling with 1 param', () => { const str = `quadrantChart title Analytics and Business Intelligence Platforms x-axis "Completeness of Vision ❤" --> "x-axis-2" @@ -367,31 +354,80 @@ describe('Testing quadrantChart jison file', () => { { text: 'Microsoft', type: 'text' }, '0.75', '0.75', - '10' + 'radius: 10' ); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'Salesforce', type: 'text' }, '0.55', '0.60', - '', - '#ff0000' + 'color: #ff0000' ); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'IBM', type: 'text' }, '0.51', '0.40', - '', - '', - '#ff00ff' + 'stroke_color: #ff00ff' ); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'Incorta', type: 'text' }, '0.20', '0.30', - '', - '', - '', - '10px' + 'stroke_width: 10px' ); }); }); + +it('should be able to parse the whole chart with point styling with params in a random order', () => { + const str = `quadrantChart + title Analytics and Business Intelligence Platforms + x-axis "Completeness of Vision ❤" --> "x-axis-2" + y-axis Ability to Execute --> "y-axis-2" + quadrant-1 Leaders + quadrant-2 Challengers + quadrant-3 Niche + quadrant-4 Visionaries + Microsoft: [0.75, 0.75] stroke_color: #ff00ff ,stroke_width: 10px, color: #ff0000, radius: 10 + Salesforce: [0.55, 0.60] radius: 10, color: #ff0000 + IBM: [0.51, 0.40] stroke_color: #ff00ff ,stroke_width: 10px + Incorta: [0.20, 0.30] stroke_width: 10px`; + + expect(parserFnConstructor(str)).not.toThrow(); + expect(mockDB.setXAxisLeftText).toHaveBeenCalledWith({ + text: 'Completeness of Vision ❤', + type: 'text', + }); + expect(mockDB.setXAxisRightText).toHaveBeenCalledWith({ text: 'x-axis-2', type: 'text' }); + expect(mockDB.setYAxisTopText).toHaveBeenCalledWith({ text: 'y-axis-2', type: 'text' }); + expect(mockDB.setYAxisBottomText).toHaveBeenCalledWith({ + text: 'Ability to Execute', + type: 'text', + }); + expect(mockDB.setQuadrant1Text).toHaveBeenCalledWith({ text: 'Leaders', type: 'text' }); + expect(mockDB.setQuadrant2Text).toHaveBeenCalledWith({ text: 'Challengers', type: 'text' }); + expect(mockDB.setQuadrant3Text).toHaveBeenCalledWith({ text: 'Niche', type: 'text' }); + expect(mockDB.setQuadrant4Text).toHaveBeenCalledWith({ text: 'Visionaries', type: 'text' }); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'Microsoft', type: 'text' }, + '0.75', + '0.75', + 'stroke_color: #ff00ff ,stroke_width: 10px, color: #ff0000, radius: 10' + ); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'Salesforce', type: 'text' }, + '0.55', + '0.60', + 'radius: 10, color: #ff0000' + ); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'IBM', type: 'text' }, + '0.51', + '0.40', + 'stroke_color: #ff00ff ,stroke_width: 10px' + ); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'Incorta', type: 'text' }, + '0.20', + '0.30', + 'stroke_width: 10px' + ); +}); diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts index e5ced4e82c..a75906902b 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts @@ -12,10 +12,10 @@ export type TextHorizontalPos = 'top' | 'middle' | 'bottom'; export interface QuadrantPointInputType extends Point { text: string; - radius: number; - color: string; - strokeColor: string; - strokeWidth: string; + radius?: number; + color?: string; + strokeColor?: string; + strokeWidth?: string; } export interface QuadrantTextType extends Point { diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts index dff877cfbc..e4edb0b042 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts @@ -53,24 +53,39 @@ function setYAxisBottomText(textObj: LexTextObj) { quadrantBuilder.setData({ yAxisBottomText: textSanitizer(textObj.text) }); } -function addPoint( - textObj: LexTextObj, - x: number, - y: number, - radius: number, - color: string, - stroke_color: string, - stroke_width: string -) { +function addPoint(textObj: LexTextObj, x: number, y: number, styles_string: string) { + const styles_object: { + radius?: number; + color?: string; + strokeColor?: string; + strokeWidth?: string; + } = {}; + if (styles_string !== '') { + const styles = styles_string.trim().split(/\s*,\s*/); + for (const item of styles) { + const style = item.split(/\s*:\s*/); + if (style[0] == 'radius') { + styles_object.radius = parseInt(style[1]); + } else if (style[0] == 'color') { + styles_object.color = style[1]; + } else if (style[0] == 'strokeColor') { + styles_object.strokeColor = style[1]; + } else if (style[0] == 'strokeWidth') { + styles_object.strokeWidth = style[1]; + } else { + // do we add error if an unknown style is added or do we ignore it + } + } + } quadrantBuilder.addPoints([ { x, y, text: textSanitizer(textObj.text), - radius, - color, - strokeColor: stroke_color, - strokeWidth: stroke_width, + radius: styles_object.radius, + color: styles_object.color, + strokeColor: styles_object.strokeColor, + strokeWidth: styles_object.strokeWidth, }, ]); } From a599e33ec216de219510018d1725f6752447646a Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Fri, 12 Jan 2024 20:41:25 +0000 Subject: [PATCH 04/18] add: class names and class definitions|todo: tests --- .../quadrant-chart/parser/quadrant.jison | 10 +- .../parser/quadrant.jison.spec.ts | 118 ++++++++++-------- .../quadrant-chart/quadrantBuilder.ts | 32 +++++ .../src/diagrams/quadrant-chart/quadrantDb.ts | 62 ++++++--- 4 files changed, 148 insertions(+), 74 deletions(-) diff --git a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison index e3ce4c0316..8ea4160ffb 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison +++ b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison @@ -12,6 +12,8 @@ %x point_x %x point_y %x styles_string +%x class_styles +%x class_name %% \%\%(?!\{)[^\n]* /* skip comments */ [^\}]\%\%[^\n]* /* skip comments */ @@ -44,12 +46,17 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multiline");} ["] this.popState(); [^"]* return "STR"; +\:\:\: {this.begin('class_name')} +^\w+ {this.popState(); return 'class_name';} + \s*\:\s*\[\s* {this.begin("point_start"); return 'point_start';} (1)|(0(.\d+)?) {this.begin('point_x'); return 'point_x';} \s*\]" "* {this.popState(); this.begin('styles_string')} .* {this.popState(); return 'styles_string';} \s*\,\s* {this.popState(); this.begin('point_y');} (1)|(0(.\d+)?) {this.popState(); return 'point_y';} +\s*classDef\s* {this.begin('class_styles')} +.* {this.popState(); yy.addClass(this.match);} " "*"quadrantChart"" "* return 'QUADRANT'; @@ -105,7 +112,8 @@ statement ; points - : text point_start point_x point_y styles_string {yy.addPoint($1, $3, $4, $5);} + : text point_start point_x point_y styles_string {yy.addPoint($1, "", $3, $4, $5);} + | text class_name point_start point_x point_y styles_string {yy.addPoint($1, $2, $4, $5, $6);} ; axisDetails diff --git a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts index 67ac117c56..9462d98de9 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts @@ -298,24 +298,28 @@ describe('Testing quadrantChart jison file', () => { expect(mockDB.setQuadrant4Text).toHaveBeenCalledWith({ text: 'Visionaries', type: 'text' }); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'Microsoft', type: 'text' }, + '', '0.75', '0.75', 'radius: 10' ); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'Salesforce', type: 'text' }, + '', '0.55', '0.60', 'radius: 10, color: #ff0000' ); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'IBM', type: 'text' }, + '', '0.51', '0.40', 'radius: 10, color: #ff0000, stroke_color: #ff00ff' ); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'Incorta', type: 'text' }, + '', '0.20', '0.30', 'radius: 10 ,color: #ff0000 ,stroke_color: #ff00ff ,stroke_width: 10px' @@ -352,82 +356,90 @@ describe('Testing quadrantChart jison file', () => { expect(mockDB.setQuadrant4Text).toHaveBeenCalledWith({ text: 'Visionaries', type: 'text' }); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'Microsoft', type: 'text' }, + '', '0.75', '0.75', 'radius: 10' ); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'Salesforce', type: 'text' }, + '', '0.55', '0.60', 'color: #ff0000' ); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'IBM', type: 'text' }, + '', '0.51', '0.40', 'stroke_color: #ff00ff' ); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'Incorta', type: 'text' }, + '', '0.20', '0.30', 'stroke_width: 10px' ); }); -}); -it('should be able to parse the whole chart with point styling with params in a random order', () => { - const str = `quadrantChart - title Analytics and Business Intelligence Platforms - x-axis "Completeness of Vision ❤" --> "x-axis-2" - y-axis Ability to Execute --> "y-axis-2" - quadrant-1 Leaders - quadrant-2 Challengers - quadrant-3 Niche - quadrant-4 Visionaries - Microsoft: [0.75, 0.75] stroke_color: #ff00ff ,stroke_width: 10px, color: #ff0000, radius: 10 - Salesforce: [0.55, 0.60] radius: 10, color: #ff0000 - IBM: [0.51, 0.40] stroke_color: #ff00ff ,stroke_width: 10px - Incorta: [0.20, 0.30] stroke_width: 10px`; - - expect(parserFnConstructor(str)).not.toThrow(); - expect(mockDB.setXAxisLeftText).toHaveBeenCalledWith({ - text: 'Completeness of Vision ❤', - type: 'text', - }); - expect(mockDB.setXAxisRightText).toHaveBeenCalledWith({ text: 'x-axis-2', type: 'text' }); - expect(mockDB.setYAxisTopText).toHaveBeenCalledWith({ text: 'y-axis-2', type: 'text' }); - expect(mockDB.setYAxisBottomText).toHaveBeenCalledWith({ - text: 'Ability to Execute', - type: 'text', + it('should be able to parse the whole chart with point styling with params in a random order + class names', () => { + const str = `quadrantChart + title Analytics and Business Intelligence Platforms + x-axis "Completeness of Vision ❤" --> "x-axis-2" + y-axis Ability to Execute --> "y-axis-2" + quadrant-1 Leaders + quadrant-2 Challengers + quadrant-3 Niche + quadrant-4 Visionaries + Microsoft: [0.75, 0.75] stroke_color: #ff00ff ,stroke_width: 10px, color: #ff0000, radius: 10 + Salesforce:::class1: [0.55, 0.60] radius: 10, color: #ff0000 + IBM: [0.51, 0.40] stroke_color: #ff00ff ,stroke_width: 10px + Incorta: [0.20, 0.30] stroke_width: 10px`; + + expect(parserFnConstructor(str)).not.toThrow(); + expect(mockDB.setXAxisLeftText).toHaveBeenCalledWith({ + text: 'Completeness of Vision ❤', + type: 'text', + }); + expect(mockDB.setXAxisRightText).toHaveBeenCalledWith({ text: 'x-axis-2', type: 'text' }); + expect(mockDB.setYAxisTopText).toHaveBeenCalledWith({ text: 'y-axis-2', type: 'text' }); + expect(mockDB.setYAxisBottomText).toHaveBeenCalledWith({ + text: 'Ability to Execute', + type: 'text', + }); + expect(mockDB.setQuadrant1Text).toHaveBeenCalledWith({ text: 'Leaders', type: 'text' }); + expect(mockDB.setQuadrant2Text).toHaveBeenCalledWith({ text: 'Challengers', type: 'text' }); + expect(mockDB.setQuadrant3Text).toHaveBeenCalledWith({ text: 'Niche', type: 'text' }); + expect(mockDB.setQuadrant4Text).toHaveBeenCalledWith({ text: 'Visionaries', type: 'text' }); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'Microsoft', type: 'text' }, + '', + '0.75', + '0.75', + 'stroke_color: #ff00ff ,stroke_width: 10px, color: #ff0000, radius: 10' + ); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'Salesforce', type: 'text' }, + 'class1', + '0.55', + '0.60', + 'radius: 10, color: #ff0000' + ); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'IBM', type: 'text' }, + '', + '0.51', + '0.40', + 'stroke_color: #ff00ff ,stroke_width: 10px' + ); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'Incorta', type: 'text' }, + '', + '0.20', + '0.30', + 'stroke_width: 10px' + ); }); - expect(mockDB.setQuadrant1Text).toHaveBeenCalledWith({ text: 'Leaders', type: 'text' }); - expect(mockDB.setQuadrant2Text).toHaveBeenCalledWith({ text: 'Challengers', type: 'text' }); - expect(mockDB.setQuadrant3Text).toHaveBeenCalledWith({ text: 'Niche', type: 'text' }); - expect(mockDB.setQuadrant4Text).toHaveBeenCalledWith({ text: 'Visionaries', type: 'text' }); - expect(mockDB.addPoint).toHaveBeenCalledWith( - { text: 'Microsoft', type: 'text' }, - '0.75', - '0.75', - 'stroke_color: #ff00ff ,stroke_width: 10px, color: #ff0000, radius: 10' - ); - expect(mockDB.addPoint).toHaveBeenCalledWith( - { text: 'Salesforce', type: 'text' }, - '0.55', - '0.60', - 'radius: 10, color: #ff0000' - ); - expect(mockDB.addPoint).toHaveBeenCalledWith( - { text: 'IBM', type: 'text' }, - '0.51', - '0.40', - 'stroke_color: #ff00ff ,stroke_width: 10px' - ); - expect(mockDB.addPoint).toHaveBeenCalledWith( - { text: 'Incorta', type: 'text' }, - '0.20', - '0.30', - 'stroke_width: 10px' - ); }); diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts index a75906902b..1c7d2be194 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts @@ -10,8 +10,17 @@ const defaultThemeVariables = getThemeVariables(); export type TextVerticalPos = 'left' | 'center' | 'right'; export type TextHorizontalPos = 'top' | 'middle' | 'bottom'; +export interface stylesObject { + className?: string; + radius?: number; + color?: string; + strokeColor?: string; + strokeWidth?: string; +} + export interface QuadrantPointInputType extends Point { text: string; + className?: string; radius?: number; color?: string; strokeColor?: string; @@ -123,6 +132,7 @@ export class QuadrantBuilder { private config: QuadrantBuilderConfig; private themeConfig: QuadrantBuilderThemeConfig; private data: quadrantBuilderData; + private classes: stylesObject[] = []; constructor() { this.config = this.getDefaultConfig(); @@ -208,6 +218,13 @@ export class QuadrantBuilder { this.data.points = [...points, ...this.data.points]; } + addClass(className: string, styles: stylesObject) { + this.classes.push({ + className, + ...styles, + }); + } + setConfig(config: Partial) { log.trace('setConfig called with: ', config); this.config = { ...this.config, ...config }; @@ -476,6 +493,21 @@ export class QuadrantBuilder { .range([quadrantHeight + quadrantTop, quadrantTop]); const points: QuadrantPointType[] = this.data.points.map((point) => { + const classStyles = this.classes.find((obj) => obj.className === point.className); + if (classStyles !== undefined) { + if (classStyles.color !== undefined) { + point.color = classStyles.color; + } + if (classStyles.radius !== undefined) { + point.radius = classStyles.radius; + } + if (classStyles.strokeColor !== undefined) { + point.strokeColor = classStyles.strokeColor; + } + if (classStyles.strokeWidth !== undefined) { + point.strokeWidth = classStyles.strokeWidth; + } + } const props: QuadrantPointType = { x: xAxis(point.x), y: yAxis(point.y), diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts index e4edb0b042..3344f76e4f 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts @@ -9,6 +9,7 @@ import { setAccDescription, clear as commonClear, } from '../common/commonDb.js'; +import type { stylesObject } from './quadrantBuilder.js'; import { QuadrantBuilder } from './quadrantBuilder.js'; const config = getConfig(); @@ -53,43 +54,63 @@ function setYAxisBottomText(textObj: LexTextObj) { quadrantBuilder.setData({ yAxisBottomText: textSanitizer(textObj.text) }); } -function addPoint(textObj: LexTextObj, x: number, y: number, styles_string: string) { - const styles_object: { - radius?: number; - color?: string; - strokeColor?: string; - strokeWidth?: string; - } = {}; - if (styles_string !== '') { - const styles = styles_string.trim().split(/\s*,\s*/); +function parseStyles(stylesString: string): stylesObject { + const stylesObject: stylesObject = {}; + if (stylesString !== '') { + const styles = stylesString.trim().split(/\s*,\s*/); for (const item of styles) { const style = item.split(/\s*:\s*/); if (style[0] == 'radius') { - styles_object.radius = parseInt(style[1]); + stylesObject.radius = parseInt(style[1]); } else if (style[0] == 'color') { - styles_object.color = style[1]; - } else if (style[0] == 'strokeColor') { - styles_object.strokeColor = style[1]; - } else if (style[0] == 'strokeWidth') { - styles_object.strokeWidth = style[1]; + stylesObject.color = style[1]; + } else if (style[0] == 'stroke-color') { + stylesObject.strokeColor = style[1]; + } else if (style[0] == 'stroke-width') { + stylesObject.strokeWidth = style[1]; } else { - // do we add error if an unknown style is added or do we ignore it + // do we add error if an unknown style is added or do we ignore it ??? } } } + return stylesObject; +} + +function addPoint( + textObj: LexTextObj, + className: string, + x: number, + y: number, + stylesString: string +) { + const stylesObject = parseStyles(stylesString); quadrantBuilder.addPoints([ { x, y, + className: className, text: textSanitizer(textObj.text), - radius: styles_object.radius, - color: styles_object.color, - strokeColor: styles_object.strokeColor, - strokeWidth: styles_object.strokeWidth, + radius: stylesObject.radius, + color: stylesObject.color, + strokeColor: stylesObject.strokeColor, + strokeWidth: stylesObject.strokeWidth, }, ]); } +function addClass(stylesString: string) { + const ind = stylesString.indexOf(' '); + const className = stylesString.slice(0, ind); + const styles = parseStyles(stylesString.slice(ind + 1)); + if (className === undefined || className === '') { + // throw error + } + if (Object.keys(styles).length === 0) { + // no styles added, throw error ??? + } + quadrantBuilder.addClass(className, styles); +} + function setWidth(width: number) { quadrantBuilder.setConfig({ chartWidth: width }); } @@ -142,6 +163,7 @@ export default { setYAxisTopText, setYAxisBottomText, addPoint, + addClass, getQuadrantData, clear, setAccTitle, From 0d8016d9261bdb27faab658ef696314fb02885e5 Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Sat, 13 Jan 2024 12:30:41 +0000 Subject: [PATCH 05/18] cypress tests --- .../rendering/quadrantChart.spec.js | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/cypress/integration/rendering/quadrantChart.spec.js b/cypress/integration/rendering/quadrantChart.spec.js index fa2410da08..4f9002c65f 100644 --- a/cypress/integration/rendering/quadrantChart.spec.js +++ b/cypress/integration/rendering/quadrantChart.spec.js @@ -242,8 +242,35 @@ describe('Quadrant Chart', () => { Campaign B: [0.45, 0.23] color: #ff0000 Campaign C: [0.57, 0.69] stroke_color: #ff00ff Campaign D: [0.78, 0.34] stroke_width: 3px - Campaign E: [0.40, 0.34] radius: 20 color: #ff0000 stroke_color: #ff00ff stroke_width: 3px - Campaign F: [0.35, 0.78] + Campaign E: [0.40, 0.34] radius: 20, color: #ff0000, stroke_color: #ff00ff, stroke_width: 3px + Campaign F: [0.35, 0.78] stroke_width: 3px, color: #ff0000, radius: 20, stroke_color: #ff00ff + Campaign G: [0.22, 0.22] stroke_width: 3px, color: #309708, radius: 20, stroke_color: #5060ff + Campaign H: [0.22, 0.44] + `, + {} + ); + cy.get('svg'); + }); + + it('it should render data points with styles + classes', () => { + imgSnapshotTest( + ` + quadrantChart + title Reach and engagement of campaigns + x-axis Reach --> + y-axis Engagement --> + quadrant-1 We should expand + quadrant-2 Need to promote + quadrant-3 Re-evaluate + quadrant-4 May be improved + Campaign A:::class1: [0.3, 0.6] radius: 20 + Campaign B: [0.45, 0.23] color: #ff0000 + Campaign C: [0.57, 0.69] stroke_color: #ff00ff + Campaign D:::class2: [0.78, 0.34] stroke_width: 3px + Campaign E:::class2: [0.40, 0.34] radius: 20 color: #ff0000, stroke_color: #ff00ff, stroke_width: 3px + Campaign F:::class1: [0.35, 0.78] + classDef class1 color: #908342, radius : 10, stroke-color: #310085, stroke-width: 10px + classDef class2 color: #f00fff, radius : 10 `, {} ); From 2640120be82641bd15804249a1dc09926b83144b Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Tue, 6 Feb 2024 22:18:17 +0000 Subject: [PATCH 06/18] fixed parsing for classes and styles are in jison --- .../quadrant-chart/parser/quadrant.jison | 40 +++++++-- .../parser/quadrant.jison.spec.ts | 82 +++---------------- .../quadrant-chart/quadrantBuilder.ts | 7 +- .../src/diagrams/quadrant-chart/quadrantDb.ts | 38 +++------ 4 files changed, 60 insertions(+), 107 deletions(-) diff --git a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison index 8ea4160ffb..dc2314fc36 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison +++ b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison @@ -11,8 +11,6 @@ %x point_start %x point_x %x point_y -%x styles_string -%x class_styles %x class_name %% \%\%(?!\{)[^\n]* /* skip comments */ @@ -38,6 +36,7 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multiline");} " "*"quadrant-2"" "* return 'QUADRANT_2'; " "*"quadrant-3"" "* return 'QUADRANT_3'; " "*"quadrant-4"" "* return 'QUADRANT_4'; +"classDef" return 'CLASSDEF'; ["][`] { this.begin("md_string");} [^`"]+ { return "MD_STR";} @@ -51,12 +50,9 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multiline");} \s*\:\s*\[\s* {this.begin("point_start"); return 'point_start';} (1)|(0(.\d+)?) {this.begin('point_x'); return 'point_x';} -\s*\]" "* {this.popState(); this.begin('styles_string')} -.* {this.popState(); return 'styles_string';} +\s*\]" "* {this.popState();} \s*\,\s* {this.popState(); this.begin('point_y');} (1)|(0(.\d+)?) {this.popState(); return 'point_y';} -\s*classDef\s* {this.begin('class_styles')} -.* {this.popState(); yy.addClass(this.match);} " "*"quadrantChart"" "* return 'QUADRANT'; @@ -84,6 +80,31 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multiline");} %% /* language grammar */ +idStringToken : ALPHA | NUM | NODE_STRING | DOWN | MINUS | DEFAULT | COMMA | COLON | AMP | BRKT | MULT | UNICODE_TEXT; +styleComponent: ALPHA | NUM | NODE_STRING | COLON | UNIT | SPACE | BRKT | STYLE | PCT | MINUS ; + +idString + :idStringToken + {$$=$idStringToken} + | idString idStringToken + {$$=$idString+''+$idStringToken} + ; + +style: styleComponent + |style styleComponent + {$$ = $style + $styleComponent;} + ; + +stylesOpt: style + {$$ = [$style]} + | stylesOpt COMMA style + {$stylesOpt.push($style);$$ = $stylesOpt;} + ; + +classDefStatement + : CLASSDEF SPACE idString SPACE stylesOpt {$$ = $CLASSDEF;yy.addClass($idString,$stylesOpt);} + ; + start : eol start | SPACE start @@ -101,6 +122,7 @@ line statement : + | classDefStatement {$$=[];} | SPACE statement | axisDetails | quadrantDetails @@ -112,8 +134,10 @@ statement ; points - : text point_start point_x point_y styles_string {yy.addPoint($1, "", $3, $4, $5);} - | text class_name point_start point_x point_y styles_string {yy.addPoint($1, $2, $4, $5, $6);} + : text point_start point_x point_y {yy.addPoint($1, "", $3, $4, []);} + | text class_name point_start point_x point_y {yy.addPoint($1, $2, $4, $5, []);} + | text point_start point_x point_y stylesOpt {yy.addPoint($1, "", $3, $4, $stylesOpt);} + | text class_name point_start point_x point_y stylesOpt {yy.addPoint($1, $2, $4, $5, $stylesOpt);} ; axisDetails diff --git a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts index 9462d98de9..dc63d40da6 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts @@ -278,8 +278,8 @@ describe('Testing quadrantChart jison file', () => { quadrant-4 Visionaries Microsoft: [0.75, 0.75] radius: 10 Salesforce: [0.55, 0.60] radius: 10, color: #ff0000 - IBM: [0.51, 0.40] radius: 10, color: #ff0000, stroke_color: #ff00ff - Incorta: [0.20, 0.30] radius: 10 ,color: #ff0000 ,stroke_color: #ff00ff ,stroke_width: 10px`; + IBM: [0.51, 0.40] radius: 10, color: #ff0000, stroke-color: #ff00ff + Incorta: [0.20, 0.30] radius: 10 ,color: #ff0000 ,stroke-color: #ff00ff ,stroke-width: 10px`; expect(parserFnConstructor(str)).not.toThrow(); expect(mockDB.setXAxisLeftText).toHaveBeenCalledWith({ @@ -308,79 +308,21 @@ describe('Testing quadrantChart jison file', () => { '', '0.55', '0.60', - 'radius: 10, color: #ff0000' + ['radius: 10', 'color: #ff0000'] ); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'IBM', type: 'text' }, '', '0.51', '0.40', - 'radius: 10, color: #ff0000, stroke_color: #ff00ff' + ['radius: 10', 'color: #ff0000', 'stroke-color: #ff00ff'] ); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'Incorta', type: 'text' }, '', '0.20', '0.30', - 'radius: 10 ,color: #ff0000 ,stroke_color: #ff00ff ,stroke_width: 10px' - ); - }); - it('should be able to parse the whole chart with point styling with 1 param', () => { - const str = `quadrantChart - title Analytics and Business Intelligence Platforms - x-axis "Completeness of Vision ❤" --> "x-axis-2" - y-axis Ability to Execute --> "y-axis-2" - quadrant-1 Leaders - quadrant-2 Challengers - quadrant-3 Niche - quadrant-4 Visionaries - Microsoft: [0.75, 0.75] radius: 10 - Salesforce: [0.55, 0.60] color: #ff0000 - IBM: [0.51, 0.40] stroke_color: #ff00ff - Incorta: [0.20, 0.30] stroke_width: 10px`; - - expect(parserFnConstructor(str)).not.toThrow(); - expect(mockDB.setXAxisLeftText).toHaveBeenCalledWith({ - text: 'Completeness of Vision ❤', - type: 'text', - }); - expect(mockDB.setXAxisRightText).toHaveBeenCalledWith({ text: 'x-axis-2', type: 'text' }); - expect(mockDB.setYAxisTopText).toHaveBeenCalledWith({ text: 'y-axis-2', type: 'text' }); - expect(mockDB.setYAxisBottomText).toHaveBeenCalledWith({ - text: 'Ability to Execute', - type: 'text', - }); - expect(mockDB.setQuadrant1Text).toHaveBeenCalledWith({ text: 'Leaders', type: 'text' }); - expect(mockDB.setQuadrant2Text).toHaveBeenCalledWith({ text: 'Challengers', type: 'text' }); - expect(mockDB.setQuadrant3Text).toHaveBeenCalledWith({ text: 'Niche', type: 'text' }); - expect(mockDB.setQuadrant4Text).toHaveBeenCalledWith({ text: 'Visionaries', type: 'text' }); - expect(mockDB.addPoint).toHaveBeenCalledWith( - { text: 'Microsoft', type: 'text' }, - '', - '0.75', - '0.75', - 'radius: 10' - ); - expect(mockDB.addPoint).toHaveBeenCalledWith( - { text: 'Salesforce', type: 'text' }, - '', - '0.55', - '0.60', - 'color: #ff0000' - ); - expect(mockDB.addPoint).toHaveBeenCalledWith( - { text: 'IBM', type: 'text' }, - '', - '0.51', - '0.40', - 'stroke_color: #ff00ff' - ); - expect(mockDB.addPoint).toHaveBeenCalledWith( - { text: 'Incorta', type: 'text' }, - '', - '0.20', - '0.30', - 'stroke_width: 10px' + ['radius: 10', 'color: #ff0000', 'stroke-color: #ff00ff', 'stroke-width: 10px'] ); }); @@ -393,10 +335,10 @@ describe('Testing quadrantChart jison file', () => { quadrant-2 Challengers quadrant-3 Niche quadrant-4 Visionaries - Microsoft: [0.75, 0.75] stroke_color: #ff00ff ,stroke_width: 10px, color: #ff0000, radius: 10 + Microsoft: [0.75, 0.75] stroke-color: #ff00ff ,stroke-width: 10px, color: #ff0000, radius: 10 Salesforce:::class1: [0.55, 0.60] radius: 10, color: #ff0000 - IBM: [0.51, 0.40] stroke_color: #ff00ff ,stroke_width: 10px - Incorta: [0.20, 0.30] stroke_width: 10px`; + IBM: [0.51, 0.40] stroke-color: #ff00ff ,stroke-width: 10px + Incorta: [0.20, 0.30] stroke-width: 10px`; expect(parserFnConstructor(str)).not.toThrow(); expect(mockDB.setXAxisLeftText).toHaveBeenCalledWith({ @@ -418,28 +360,28 @@ describe('Testing quadrantChart jison file', () => { '', '0.75', '0.75', - 'stroke_color: #ff00ff ,stroke_width: 10px, color: #ff0000, radius: 10' + ['stroke-color: #ff00ff', 'stroke-width: 10px', 'color: #ff0000', 'radius: 10'] ); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'Salesforce', type: 'text' }, 'class1', '0.55', '0.60', - 'radius: 10, color: #ff0000' + ['radius: 10', 'color: #ff0000'] ); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'IBM', type: 'text' }, '', '0.51', '0.40', - 'stroke_color: #ff00ff ,stroke_width: 10px' + ['stroke-color: #ff00ff', 'stroke-width: 10px'] ); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'Incorta', type: 'text' }, '', '0.20', '0.30', - 'stroke_width: 10px' + ['stroke-width: 10px'] ); }); }); diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts index 4d20de7b76..9da6026c5b 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts @@ -10,7 +10,7 @@ const defaultThemeVariables = getThemeVariables(); export type TextVerticalPos = 'left' | 'center' | 'right'; export type TextHorizontalPos = 'top' | 'middle' | 'bottom'; -export interface stylesObject { +export interface StylesObject { className?: string; radius?: number; color?: string; @@ -132,8 +132,7 @@ export class QuadrantBuilder { private config: QuadrantBuilderConfig; private themeConfig: QuadrantBuilderThemeConfig; private data: QuadrantBuilderData; - private data: quadrantBuilderData; - private classes: stylesObject[] = []; + private classes: StylesObject[] = []; constructor() { this.config = this.getDefaultConfig(); @@ -219,7 +218,7 @@ export class QuadrantBuilder { this.data.points = [...points, ...this.data.points]; } - addClass(className: string, styles: stylesObject) { + addClass(className: string, styles: StylesObject) { this.classes.push({ className, ...styles, diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts index 3344f76e4f..8c43eb9de6 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts @@ -9,7 +9,7 @@ import { setAccDescription, clear as commonClear, } from '../common/commonDb.js'; -import type { stylesObject } from './quadrantBuilder.js'; +import type { StylesObject } from './quadrantBuilder.js'; import { QuadrantBuilder } from './quadrantBuilder.js'; const config = getConfig(); @@ -54,12 +54,11 @@ function setYAxisBottomText(textObj: LexTextObj) { quadrantBuilder.setData({ yAxisBottomText: textSanitizer(textObj.text) }); } -function parseStyles(stylesString: string): stylesObject { - const stylesObject: stylesObject = {}; - if (stylesString !== '') { - const styles = stylesString.trim().split(/\s*,\s*/); +function parseStyles(styles: string[]): StylesObject { + const stylesObject: StylesObject = {}; + if (styles.length !== 0) { for (const item of styles) { - const style = item.split(/\s*:\s*/); + const style = item.trim().split(/\s*:\s*/); if (style[0] == 'radius') { stylesObject.radius = parseInt(style[1]); } else if (style[0] == 'color') { @@ -69,21 +68,15 @@ function parseStyles(stylesString: string): stylesObject { } else if (style[0] == 'stroke-width') { stylesObject.strokeWidth = style[1]; } else { - // do we add error if an unknown style is added or do we ignore it ??? + throw new Error(`stlye named ${style[0]} is unacceptable`); } } } return stylesObject; } -function addPoint( - textObj: LexTextObj, - className: string, - x: number, - y: number, - stylesString: string -) { - const stylesObject = parseStyles(stylesString); +function addPoint(textObj: LexTextObj, className: string, x: number, y: number, styles: string[]) { + const stylesObject = parseStyles(styles); quadrantBuilder.addPoints([ { x, @@ -98,17 +91,12 @@ function addPoint( ]); } -function addClass(stylesString: string) { - const ind = stylesString.indexOf(' '); - const className = stylesString.slice(0, ind); - const styles = parseStyles(stylesString.slice(ind + 1)); - if (className === undefined || className === '') { - // throw error +function addClass(className: string, styles: string[]) { + const ss = parseStyles(styles); + if (Object.keys(ss).length === 0) { + throw new Error('class defintions require ss'); } - if (Object.keys(styles).length === 0) { - // no styles added, throw error ??? - } - quadrantBuilder.addClass(className, styles); + quadrantBuilder.addClass(className, ss); } function setWidth(width: number) { From 17959f648a7c72ceef6e23b6966c90fb8e3b89be Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Wed, 7 Feb 2024 00:21:33 +0000 Subject: [PATCH 07/18] various fixes + add unit tests for parsed styles --- .../rendering/quadrantChart.spec.js | 20 ++++---- .../quadrant-chart/parser/quadrant.jison | 4 +- .../parser/quadrant.jison.spec.ts | 46 +++++++++++++++---- .../quadrant-chart/quadrantDb.spec.ts | 28 +++++++++++ .../src/diagrams/quadrant-chart/quadrantDb.ts | 7 +-- 5 files changed, 79 insertions(+), 26 deletions(-) create mode 100644 packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts diff --git a/cypress/integration/rendering/quadrantChart.spec.js b/cypress/integration/rendering/quadrantChart.spec.js index 4f9002c65f..8a64638f39 100644 --- a/cypress/integration/rendering/quadrantChart.spec.js +++ b/cypress/integration/rendering/quadrantChart.spec.js @@ -240,11 +240,11 @@ describe('Quadrant Chart', () => { quadrant-4 May be improved Campaign A: [0.3, 0.6] radius: 20 Campaign B: [0.45, 0.23] color: #ff0000 - Campaign C: [0.57, 0.69] stroke_color: #ff00ff - Campaign D: [0.78, 0.34] stroke_width: 3px - Campaign E: [0.40, 0.34] radius: 20, color: #ff0000, stroke_color: #ff00ff, stroke_width: 3px - Campaign F: [0.35, 0.78] stroke_width: 3px, color: #ff0000, radius: 20, stroke_color: #ff00ff - Campaign G: [0.22, 0.22] stroke_width: 3px, color: #309708, radius: 20, stroke_color: #5060ff + Campaign C: [0.57, 0.69] stroke-color: #ff00ff + Campaign D: [0.78, 0.34] stroke-width: 3px + Campaign E: [0.40, 0.34] radius: 20, color: #ff0000, stroke-color: #ff00ff, stroke-width: 3px + Campaign F: [0.35, 0.78] stroke-width: 3px, color: #ff0000, radius: 20, stroke-color: #ff00ff + Campaign G: [0.22, 0.22] stroke-width: 3px, color: #309708, radius: 20, stroke-color: #5060ff Campaign H: [0.22, 0.44] `, {} @@ -265,15 +265,13 @@ describe('Quadrant Chart', () => { quadrant-4 May be improved Campaign A:::class1: [0.3, 0.6] radius: 20 Campaign B: [0.45, 0.23] color: #ff0000 - Campaign C: [0.57, 0.69] stroke_color: #ff00ff - Campaign D:::class2: [0.78, 0.34] stroke_width: 3px - Campaign E:::class2: [0.40, 0.34] radius: 20 color: #ff0000, stroke_color: #ff00ff, stroke_width: 3px + Campaign C: [0.57, 0.69] stroke-color: #ff00ff + Campaign D:::class2: [0.78, 0.34] stroke-width: 3px + Campaign E:::class2: [0.40, 0.34] radius: 20 color: #ff0000, stroke-color: #ff00ff, stroke-width: 3px Campaign F:::class1: [0.35, 0.78] classDef class1 color: #908342, radius : 10, stroke-color: #310085, stroke-width: 10px classDef class2 color: #f00fff, radius : 10 - `, - {} + ` ); - cy.get('svg'); }); }); diff --git a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison index dc2314fc36..85e82b6b57 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison +++ b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison @@ -96,9 +96,9 @@ style: styleComponent ; stylesOpt: style - {$$ = [$style]} + {$$ = [$style.trim()]} | stylesOpt COMMA style - {$stylesOpt.push($style);$$ = $stylesOpt;} + {$stylesOpt.push($style.trim());$$ = $stylesOpt;} ; classDefStatement diff --git a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts index dc63d40da6..98185ba8ae 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts @@ -203,20 +203,34 @@ describe('Testing quadrantChart jison file', () => { it('should be able to parse points', () => { let str = 'quadrantChart\npoint1: [0.1, 0.4]'; expect(parserFnConstructor(str)).not.toThrow(); - expect(mockDB.addPoint).toHaveBeenCalledWith({ text: 'point1', type: 'text' }, '0.1', '0.4'); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'point1', type: 'text' }, + '', + '0.1', + '0.4', + [] + ); clearMocks(); str = 'QuadRantChart \n Point1 : [0.1, 0.4] '; expect(parserFnConstructor(str)).not.toThrow(); - expect(mockDB.addPoint).toHaveBeenCalledWith({ text: 'Point1', type: 'text' }, '0.1', '0.4'); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'Point1', type: 'text' }, + '', + '0.1', + '0.4', + [] + ); clearMocks(); str = 'QuadRantChart \n "Point1 : (* +=[❤": [1, 0] '; expect(parserFnConstructor(str)).not.toThrow(); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'Point1 : (* +=[❤', type: 'text' }, + '', '1', - '0' + '0', + [] ); clearMocks(); @@ -255,16 +269,32 @@ describe('Testing quadrantChart jison file', () => { expect(mockDB.setQuadrant4Text).toHaveBeenCalledWith({ text: 'Visionaries', type: 'text' }); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'Microsoft', type: 'text' }, + '', + '0.75', '0.75', - '0.75' + [] ); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'Salesforce', type: 'text' }, + '', '0.55', - '0.60' + '0.60', + [] + ); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'IBM', type: 'text' }, + '', + '0.51', + '0.40', + [] + ); + expect(mockDB.addPoint).toHaveBeenCalledWith( + { text: 'Incorta', type: 'text' }, + '', + '0.20', + '0.30', + [] ); - expect(mockDB.addPoint).toHaveBeenCalledWith({ text: 'IBM', type: 'text' }, '0.51', '0.40'); - expect(mockDB.addPoint).toHaveBeenCalledWith({ text: 'Incorta', type: 'text' }, '0.20', '0.30'); }); it('should be able to parse the whole chart with point styling with all params or some params', () => { @@ -301,7 +331,7 @@ describe('Testing quadrantChart jison file', () => { '', '0.75', '0.75', - 'radius: 10' + ['radius: 10'] ); expect(mockDB.addPoint).toHaveBeenCalledWith( { text: 'Salesforce', type: 'text' }, diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts new file mode 100644 index 0000000000..995a3e2d67 --- /dev/null +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts @@ -0,0 +1,28 @@ +import quadrantDb from './quadrantDb.js'; + +describe('quadrant unit tests', () => { + it('should parse the styles array and return a StylesObject', () => { + const styles = ['radius: 10', 'color: #ff0000', 'stroke-color: #ff00ff', 'stroke-width: 10px']; + const result = quadrantDb.parseStyles(styles); + + expect(result).toEqual({ + radius: 10, + color: '#ff0000', + strokeColor: '#ff00ff', + strokeWidth: '10px', + }); + }); + + it('should throw an error for unacceptable style name', () => { + const styles: string[] = ['test_name: value']; + expect(() => quadrantDb.parseStyles(styles)).toThrowError( + 'stlye named test_name is unacceptable' + ); + }); + + it('should return an empty StylesObject for an empty input array', () => { + const styles: string[] = []; + const result = quadrantDb.parseStyles(styles); + expect(result).toEqual({}); + }); +}); diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts index 8c43eb9de6..b4e9d38f9f 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts @@ -92,11 +92,7 @@ function addPoint(textObj: LexTextObj, className: string, x: number, y: number, } function addClass(className: string, styles: string[]) { - const ss = parseStyles(styles); - if (Object.keys(ss).length === 0) { - throw new Error('class defintions require ss'); - } - quadrantBuilder.addClass(className, ss); + quadrantBuilder.addClass(className, parseStyles(styles)); } function setWidth(width: number) { @@ -150,6 +146,7 @@ export default { setXAxisRightText, setYAxisTopText, setYAxisBottomText, + parseStyles, addPoint, addClass, getQuadrantData, From c1cb171071c053f5cafbdb6b3ebfecd043caf5ca Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Wed, 7 Feb 2024 00:57:05 +0000 Subject: [PATCH 08/18] added styles values validation + unit tests --- .../quadrant-chart/quadrantDb.spec.ts | 22 +++++++++++++++++++ .../src/diagrams/quadrant-chart/quadrantDb.ts | 16 ++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts index 995a3e2d67..a0d0f65a74 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts @@ -25,4 +25,26 @@ describe('quadrant unit tests', () => { const result = quadrantDb.parseStyles(styles); expect(result).toEqual({}); }); + + it('should throw an error for unacceptable style value', () => { + let styles: string[] = ['radius: f']; + expect(() => quadrantDb.parseStyles(styles)).toThrowError( + 'value for radius f is unvalid, requires a number' + ); + + styles = ['color: ffaa']; + expect(() => quadrantDb.parseStyles(styles)).toThrowError( + 'value for color ffaa is unvalid, requires a valid hex code' + ); + + styles = ['stroke-color: #f677779']; + expect(() => quadrantDb.parseStyles(styles)).toThrowError( + 'value for stroke-color #f677779 is unvalid, requires a valid hex code' + ); + + styles = ['stroke-width: 30']; + expect(() => quadrantDb.parseStyles(styles)).toThrowError( + 'value for stroke-width 30 is unvalid, requires a valid number of pixels (eg. 10px)' + ); + }); }); diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts index b4e9d38f9f..9d8dbe7329 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts @@ -60,12 +60,28 @@ function parseStyles(styles: string[]): StylesObject { for (const item of styles) { const style = item.trim().split(/\s*:\s*/); if (style[0] == 'radius') { + if (!/^\d+$/.test(style[1])) { + throw new Error(`value for radius ${style[1]} is unvalid, requires a number`); + } stylesObject.radius = parseInt(style[1]); } else if (style[0] == 'color') { + if (!/^#?([\dA-Fa-f]{6}|[\dA-Fa-f]{3})$/.test(style[1])) { + throw new Error(`value for color ${style[1]} is unvalid, requires a valid hex code`); + } stylesObject.color = style[1]; } else if (style[0] == 'stroke-color') { + if (!/^#?([\dA-Fa-f]{6}|[\dA-Fa-f]{3})$/.test(style[1])) { + throw new Error( + `value for stroke-color ${style[1]} is unvalid, requires a valid hex code` + ); + } stylesObject.strokeColor = style[1]; } else if (style[0] == 'stroke-width') { + if (!/^\d+px$/.test(style[1])) { + throw new Error( + `value for stroke-width ${style[1]} is unvalid, requires a valid number of pixels (eg. 10px)` + ); + } stylesObject.strokeWidth = style[1]; } else { throw new Error(`stlye named ${style[0]} is unacceptable`); From 8ad056b8a2ab1c7f7bc513fe7a7030bd65ec3bba Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Wed, 7 Feb 2024 01:20:04 +0000 Subject: [PATCH 09/18] 1 tiny typo --- cypress/integration/rendering/quadrantChart.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/integration/rendering/quadrantChart.spec.js b/cypress/integration/rendering/quadrantChart.spec.js index 8a64638f39..512a82468d 100644 --- a/cypress/integration/rendering/quadrantChart.spec.js +++ b/cypress/integration/rendering/quadrantChart.spec.js @@ -267,7 +267,7 @@ describe('Quadrant Chart', () => { Campaign B: [0.45, 0.23] color: #ff0000 Campaign C: [0.57, 0.69] stroke-color: #ff00ff Campaign D:::class2: [0.78, 0.34] stroke-width: 3px - Campaign E:::class2: [0.40, 0.34] radius: 20 color: #ff0000, stroke-color: #ff00ff, stroke-width: 3px + Campaign E:::class2: [0.40, 0.34] radius: 20, color: #ff0000, stroke-color: #ff00ff, stroke-width: 3px Campaign F:::class1: [0.35, 0.78] classDef class1 color: #908342, radius : 10, stroke-color: #310085, stroke-width: 10px classDef class2 color: #f00fff, radius : 10 From f1aa6fff9c2966b06b4bc17af3619b356f0cc618 Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Sun, 11 Feb 2024 18:56:33 +0000 Subject: [PATCH 10/18] some fixes --- .../rendering/quadrantChart.spec.js | 12 ++-- .../quadrant-chart/quadrantBuilder.ts | 29 +++------ .../quadrant-chart/quadrantDb.spec.ts | 8 +-- .../src/diagrams/quadrant-chart/quadrantDb.ts | 65 +++++++++---------- .../src/diagrams/quadrant-chart/utils.ts | 20 ++++++ 5 files changed, 70 insertions(+), 64 deletions(-) create mode 100644 packages/mermaid/src/diagrams/quadrant-chart/utils.ts diff --git a/cypress/integration/rendering/quadrantChart.spec.js b/cypress/integration/rendering/quadrantChart.spec.js index 512a82468d..64e198ac18 100644 --- a/cypress/integration/rendering/quadrantChart.spec.js +++ b/cypress/integration/rendering/quadrantChart.spec.js @@ -239,12 +239,12 @@ describe('Quadrant Chart', () => { quadrant-3 Re-evaluate quadrant-4 May be improved Campaign A: [0.3, 0.6] radius: 20 - Campaign B: [0.45, 0.23] color: #ff0000 - Campaign C: [0.57, 0.69] stroke-color: #ff00ff - Campaign D: [0.78, 0.34] stroke-width: 3px - Campaign E: [0.40, 0.34] radius: 20, color: #ff0000, stroke-color: #ff00ff, stroke-width: 3px - Campaign F: [0.35, 0.78] stroke-width: 3px, color: #ff0000, radius: 20, stroke-color: #ff00ff - Campaign G: [0.22, 0.22] stroke-width: 3px, color: #309708, radius: 20, stroke-color: #5060ff + Campaign B: [0.45, 0.23] color: #ff0000 + Campaign C: [0.57, 0.69] stroke-color: #ff00ff + Campaign D: [0.78, 0.34] stroke-width: 3px + Campaign E: [0.40, 0.34] radius: 20, color: #ff0000 , stroke-color : #ff00ff, stroke-width : 3px + Campaign F: [0.35, 0.78] stroke-width: 3px , color: #ff0000, radius: 20, stroke-color: #ff00ff + Campaign G: [0.22, 0.22] stroke-width: 3px , color: #309708 , radius : 20 , stroke-color: #5060ff Campaign H: [0.22, 0.44] `, {} diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts index 9da6026c5b..4aaeb45b9e 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts @@ -18,13 +18,8 @@ export interface StylesObject { strokeWidth?: string; } -export interface QuadrantPointInputType extends Point { +export interface QuadrantPointInputType extends Point, StylesObject { text: string; - className?: string; - radius?: number; - color?: string; - strokeColor?: string; - strokeWidth?: string; } export interface QuadrantTextType extends Point { @@ -36,12 +31,12 @@ export interface QuadrantTextType extends Point { rotation: number; } -export interface QuadrantPointType extends Point { +export interface QuadrantPointType + extends Point, + Pick { fill: string; radius: number; text: QuadrantTextType; - strokeColor: string; - strokeWidth: string; } export interface QuadrantQuadrantsType extends Point { @@ -132,7 +127,7 @@ export class QuadrantBuilder { private config: QuadrantBuilderConfig; private themeConfig: QuadrantBuilderThemeConfig; private data: QuadrantBuilderData; - private classes: StylesObject[] = []; + private classes: Record = {}; constructor() { this.config = this.getDefaultConfig(); @@ -219,10 +214,7 @@ export class QuadrantBuilder { } addClass(className: string, styles: StylesObject) { - this.classes.push({ - className, - ...styles, - }); + this.classes[className] = styles; } setConfig(config: Partial) { @@ -493,7 +485,7 @@ export class QuadrantBuilder { .range([quadrantHeight + quadrantTop, quadrantTop]); const points: QuadrantPointType[] = this.data.points.map((point) => { - const classStyles = this.classes.find((obj) => obj.className === point.className); + const classStyles = this.classes[point.className as keyof typeof this.classes]; if (classStyles !== undefined) { if (classStyles.color !== undefined) { point.color = classStyles.color; @@ -511,11 +503,8 @@ export class QuadrantBuilder { const props: QuadrantPointType = { x: xAxis(point.x), y: yAxis(point.y), - fill: - point.color !== undefined && point.color !== '' - ? point.color - : this.themeConfig.quadrantPointFill, - radius: point.radius !== undefined && point.radius ? point.radius : this.config.pointRadius, + fill: point.color || this.themeConfig.quadrantPointFill, + radius: point.radius || this.config.pointRadius, text: { text: point.text, fill: this.themeConfig.quadrantPointTextFill, diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts index a0d0f65a74..9a49a067f9 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts @@ -29,22 +29,22 @@ describe('quadrant unit tests', () => { it('should throw an error for unacceptable style value', () => { let styles: string[] = ['radius: f']; expect(() => quadrantDb.parseStyles(styles)).toThrowError( - 'value for radius f is unvalid, requires a number' + 'value for radius f is invalid, please use a valid number' ); styles = ['color: ffaa']; expect(() => quadrantDb.parseStyles(styles)).toThrowError( - 'value for color ffaa is unvalid, requires a valid hex code' + 'value for color ffaa is invalid, please use a valid hex code' ); styles = ['stroke-color: #f677779']; expect(() => quadrantDb.parseStyles(styles)).toThrowError( - 'value for stroke-color #f677779 is unvalid, requires a valid hex code' + 'value for stroke-color #f677779 is invalid, please use a valid hex code' ); styles = ['stroke-width: 30']; expect(() => quadrantDb.parseStyles(styles)).toThrowError( - 'value for stroke-width 30 is unvalid, requires a valid number of pixels (eg. 10px)' + 'value for stroke-width 30 is invalid, please use a valid number of pixels (eg. 10px)' ); }); }); diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts index 9d8dbe7329..e3da724f81 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts @@ -11,6 +11,12 @@ import { } from '../common/commonDb.js'; import type { StylesObject } from './quadrantBuilder.js'; import { QuadrantBuilder } from './quadrantBuilder.js'; +import { + validateHexCode, + validateSizeInPixels, + validateNumber, + InvalidStyleError, +} from './utils.js'; const config = getConfig(); @@ -56,36 +62,30 @@ function setYAxisBottomText(textObj: LexTextObj) { function parseStyles(styles: string[]): StylesObject { const stylesObject: StylesObject = {}; - if (styles.length !== 0) { - for (const item of styles) { - const style = item.trim().split(/\s*:\s*/); - if (style[0] == 'radius') { - if (!/^\d+$/.test(style[1])) { - throw new Error(`value for radius ${style[1]} is unvalid, requires a number`); - } - stylesObject.radius = parseInt(style[1]); - } else if (style[0] == 'color') { - if (!/^#?([\dA-Fa-f]{6}|[\dA-Fa-f]{3})$/.test(style[1])) { - throw new Error(`value for color ${style[1]} is unvalid, requires a valid hex code`); - } - stylesObject.color = style[1]; - } else if (style[0] == 'stroke-color') { - if (!/^#?([\dA-Fa-f]{6}|[\dA-Fa-f]{3})$/.test(style[1])) { - throw new Error( - `value for stroke-color ${style[1]} is unvalid, requires a valid hex code` - ); - } - stylesObject.strokeColor = style[1]; - } else if (style[0] == 'stroke-width') { - if (!/^\d+px$/.test(style[1])) { - throw new Error( - `value for stroke-width ${style[1]} is unvalid, requires a valid number of pixels (eg. 10px)` - ); - } - stylesObject.strokeWidth = style[1]; - } else { - throw new Error(`stlye named ${style[0]} is unacceptable`); + for (const style of styles) { + const [key, value] = style.trim().split(/\s*:\s*/); + if (key == 'radius') { + if (validateNumber(value)) { + throw new InvalidStyleError(key, value, 'number'); + } + stylesObject.radius = parseInt(value); + } else if (key == 'color') { + if (validateHexCode(value)) { + throw new InvalidStyleError(key, value, 'hex code'); + } + stylesObject.color = value; + } else if (key == 'stroke-color') { + if (validateHexCode(value)) { + throw new InvalidStyleError(key, value, 'hex code'); + } + stylesObject.strokeColor = value; + } else if (key == 'stroke-width') { + if (validateSizeInPixels(value)) { + throw new InvalidStyleError(key, value, 'number of pixels (eg. 10px)'); } + stylesObject.strokeWidth = value; + } else { + throw new Error(`stlye named ${key} is unacceptable`); } } return stylesObject; @@ -97,12 +97,9 @@ function addPoint(textObj: LexTextObj, className: string, x: number, y: number, { x, y, - className: className, text: textSanitizer(textObj.text), - radius: stylesObject.radius, - color: stylesObject.color, - strokeColor: stylesObject.strokeColor, - strokeWidth: stylesObject.strokeWidth, + className, + ...stylesObject, }, ]); } diff --git a/packages/mermaid/src/diagrams/quadrant-chart/utils.ts b/packages/mermaid/src/diagrams/quadrant-chart/utils.ts new file mode 100644 index 0000000000..fca3c8f9a8 --- /dev/null +++ b/packages/mermaid/src/diagrams/quadrant-chart/utils.ts @@ -0,0 +1,20 @@ +class InvalidStyleError extends Error { + constructor(style: string, value: string, type: string) { + super(`value for ${style} ${value} is invalid, please use a valid ${type}`); + this.name = 'InvalidStyleError'; + } +} + +function validateHexCode(value: string): boolean { + return !/^#?([\dA-Fa-f]{6}|[\dA-Fa-f]{3})$/.test(value); +} + +function validateNumber(value: string): boolean { + return !/^\d+$/.test(value); +} + +function validateSizeInPixels(value: string): boolean { + return !/^\d+px$/.test(value); +} + +export { validateHexCode, validateNumber, validateSizeInPixels, InvalidStyleError }; From 358d855c88ae5ccd7c70ccef8319d6afdff2fa09 Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Wed, 6 Mar 2024 13:29:15 +0000 Subject: [PATCH 11/18] fixed typo --- packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts | 2 +- packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts index 9a49a067f9..2d191a26ad 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts @@ -16,7 +16,7 @@ describe('quadrant unit tests', () => { it('should throw an error for unacceptable style name', () => { const styles: string[] = ['test_name: value']; expect(() => quadrantDb.parseStyles(styles)).toThrowError( - 'stlye named test_name is unacceptable' + 'style named test_name is unacceptable' ); }); diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts index e3da724f81..4d0198f46a 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts @@ -85,7 +85,7 @@ function parseStyles(styles: string[]): StylesObject { } stylesObject.strokeWidth = value; } else { - throw new Error(`stlye named ${key} is unacceptable`); + throw new Error(`style named ${key} is unacceptable`); } } return stylesObject; From 29ec8cbd0a31e11d24e04375d3d84ccb6eebf000 Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Sun, 24 Mar 2024 18:48:57 +0000 Subject: [PATCH 12/18] small fixes --- .../mermaid/src/diagrams/quadrant-chart/quadrantDb.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts index 4d0198f46a..babcca7199 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts @@ -64,28 +64,28 @@ function parseStyles(styles: string[]): StylesObject { const stylesObject: StylesObject = {}; for (const style of styles) { const [key, value] = style.trim().split(/\s*:\s*/); - if (key == 'radius') { + if (key === 'radius') { if (validateNumber(value)) { throw new InvalidStyleError(key, value, 'number'); } stylesObject.radius = parseInt(value); - } else if (key == 'color') { + } else if (key === 'color') { if (validateHexCode(value)) { throw new InvalidStyleError(key, value, 'hex code'); } stylesObject.color = value; - } else if (key == 'stroke-color') { + } else if (key === 'stroke-color') { if (validateHexCode(value)) { throw new InvalidStyleError(key, value, 'hex code'); } stylesObject.strokeColor = value; - } else if (key == 'stroke-width') { + } else if (key === 'stroke-width') { if (validateSizeInPixels(value)) { throw new InvalidStyleError(key, value, 'number of pixels (eg. 10px)'); } stylesObject.strokeWidth = value; } else { - throw new Error(`style named ${key} is unacceptable`); + throw new Error(`style named ${key} is not supported.`); } } return stylesObject; From 3b8e6ecc42a232f4262e9a707270848390658058 Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Sun, 24 Mar 2024 18:55:56 +0000 Subject: [PATCH 13/18] small fix (follow) --- .../mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts index 2d191a26ad..2a604304ad 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.spec.ts @@ -13,10 +13,10 @@ describe('quadrant unit tests', () => { }); }); - it('should throw an error for unacceptable style name', () => { + it('should throw an error for non supported style name', () => { const styles: string[] = ['test_name: value']; expect(() => quadrantDb.parseStyles(styles)).toThrowError( - 'style named test_name is unacceptable' + 'style named test_name is not supported.' ); }); @@ -26,7 +26,7 @@ describe('quadrant unit tests', () => { expect(result).toEqual({}); }); - it('should throw an error for unacceptable style value', () => { + it('should throw an error for non supported style value', () => { let styles: string[] = ['radius: f']; expect(() => quadrantDb.parseStyles(styles)).toThrowError( 'value for radius f is invalid, please use a valid number' From 3f95c78428f581289838de6c393dbca21ff5f9e4 Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Tue, 26 Mar 2024 22:44:37 +0000 Subject: [PATCH 14/18] added styling docs --- docs/syntax/quadrantChart.md | 59 ++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/docs/syntax/quadrantChart.md b/docs/syntax/quadrantChart.md index fdf8667792..c41a12bc1b 100644 --- a/docs/syntax/quadrantChart.md +++ b/docs/syntax/quadrantChart.md @@ -102,6 +102,45 @@ Points are used to plot a circle inside the quadrantChart. The syntax is ` 1. `Point 1: [0.75, 0.80]` here the Point 1 will be drawn in the top right quadrant. 2. `Point 2: [0.35, 0.24]` here the Point 2 will be drawn in the bottom left quadrant. + + +### Point styling +Points cant either be styled directly or with defined shared classes +1. direct styling +```md +Point A: [0.9, 0.0] radius: 12 +Point B: [0.8, 0.1] color: #ff3300, radius: 10 +Point C: [0.7, 0.2] radius: 25, color: #00ff33, stroke-color: #10f0f0 +Point D: [0.6, 0.3] radius: 15, stroke-color: #00ff0f, stroke-width: 5px ,color: #ff33f0 +``` +2. classes styling +```md +Point A:::class1: [0.9, 0.0] +Point B:::class2: [0.8, 0.1] +Point C:::class3: [0.7, 0.2] +Point D:::class3: [0.7, 0.2] +classDef class1 color: #109060 +classDef class2 color: #908342, radius : 10, stroke-color: #310085, stroke-width: 10px +classDef class3 color: #f00fff, radius : 10 +``` + + +#### available styles: + +| Parameter | Description | +| -------------------------------- | ------------------------------------------------------------------------| +| color | Fill color of the point | +| radius | Radius of the point | +| stroke-width | Border width of the point | +| stroke-color | Border color of the point (useless when stroke-width is not specified) | + + +```note +class styles take priority over direct styles and direct styles take priority over theme styles +``` + + + ## Chart Configurations | Parameter | Description | Default value | @@ -168,3 +207,23 @@ quadrantChart quadrant-3 Delegate quadrant-4 Delete ``` +## Example on styling +```mermaid +quadrantChart + title Reach and engagement of campaigns + x-axis Low Reach --> High Reach + y-axis Low Engagement --> High Engagement + quadrant-1 We should expand + quadrant-2 Need to promote + quadrant-3 Re-evaluate + quadrant-4 May be improved + Campaign A: [0.9, 0.0] radius: 12 + Campaign B:::class1: [0.8, 0.1] color: #ff3300, radius: 10 + Campaign C: [0.7, 0.2] radius: 25, color: #00ff33, stroke-color: #10f0f0 + Campaign D: [0.6, 0.3] radius: 15, stroke-color: #00ff0f, stroke-width: 5px ,color: #ff33f0 + Campaign E:::class2: [0.5, 0.4] + Campaign F:::class3: [0.4, 0.5] color: #0000ff + classDef class1 color: #109060 + classDef class2 color: #908342, radius : 10, stroke-color: #310085, stroke-width: 10px + classDef class3 color: #f00fff, radius : 10 +``` \ No newline at end of file From 585609b9070af8112ad40958282d91e886339a8b Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Tue, 26 Mar 2024 22:50:27 +0000 Subject: [PATCH 15/18] lint fix --- docs/syntax/quadrantChart.md | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/docs/syntax/quadrantChart.md b/docs/syntax/quadrantChart.md index c41a12bc1b..3b1430dd88 100644 --- a/docs/syntax/quadrantChart.md +++ b/docs/syntax/quadrantChart.md @@ -102,18 +102,21 @@ Points are used to plot a circle inside the quadrantChart. The syntax is ` 1. `Point 1: [0.75, 0.80]` here the Point 1 will be drawn in the top right quadrant. 2. `Point 2: [0.35, 0.24]` here the Point 2 will be drawn in the bottom left quadrant. - - ### Point styling + Points cant either be styled directly or with defined shared classes + 1. direct styling + ```md Point A: [0.9, 0.0] radius: 12 Point B: [0.8, 0.1] color: #ff3300, radius: 10 -Point C: [0.7, 0.2] radius: 25, color: #00ff33, stroke-color: #10f0f0 -Point D: [0.6, 0.3] radius: 15, stroke-color: #00ff0f, stroke-width: 5px ,color: #ff33f0 +Point C: [0.7, 0.2] radius: 25, color: #00ff33, stroke-color: #10f0f0 +Point D: [0.6, 0.3] radius: 15, stroke-color: #00ff0f, stroke-width: 5px ,color: #ff33f0 ``` + 2. classes styling + ```md Point A:::class1: [0.9, 0.0] Point B:::class2: [0.8, 0.1] @@ -124,23 +127,19 @@ classDef class2 color: #908342, radius : 10, stroke-color: #310085, stroke-width classDef class3 color: #f00fff, radius : 10 ``` - #### available styles: -| Parameter | Description | -| -------------------------------- | ------------------------------------------------------------------------| -| color | Fill color of the point | -| radius | Radius of the point | -| stroke-width | Border width of the point | -| stroke-color | Border color of the point (useless when stroke-width is not specified) | - +| Parameter | Description | +| ------------ | ---------------------------------------------------------------------- | +| color | Fill color of the point | +| radius | Radius of the point | +| stroke-width | Border width of the point | +| stroke-color | Border color of the point (useless when stroke-width is not specified) | ```note class styles take priority over direct styles and direct styles take priority over theme styles ``` - - ## Chart Configurations | Parameter | Description | Default value | @@ -207,7 +206,9 @@ quadrantChart quadrant-3 Delegate quadrant-4 Delete ``` + ## Example on styling + ```mermaid quadrantChart title Reach and engagement of campaigns @@ -219,11 +220,11 @@ quadrantChart quadrant-4 May be improved Campaign A: [0.9, 0.0] radius: 12 Campaign B:::class1: [0.8, 0.1] color: #ff3300, radius: 10 - Campaign C: [0.7, 0.2] radius: 25, color: #00ff33, stroke-color: #10f0f0 - Campaign D: [0.6, 0.3] radius: 15, stroke-color: #00ff0f, stroke-width: 5px ,color: #ff33f0 + Campaign C: [0.7, 0.2] radius: 25, color: #00ff33, stroke-color: #10f0f0 + Campaign D: [0.6, 0.3] radius: 15, stroke-color: #00ff0f, stroke-width: 5px ,color: #ff33f0 Campaign E:::class2: [0.5, 0.4] Campaign F:::class3: [0.4, 0.5] color: #0000ff classDef class1 color: #109060 classDef class2 color: #908342, radius : 10, stroke-color: #310085, stroke-width: 10px classDef class3 color: #f00fff, radius : 10 -``` \ No newline at end of file +``` From 253adcb0eb29ea102cc738ea92d3a95c233fb0eb Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Tue, 26 Mar 2024 22:54:01 +0000 Subject: [PATCH 16/18] added docs build --- docs/syntax/quadrantChart.md | 60 ------------------------------------ 1 file changed, 60 deletions(-) diff --git a/docs/syntax/quadrantChart.md b/docs/syntax/quadrantChart.md index 3b1430dd88..fdf8667792 100644 --- a/docs/syntax/quadrantChart.md +++ b/docs/syntax/quadrantChart.md @@ -102,44 +102,6 @@ Points are used to plot a circle inside the quadrantChart. The syntax is ` 1. `Point 1: [0.75, 0.80]` here the Point 1 will be drawn in the top right quadrant. 2. `Point 2: [0.35, 0.24]` here the Point 2 will be drawn in the bottom left quadrant. -### Point styling - -Points cant either be styled directly or with defined shared classes - -1. direct styling - -```md -Point A: [0.9, 0.0] radius: 12 -Point B: [0.8, 0.1] color: #ff3300, radius: 10 -Point C: [0.7, 0.2] radius: 25, color: #00ff33, stroke-color: #10f0f0 -Point D: [0.6, 0.3] radius: 15, stroke-color: #00ff0f, stroke-width: 5px ,color: #ff33f0 -``` - -2. classes styling - -```md -Point A:::class1: [0.9, 0.0] -Point B:::class2: [0.8, 0.1] -Point C:::class3: [0.7, 0.2] -Point D:::class3: [0.7, 0.2] -classDef class1 color: #109060 -classDef class2 color: #908342, radius : 10, stroke-color: #310085, stroke-width: 10px -classDef class3 color: #f00fff, radius : 10 -``` - -#### available styles: - -| Parameter | Description | -| ------------ | ---------------------------------------------------------------------- | -| color | Fill color of the point | -| radius | Radius of the point | -| stroke-width | Border width of the point | -| stroke-color | Border color of the point (useless when stroke-width is not specified) | - -```note -class styles take priority over direct styles and direct styles take priority over theme styles -``` - ## Chart Configurations | Parameter | Description | Default value | @@ -206,25 +168,3 @@ quadrantChart quadrant-3 Delegate quadrant-4 Delete ``` - -## Example on styling - -```mermaid -quadrantChart - title Reach and engagement of campaigns - x-axis Low Reach --> High Reach - y-axis Low Engagement --> High Engagement - quadrant-1 We should expand - quadrant-2 Need to promote - quadrant-3 Re-evaluate - quadrant-4 May be improved - Campaign A: [0.9, 0.0] radius: 12 - Campaign B:::class1: [0.8, 0.1] color: #ff3300, radius: 10 - Campaign C: [0.7, 0.2] radius: 25, color: #00ff33, stroke-color: #10f0f0 - Campaign D: [0.6, 0.3] radius: 15, stroke-color: #00ff0f, stroke-width: 5px ,color: #ff33f0 - Campaign E:::class2: [0.5, 0.4] - Campaign F:::class3: [0.4, 0.5] color: #0000ff - classDef class1 color: #109060 - classDef class2 color: #908342, radius : 10, stroke-color: #310085, stroke-width: 10px - classDef class3 color: #f00fff, radius : 10 -``` From 3357844a1f5b15ed8b2905c837d2390a6b079f2a Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Tue, 16 Apr 2024 08:44:21 +0530 Subject: [PATCH 17/18] feat: Change precedence of styling --- .../rendering/quadrantChart.spec.js | 2 +- .../quadrant-chart/quadrantBuilder.ts | 26 +++++-------------- 2 files changed, 7 insertions(+), 21 deletions(-) diff --git a/cypress/integration/rendering/quadrantChart.spec.js b/cypress/integration/rendering/quadrantChart.spec.js index 64e198ac18..83a1455c6a 100644 --- a/cypress/integration/rendering/quadrantChart.spec.js +++ b/cypress/integration/rendering/quadrantChart.spec.js @@ -1,4 +1,4 @@ -import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts'; +import { imgSnapshotTest } from '../../helpers/util.ts'; describe('Quadrant Chart', () => { it('should render if only chart type is provided', () => { diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts index 4aaeb45b9e..173b4c0780 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantBuilder.ts @@ -1,7 +1,7 @@ import { scaleLinear } from 'd3'; -import { log } from '../../logger.js'; import type { BaseDiagramConfig, QuadrantChartConfig } from '../../config.type.js'; import defaultConfig from '../../defaultConfig.js'; +import { log } from '../../logger.js'; import { getThemeVariables } from '../../themes/theme-default.js'; import type { Point } from '../../types.js'; @@ -202,6 +202,7 @@ export class QuadrantBuilder { this.config = this.getDefaultConfig(); this.themeConfig = this.getDefaultThemeConfig(); this.data = this.getDefaultData(); + this.classes = {}; log.info('clear called'); } @@ -486,19 +487,8 @@ export class QuadrantBuilder { const points: QuadrantPointType[] = this.data.points.map((point) => { const classStyles = this.classes[point.className as keyof typeof this.classes]; - if (classStyles !== undefined) { - if (classStyles.color !== undefined) { - point.color = classStyles.color; - } - if (classStyles.radius !== undefined) { - point.radius = classStyles.radius; - } - if (classStyles.strokeColor !== undefined) { - point.strokeColor = classStyles.strokeColor; - } - if (classStyles.strokeWidth !== undefined) { - point.strokeWidth = classStyles.strokeWidth; - } + if (classStyles) { + point = { ...classStyles, ...point }; } const props: QuadrantPointType = { x: xAxis(point.x), @@ -515,12 +505,8 @@ export class QuadrantBuilder { fontSize: this.config.pointLabelFontSize, rotation: 0, }, - strokeColor: - point.strokeColor !== undefined && point.strokeColor !== '' - ? point.strokeColor - : this.themeConfig.quadrantPointFill, - strokeWidth: - point.strokeWidth !== undefined && point.strokeWidth !== '' ? point.strokeWidth : '0px', + strokeColor: point.strokeColor || this.themeConfig.quadrantPointFill, + strokeWidth: point.strokeWidth || '0px', }; return props; }); From eb4a6fd2ed26baa36ee2cb7ea795345ea1331f4d Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Tue, 16 Apr 2024 08:45:22 +0530 Subject: [PATCH 18/18] docs: Add quadrant point styling Co-authored-by: ilyes-ced <109927235+ilyes-ced@users.noreply.github.com> --- docs/syntax/quadrantChart.md | 83 +++++++++++++++++++ .../mermaid/src/docs/syntax/quadrantChart.md | 63 ++++++++++++++ 2 files changed, 146 insertions(+) diff --git a/docs/syntax/quadrantChart.md b/docs/syntax/quadrantChart.md index fdf8667792..ba80638452 100644 --- a/docs/syntax/quadrantChart.md +++ b/docs/syntax/quadrantChart.md @@ -168,3 +168,86 @@ quadrantChart quadrant-3 Delegate quadrant-4 Delete ``` + +### Point styling + +Points can either be styled directly or with defined shared classes + +1. Direct styling + +```md +Point A: [0.9, 0.0] radius: 12 +Point B: [0.8, 0.1] color: #ff3300, radius: 10 +Point C: [0.7, 0.2] radius: 25, color: #00ff33, stroke-color: #10f0f0 +Point D: [0.6, 0.3] radius: 15, stroke-color: #00ff0f, stroke-width: 5px ,color: #ff33f0 +``` + +2. Classes styling + +```md +Point A:::class1: [0.9, 0.0] +Point B:::class2: [0.8, 0.1] +Point C:::class3: [0.7, 0.2] +Point D:::class3: [0.7, 0.2] +classDef class1 color: #109060 +classDef class2 color: #908342, radius : 10, stroke-color: #310085, stroke-width: 10px +classDef class3 color: #f00fff, radius : 10 +``` + +#### Available styles: + +| Parameter | Description | +| ------------ | ---------------------------------------------------------------------- | +| color | Fill color of the point | +| radius | Radius of the point | +| stroke-width | Border width of the point | +| stroke-color | Border color of the point (useless when stroke-width is not specified) | + +> **Note** +> Order of preference: +> +> 1. Direct styles +> 2. Class styles +> 3. Theme styles + +## Example on styling + +```mermaid-example +quadrantChart + title Reach and engagement of campaigns + x-axis Low Reach --> High Reach + y-axis Low Engagement --> High Engagement + quadrant-1 We should expand + quadrant-2 Need to promote + quadrant-3 Re-evaluate + quadrant-4 May be improved + Campaign A: [0.9, 0.0] radius: 12 + Campaign B:::class1: [0.8, 0.1] color: #ff3300, radius: 10 + Campaign C: [0.7, 0.2] radius: 25, color: #00ff33, stroke-color: #10f0f0 + Campaign D: [0.6, 0.3] radius: 15, stroke-color: #00ff0f, stroke-width: 5px ,color: #ff33f0 + Campaign E:::class2: [0.5, 0.4] + Campaign F:::class3: [0.4, 0.5] color: #0000ff + classDef class1 color: #109060 + classDef class2 color: #908342, radius : 10, stroke-color: #310085, stroke-width: 10px + classDef class3 color: #f00fff, radius : 10 +``` + +```mermaid +quadrantChart + title Reach and engagement of campaigns + x-axis Low Reach --> High Reach + y-axis Low Engagement --> High Engagement + quadrant-1 We should expand + quadrant-2 Need to promote + quadrant-3 Re-evaluate + quadrant-4 May be improved + Campaign A: [0.9, 0.0] radius: 12 + Campaign B:::class1: [0.8, 0.1] color: #ff3300, radius: 10 + Campaign C: [0.7, 0.2] radius: 25, color: #00ff33, stroke-color: #10f0f0 + Campaign D: [0.6, 0.3] radius: 15, stroke-color: #00ff0f, stroke-width: 5px ,color: #ff33f0 + Campaign E:::class2: [0.5, 0.4] + Campaign F:::class3: [0.4, 0.5] color: #0000ff + classDef class1 color: #109060 + classDef class2 color: #908342, radius : 10, stroke-color: #310085, stroke-width: 10px + classDef class3 color: #f00fff, radius : 10 +``` diff --git a/packages/mermaid/src/docs/syntax/quadrantChart.md b/packages/mermaid/src/docs/syntax/quadrantChart.md index d6793aea61..39bbcafa1c 100644 --- a/packages/mermaid/src/docs/syntax/quadrantChart.md +++ b/packages/mermaid/src/docs/syntax/quadrantChart.md @@ -136,3 +136,66 @@ quadrantChart quadrant-3 Delegate quadrant-4 Delete ``` + +### Point styling + +Points can either be styled directly or with defined shared classes + +1. Direct styling + +```md +Point A: [0.9, 0.0] radius: 12 +Point B: [0.8, 0.1] color: #ff3300, radius: 10 +Point C: [0.7, 0.2] radius: 25, color: #00ff33, stroke-color: #10f0f0 +Point D: [0.6, 0.3] radius: 15, stroke-color: #00ff0f, stroke-width: 5px ,color: #ff33f0 +``` + +2. Classes styling + +```md +Point A:::class1: [0.9, 0.0] +Point B:::class2: [0.8, 0.1] +Point C:::class3: [0.7, 0.2] +Point D:::class3: [0.7, 0.2] +classDef class1 color: #109060 +classDef class2 color: #908342, radius : 10, stroke-color: #310085, stroke-width: 10px +classDef class3 color: #f00fff, radius : 10 +``` + +#### Available styles: + +| Parameter | Description | +| ------------ | ---------------------------------------------------------------------- | +| color | Fill color of the point | +| radius | Radius of the point | +| stroke-width | Border width of the point | +| stroke-color | Border color of the point (useless when stroke-width is not specified) | + +```note +Order of preference: +1. Direct styles +2. Class styles +3. Theme styles +``` + +## Example on styling + +```mermaid-example +quadrantChart + title Reach and engagement of campaigns + x-axis Low Reach --> High Reach + y-axis Low Engagement --> High Engagement + quadrant-1 We should expand + quadrant-2 Need to promote + quadrant-3 Re-evaluate + quadrant-4 May be improved + Campaign A: [0.9, 0.0] radius: 12 + Campaign B:::class1: [0.8, 0.1] color: #ff3300, radius: 10 + Campaign C: [0.7, 0.2] radius: 25, color: #00ff33, stroke-color: #10f0f0 + Campaign D: [0.6, 0.3] radius: 15, stroke-color: #00ff0f, stroke-width: 5px ,color: #ff33f0 + Campaign E:::class2: [0.5, 0.4] + Campaign F:::class3: [0.4, 0.5] color: #0000ff + classDef class1 color: #109060 + classDef class2 color: #908342, radius : 10, stroke-color: #310085, stroke-width: 10px + classDef class3 color: #f00fff, radius : 10 +```