MediaWiki:Gadget-make-pie.js
From WikiMSK
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (โ-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (โ-Shift-R on a Mac)
- Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Press Ctrl-F5.
/// a 2D (x,y) pair
function Point() { this.x = 0; this.y = 0; }
/// scale the point by @factor
Point.prototype.scale = function(factor) {
const next = new Point()
next.x = this.x * factor
next.y = this.y * factor
return next
}
/// determine the point on a unit circle from the passed @turns
Point.from_turns = function(turns) {
const self = new Point
self.x = Math.cos(2 * Math.PI * turns)
self.y = Math.sin(2 * Math.PI * turns)
return self
}
const Wedge = {
start: 0,
turns: 1,
/// the point @ start
get front() { return Point.from_turns(this.start) },
/// the point @ (start + turns)
get after() { return Point.from_turns(this.start + this.turns) },
/// the center of the wedge
get middle() { return Point.from_turns(this.start + this.turns / 2) },
/// create a wedge element for a pie chart
make: function make_wedge(svg, radius) {
// edges of the wedge... wEdges, if you will
const p1 = this.front.scale(radius)
const p2 = this.after.scale(radius)
// parts of the pat
const ds = []
// move to origin
ds.push(['M', 0, 0])
// draw line to first point
ds.push(['L', p1.x, p1.y])
// draw arc to correct point
const arc = ['A', radius, radius, 0, ((this.turns) > .5)*1, 1, p2.x, p2.y]
ds.push(arc)
// draw line to origin
ds.push(['L', 0, 0])
console.debug('make-wedge:', 'self:', this, 'points:', [p1, p2], '\tpath:', ds)
const self = svg.createElement('path')
self.classList.add('wedge')
// attach path to element
self.setAttribute('d', ds.flat().join(' '))
return self
},
}
module.exports = function make_pie(name, radius) {
// setup element
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
svg.classList.add('pie-chart')
svg.setAttribute('style', 'width: 100%; height: 100%;')
// setup svg itself
svg.setAttribute('viewBox', [-radius, -radius, 2*radius, 2*radius].join(' '))
svg.setAttribute('name', name)
/// help make svg elements
svg.createElement = function make_svg_el(tag) { return document.createElementNS(this.namespaceURI, tag) }
// setup data addition
const data = []
/// add a slice to the pie
svg.add_data_entry = function(count, name, label, fill) { data.push({ count: count, name: name, label: label || name, color: fill, }) }
/// wedge all the slices into the pie
svg.render = function() { console.debug('make-pie:', 'rendering', svg, data)
const total = data.map(function (v) { return v.count }).reduce(function (prev, self) { return prev + self })
Wedge.start = -1/4 // TODO: change this
data.forEach(function each_wedge(slice) {
// setup this wedge
Wedge.turns = slice.count / total
// create wedge
const el = Wedge.make(svg, radius)
el.setAttribute('name', slice.name)
el.setAttribute('fill', slice.color)
// create label
const text = svg.createElement('text')
text.classList.add('wedge')
text.innerHTML = slice.label
const text_pos = Wedge.middle.scale(radius * 2 / 3)
text.setAttribute('x', text_pos.x)
text.setAttribute('y', text_pos.y)
// show on pie
svg.appendChild(el)
svg.appendChild(text)
// setup next Wedge
Wedge.start += Wedge.turns
})
}
return svg
}