Last active
August 29, 2015 14:01
-
-
Save janpaul123/b2e6e0d2faef0bf99a22 to your computer and use it in GitHub Desktop.
Mini Factwheels
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Made by @markijbema, based on @joelkuiper's SVG Factwheel | |
require 'rvg/rvg' | |
include Magick | |
include Math | |
class SvgWheelBuilder | |
def initialize( | |
percentages_max_colors=['#98d100', '#36A9E1', '#E94E1B'], | |
percentages_colors=['#dbeab3','#c5eaf8','#f8caba'], # green blue red | |
disabled_color = '#dadada' | |
) | |
#sanity check, if the color is in the wrong format imagemagick crashes in mysterious ways | |
[percentages_max_colors, percentages_colors, [disabled_color]].each do |colors| | |
colors.each do |color| | |
unless color =~ /^#[a-fA-F0-9]{6}$/ | |
raise "Color should be in #xxxxxx format" | |
end | |
end | |
end | |
@disabled_color = disabled_color | |
@percentages_colors = percentages_colors | |
@percentages_max_colors = percentages_max_colors | |
end | |
def wheel(percentages) | |
RVG::Group.new do |canvas| | |
had = 0; | |
percentages.each_with_index do |percentage, index| | |
if percentage == percentages.max | |
stroke = @percentages_max_colors[index] | |
else | |
# stroke = @percentages_colors[index] | |
stroke = @disabled_color | |
end | |
canvas.path(arc_path(percentage,had,6)).styles(:fill => 'none', :stroke => stroke, :stroke_width => 4) | |
had += percentage | |
end | |
end | |
end | |
def string_for_float(f) | |
("%0.5f"%f).sub(/^-(0.0+)$/, '\1') | |
end | |
def arc_path(percentage, percentage_offset, radius) | |
large_angle = percentage > 50 | |
start_angle = percentage_offset * 2*Math::PI / 100 | |
end_angle = (percentage_offset + percentage) * 2*Math::PI / 100 | |
start_x = radius * Math.cos(start_angle) | |
start_y = - radius * Math.sin(start_angle) | |
end_x = radius * Math.cos(end_angle) | |
end_y = - radius * Math.sin(end_angle) | |
path_string(start_x,start_y, end_x, end_y, large_angle, radius) | |
end | |
def path_string(start_x, start_y, end_x, end_y, large_angle, radius) | |
start_x = string_for_float(start_x) | |
start_y = string_for_float(start_y) | |
end_x = string_for_float(end_x) | |
end_y = string_for_float(end_y) | |
return [['M',start_x,start_y], | |
["A", radius, radius, 0, large_angle ? 1 : 0, 0, end_x, end_y]].flatten.join(' ') | |
end | |
end | |
class PercentageFormatter | |
def initialize(round_to, minimum) | |
@round_to = round_to | |
@minimum = minimum | |
end | |
DOUBT_INDEX = 1 | |
def floor_percentages(percentages) | |
percentages.map {|x| ((x.to_f / @round_to )).floor.to_i * @round_to } | |
end | |
def cap_percentages(percentages) | |
round_to = @round_to | |
minimum = @minimum | |
after_total, large_ones = 0.0, 0.0 | |
percentages.each do |percentage| | |
after_total += [percentage, minimum].max | |
if percentage > (100 - minimum)/2 | |
large_ones += percentage | |
end | |
end | |
too_much = after_total - 100 | |
percentages = percentages.map do |percentage| | |
if percentage < minimum | |
percentage = minimum | |
elsif percentage > (100-minimum)/2 | |
percentage = percentage - percentage/large_ones*too_much | |
end | |
percentage.round | |
end | |
end | |
def process_percentages(percentages) | |
percentages = cap_percentages(percentages) | |
percentages = floor_percentages(percentages) | |
percentages[DOUBT_INDEX] += 100 - percentages.reduce(0,:+) | |
percentages | |
end | |
end | |
[ | |
[100, 0, 0], | |
[0, 100, 0], | |
[0, 0, 100], | |
[10000, 8, 13], | |
[2, 1, 0], | |
[7839, 8009, 3041], | |
[182, 119, 1205], | |
[4, 2, 8], | |
[10, 3, 0], | |
[6, 4, 2], | |
[11, 2, 0], | |
[9, 3, 0], | |
[7, 0, 0], | |
[0, 2, 0], | |
[7, 2, 0], | |
[11, 4, 8], | |
].each do |values| | |
total = values.inject{|sum,x| sum + x } | |
percentages_wrong_order = values.map{|i| 100*i/total} | |
# we denote them in above in green,red,blue format, but the SvgWheelBuilder expects green,blue,red | |
percentages = [percentages_wrong_order[0], percentages_wrong_order[2], percentages_wrong_order[1]] | |
after_percentages = PercentageFormatter.new(5,15).process_percentages(percentages) | |
rvg = RVG.new(20,20).viewbox(0,0,20,20) do |canvas| | |
canvas.use(SvgWheelBuilder.new().wheel(after_percentages)).translate(10,10) | |
end | |
local_path = "#{values.join('-')}.png" | |
rvg.draw.write(local_path) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment