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
}