Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jolewis-ddn committed Apr 20, 2021
1 parent 834a524 commit a15c385
Show file tree
Hide file tree
Showing 4 changed files with 318 additions and 0 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,18 @@
# singleBar
Simple single bar chart (uses p5.js)

# Parameters

* `values`: Array of numeric values (between 3 and 5 values in length) (no default)
* `hideValues`: Do not display the numeric values (default: false)
* `save`: Automatically download as PNG (the value of the `save` parameter is the filename) (no default)

# Use

* Copy the HTML and JS files to a local folder
* Note: you must change the path to the JS file in the HTML (line 8) if you don't store them in the same folder
* *optional* Start a web server (Note: the page works when opening the HTML file from your browser without going through a web server)
* Open the HTML file - the page will open with a default array & show you the corresponding URL with all the parameters

# Sample
![Sample Image](singleBar-sample.png)
Binary file added singleBar-sample.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
146 changes: 146 additions & 0 deletions singleBar.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<!-- @format -->

<!DOCTYPE html>
<html lang="en">
<head>
<title>P5.js Single Bar Chart</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
<script src="./singleBar.js"></script>
</head>
<body>
<!-- no body is needed. P5.js creates the canvas and draws to it directly -->
<script>
// Debugging method
let debug = true
function dbg(msg) {
if (debug) {
console.log(msg)
}
}

// Value boxes
let i1, i2, i3, i4, i5

let bullet // bullet chart object
let canvas // canvas

let a = 5 // Default value[0]
let b = 3 // Default value[1]
let c = 2 // Default value[2]
let d = 7 // Default value[3]
let e = 12 // Default value[4]

let cbHide, helpDiv // HTML elements for checkbox and link text

/*
* Create bar in a single run - no looping
*/
function setup() {
let params = getURLParams()

// Update or remove these settings based on your preference
// Only `values` is required
const values = params.values ? params.values.split(',') : [a, b, c, d]
const width = params.width || false
const height = params.height || false

const hideValues =
(params.hideValues &&
(params.hideValues == 'true' || params.hideValues == 'yes')) ||
false

const showValues = !hideValues

if (values) { // Values were supplied, so set them
a = values[0]
b = values[1]
c = values[2]
d = values[3]
e = values[4]
} else { // No values, so use the defaults
values = [a, b, c, d]
}
// If you remove variables above, remove them from this constructor call, too
sb = new SingleBar(values, showValues) //, width, height)

// The bullet object calculates the proper width and height of the canvas
canvas = createCanvas(sb.getWidth(), sb.getHeight())
sb.display()
noLoop() // Do not execute the draw() method

let inputSize = 30
i1 = createInput(a).size(inputSize).input(inputEvent)
i2 = createInput(b).size(inputSize).input(inputEvent)
i3 = createInput(c).size(inputSize).input(inputEvent)
i4 = createInput(d).size(inputSize).input(inputEvent)
i5 = createInput(e).size(inputSize).input(inputEvent)

cbHide = createCheckbox('hide values', hideValues).changed(checkEvent)

helpDiv = createDiv()
updateHelpDiv()

if (params.save) {
let filename = params.save || 'singleBar'
saveCanvas(canvas, filename, 'png')
}
}

/**
* When one of the value boxes changes,
* set the new values and trigger a display refresh
*
* @memberof SingleBar
*/
function inputEvent() {
if (i5.value()) {
sb.setValues([
i1.value(),
i2.value(),
i3.value(),
i4.value(),
i5.value(),
])
} else if (i4.value()) {
sb.setValues([i1.value(), i2.value(), i3.value(), i4.value()])
} else {
// min 3 values
sb.setValues([i1.value(), i2.value(), i3.value()])
}
updateHelpDiv()
sb.display()
}

/**
* Toggle the hideValues checkbox
* then refresh bar display
*
* @memberof SingleBar
*/
function checkEvent() {
sb.setShowValues(!this.checked())
updateHelpDiv()
sb.display()
}

