Skip to content

Commit

Permalink
Merge pull request #22 from nao1215/piechart
Browse files Browse the repository at this point in the history
Introduce pie chart (mermaid)
  • Loading branch information
nao1215 authored May 5, 2024
2 parents 97b5eb5 + 9dd5318 commit 9405b5a
Show file tree
Hide file tree
Showing 11 changed files with 594 additions and 93 deletions.
75 changes: 69 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ Additionally, complex code that increases the complexity of the library, such as
- [x] Plain text
- [x] Details
- [x] Alerts; NOTE, TIP, IMPORTANT, CAUTION, WARNING
- [x] mermaid (only support sequence diagram)
- [x] mermaid sequence diagram
- [x] mermaid pie chart

### Features not in Markdown syntax
- Generate badges; RedBadge(), YellowBadge(), GreenBadge().
Expand Down Expand Up @@ -182,7 +183,7 @@ go generate ./...
This markdown is generated by `go generate`
````

### Generate alerts
### Alerts syntax
The markdown package can create alerts. Alerts are useful for displaying important information in Markdown. This syntax is supported by GitHub.
[Code example:](./doc/alert/main.go)
```go
Expand Down Expand Up @@ -231,7 +232,7 @@ Your alert will look like this;
> [!CAUTION]
> This is caution
### Generate status badge
### Status badge syntax
The markdown package can create red, yellow, and green status badges.
[Code example:](./doc/badge/main.go)
```go
Expand All @@ -256,8 +257,7 @@ Your badge will look like this;
![Badge](https://img.shields.io/badge/yellow_badge-yellow)
![Badge](https://img.shields.io/badge/green_badge-green)

### Generate mermaid sequence diagram
Generate mermaid in markdown. You can generate mermaid using go generate. Please define code to generate Mermaid first. Then, run "go generate ./..." to generate it.
### Mermaid sequence diagram syntax

```go
package main
Expand All @@ -272,7 +272,7 @@ import (
//go:generate go run main.go

func main() {
diagram := sequence.NewDiagram(os.Stdout).
diagram := sequence.NewDiagram(io.Discard).
Participant("Sophia").
Participant("David").
Participant("Subaru").
Expand Down Expand Up @@ -346,7 +346,70 @@ sequenceDiagram
David-->>Sophia: wake up, wake up
```

### Pie chart syntax

```go
package main

import (
"io"
"os"

"github.com/nao1215/markdown"
"github.com/nao1215/markdown/mermaid/piechart"
)

//go:generate go run main.go

func main() {
f, err := os.Create("generated.md")
if err != nil {
panic(err)
}

chart := piechart.NewPieChart(
io.Discard,
piechart.WithTitle("mermaid pie chart builder"),
piechart.WithShowData(true),
).
LabelAndIntValue("A", 10).
LabelAndFloatValue("B", 20.1).
LabelAndIntValue("C", 30).
String()

err = markdown.NewMarkdown(f).
H2("Pie Chart").
CodeBlocks(markdown.SyntaxHighlightMermaid, chart).
Build()

if err != nil {
panic(err)
}
}
```

Plain text output: [markdown is here](./doc/piechart/generated.md)
````
## Pie Chart
```mermaid
%%{init: {"pie": {"textPosition": 0.75}, "themeVariables": {"pieOuterStrokeWidth": "5px"}} }%%
pie showData
title mermaid pie chart builder
"A" : 10
"B" : 20.100000
"C" : 30
```
````

Mermaid output:
```mermaid
%%{init: {"pie": {"textPosition": 0.75}, "themeVariables": {"pieOuterStrokeWidth": "5px"}} }%%
pie showData
title mermaid pie chart builder
"A" : 10
"B" : 20.100000
"C" : 30
```

## Creating an index for a directory full of markdown files
The markdown package can create an index for Markdown files within the specified directory. This feature was added to generate indexes for Markdown documents produced by [nao1215/spectest](https://github.com/nao1215/spectest).
Expand Down
9 changes: 9 additions & 0 deletions doc/piechart/generated.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## Pie Chart
```mermaid
%%{init: {"pie": {"textPosition": 0.75}, "themeVariables": {"pieOuterStrokeWidth": "5px"}} }%%
pie showData
title mermaid pie chart builder
"A" : 10
"B" : 20.100000
"C" : 30
```
40 changes: 40 additions & 0 deletions doc/piechart/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//go:build linux || darwin

// Package main is generating mermaid sequence diagram.
package main

import (
"io"
"os"

"github.com/nao1215/markdown"
"github.com/nao1215/markdown/mermaid/piechart"
)

//go:generate go run main.go

func main() {
f, err := os.Create("generated.md")
if err != nil {
panic(err)
}

chart := piechart.NewPieChart(
io.Discard,
piechart.WithTitle("mermaid pie chart builder"),
piechart.WithShowData(true),
).
LabelAndIntValue("A", 10).
LabelAndFloatValue("B", 20.1).
LabelAndIntValue("C", 30).
String()

err = markdown.NewMarkdown(f).
H2("Pie Chart").
CodeBlocks(markdown.SyntaxHighlightMermaid, chart).
Build()

if err != nil {
panic(err)
}
}
3 changes: 2 additions & 1 deletion doc/sequence/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package main

import (
"io"
"os"

"github.com/nao1215/markdown"
Expand All @@ -18,7 +19,7 @@ func main() {
panic(err)
}

diagram := sequence.NewDiagram(os.Stdout).
diagram := sequence.NewDiagram(io.Discard).
Participant("Sophia").
Participant("David").
Participant("Subaru").
Expand Down
60 changes: 60 additions & 0 deletions mermaid/piechart/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package piechart

// config is a pie chart configuration.
type config struct {
// The axial position of the pie slice labels,
// from 0.0 at the center to 1.0 at the outside edge of the circle.
textPosition float64
// showData is a flag to show the data in the pie chart.
showData bool
// title is the title of the pie chart.
title string
}

// newConfig returns a new Config with default values.
func newConfig() *config {
return &config{
textPosition: defaultTextPosition,
}
}

const (
// defaultTextPosition is the default axial position of the pie slice labels.
defaultTextPosition float64 = 0.75
// minTextPosition is the minimum axial position of the pie slice labels.
minTextPosition float64 = 0.0
// maxTextPosition is the maximum axial position of the pie slice labels.
maxTextPosition float64 = 1.0
// noTitle is a constant for no title.
noTitle string = ""
)

// Option sets the options for the PieChart struct.
type Option func(*config)

// WithTextPosition sets the axial position of the pie slice labels.
// The axial position of the pie slice labels, from 0.0 at the center
// to 1.0 at the outside edge of the circle.
// If pos is less than 0.0 or greater than 1.0, it will be set to the default value (0.75)
func WithTextPosition(pos float64) Option {
return func(c *config) {
if pos < minTextPosition || pos > maxTextPosition {
pos = defaultTextPosition
}
c.textPosition = pos
}
}

// WithShowData sets the showData configuration.
func WithShowData(showData bool) Option {
return func(c *config) {
c.showData = showData
}
}

// WithTitle sets the title configuration.
func WithTitle(title string) Option {
return func(c *config) {
c.title = title
}
}
93 changes: 93 additions & 0 deletions mermaid/piechart/pie_chart.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Package piechart is mermaid pie chart builder.
package piechart

import (
"fmt"
"io"
"runtime"
"strings"
)

// PieChart is a pie chart builder.
type PieChart struct {
// body is pie chart body.
body []string
// dest is output destination for pie chart body.
dest io.Writer
// err manages errors that occur in all parts of the pie chart building.
err error
// config is the configuration for the pie chart.
config *config
}

// NewPieChart returns a new PieChart.
func NewPieChart(w io.Writer, opts ...Option) *PieChart {
c := newConfig()

for _, opt := range opts {
opt(c)
}

lines := []string{}
lines = append(
lines,
fmt.Sprintf(
"%%%%{init: {\"pie\": {\"textPosition\": %.2f}, \"themeVariables\": {\"pieOuterStrokeWidth\": \"5px\"}} }%%%%",
c.textPosition,
))

baseLine := "pie"
if c.showData {
baseLine += " showData"
}

if c.title == noTitle {
lines = append(lines, baseLine)
} else {
lines = append(lines, baseLine)
lines = append(lines, fmt.Sprintf(" title %s", c.title))
}

return &PieChart{
body: lines,
dest: w,
config: c,
}
}

// String returns the pie chart body.
func (p *PieChart) String() string {
return strings.Join(p.body, lineFeed())
}

// Build writes the pie chart body to the output destination.
func (p *PieChart) Build() error {
if _, err := fmt.Fprint(p.dest, p.String()); err != nil {
if p.err != nil {
return fmt.Errorf("failed to write: %w: %s", err, p.err.Error()) //nolint:wrapcheck
}
return fmt.Errorf("failed to write: %w", err)
}
return nil
}

// LabelAndIntValue adds a label and value to the pie chart.
func (p *PieChart) LabelAndIntValue(label string, value uint64) *PieChart {
p.body = append(p.body, fmt.Sprintf(" \"%s\" : %d", label, value))
return p
}

// LabelAndFloatValue adds a label and value to the pie chart.
// The value is formatted with a precision of 6 digits after the decimal point.
func (p *PieChart) LabelAndFloatValue(label string, value float64) *PieChart {
p.body = append(p.body, fmt.Sprintf(" \"%s\" : %f", label, value))
return p
}

// lineFeed return line feed for current OS.
func lineFeed() string {
if runtime.GOOS == "windows" {
return "\r\n"
}
return "\n"
}
Loading

0 comments on commit 9405b5a

Please sign in to comment.