/**
* Show the hyperlink for the currently displayed bar
*
* @memberof SingleBar
*/
function updateHelpDiv() {
helpDiv.html(
`<a href='singleBar.html?values=${sb.values.join(
','
)}&hideValues=${cbHide.checked()}'>singleBar.html?values=${sb.values.join(
','
)}&hideValues=${cbHide.checked()}</a>`
)
}

function draw() {
// no-op - the chart is drawn in the setup() and *Event() methods
}
</script>
</body>
</html>
156 changes: 156 additions & 0 deletions singleBar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/** @format */

const DEFAULT_MAX = 100 // Total of all values
const DEFAULT_WIDTH = 400 // Total width of the bar
const DEFAULT_HEIGHT = 20 // Height of the bar

// Default colors based on # of values supplied
const DEFAULT_COLORS_3 = ['#EF476F', '#FFD166', '#06D6A0']
const DEFAULT_COLORS_4 = ['#EF476F', '#FFD166', '#06D6A0', '#073B4C']
const DEFAULT_COLORS_5 = ['#EF476F', '#FFD166', '#06D6A0', '#118AB2', '#073B4C']

const DEFAULT_FONT_COLORS = ['white', 'black', 'black', 'white', 'white']

const DEFAULT_SHOW_VALUES = false

/**
* Class to create SingleBar object
* Requires: p5.js
*/
class SingleBar {
/**
* Constructor
* @param {number} values - Values (comma-separated)
* @param {number} width - Width of the canvas
* @param {number} height - Height of the canvas
* @param {number} barHeight - Height of the value bar
*
*/
constructor(
values,
showValues = DEFAULT_SHOW_VALUES,
width = DEFAULT_WIDTH,
height = DEFAULT_HEIGHT
) {
this.buffer = 0 // Horizontal buffer
this.vbuffer = 0 // Vertical buffer (above/below chart)

this.setValues(values.map((x) => +x))

this.canvasWidth = width
this.canvasHeight = height
this.showValues = showValues

// Calculate the bounding box of the chart
this.chartX = 0
this.chartY = 0

this.chartWidth = this.canvasWidth - this.chartX // No buffer
this.chartHeight = this.canvasHeight // No buffer

// points per pixel
this.ppp = this.chartWidth / this.max
noLoop()
}

/**
* Set the array of values
* Note: will be converted to numbers (or fail)
*
* @param {Array} v Array of numeric values
* @memberof SingleBar
*/
setValues(v) {
this.binCount = v.length
this.values = v.map((x) => +x)
console.log(`this.values = `, this.values)
this.max = this.values.reduce((p, c) => (p += c))
this.ppp = this.chartWidth / this.max

// Set up the bins and colors
switch (this.binCount) {
case 3:
this.colors = DEFAULT_COLORS_3
break
case 4:
this.colors = DEFAULT_COLORS_4
break
case 5:
this.colors = DEFAULT_COLORS_5
break
default:
this.colors = []
break
}
this.fontColors = DEFAULT_FONT_COLORS
}

/**
* Show the values?
*
* @param {boolean} s Display
* @memberof SingleBar
*/
setShowValues(s) {
this.showValues = s
}

/**
* Standard p5js display() function
* Note: noloop() is set to prevent refresh
*
* @memberof SingleBar
*/
display() {
// Quantitiatve Bins
noStroke()
let shade = 0
let prevW = 0

textAlign(CENTER, CENTER)

// Create the shaded backgrounds
for (let i = 0; i < this.binCount; i++) {
let thisW = this.ppp * this.values[i]

fill(this.colors[i])
rect(this.chartX + prevW, 0, thisW, this.chartHeight)

// Print the value
if (this.showValues) {
fill(this.fontColors[i])
if (this.values[i] > 0) {
text(this.values[i], prevW + thisW / 2, this.canvasHeight / 2)
}
}
// Catch the width for the next loop
prevW += thisW
}
}

/**
* Get the canvas width
* @returns {number} Canvas width
*/
getWidth() {
return this.canvasWidth
}

/**
* Get the canvas height
* @returns {number} Canvas height
*/
getHeight() {
return this.canvasHeight
}
}

/**
* Print debug message
* @param {string} msg Debug message
*/
function dbg(msg) {
if (debug) {
console.log(msg)
}
}

0 comments on commit a15c385

Please sign in to comment.