-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixed bug handling 1 and 0 #1
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,107 +1,168 @@ | ||
/** | ||
* Generate a donut chart. | ||
* | ||
* @param {object} parent The parent element to place the chart within. | ||
* @param {object} spec The chart details { radius, stroke, scale, items } (See README). | ||
*/ | ||
function DonutChart(parent, spec) { | ||
var __polar2xy = function(a, r) { | ||
return { | ||
x: Math.cos(a * 2 * Math.PI) * r, | ||
y: -Math.sin(a * 2 * Math.PI) * r, | ||
} | ||
} | ||
|
||
var __gen_arc_path = function(cx, cy, r, start, offset) { | ||
var end = __polar2xy(start + offset, r) | ||
start = __polar2xy(start, r) | ||
return [ | ||
"M", cx + start.x, cy + start.y, | ||
"A", r, r, 0, +(offset > .5), 0, cx + end.x, cy + end.y, | ||
].join(" ") | ||
} | ||
|
||
var __gen_chart_item = function(out, c, r, prev, cur, i, stroke) { | ||
out.push(["path", { | ||
d: __gen_arc_path(c, c, r, prev, cur), | ||
class: "chart-item-" + i, | ||
fill: "transparent", | ||
"stroke-width": stroke, | ||
}]) | ||
} | ||
|
||
var __gen_chart = function(chart) { | ||
var prev = 0, out = [] | ||
// FIXME get radius and stroke-width from CSS | ||
var c = chart.r, r = chart.r - chart.stroke / 2 | ||
for (var i in chart.items) { | ||
cur = chart.items[i] | ||
__gen_chart_item(out, c, r, prev, cur.value, i, chart.stroke) | ||
prev += cur.value | ||
} | ||
if (prev < 1) { | ||
__gen_chart_item(out, c, r, prev, 1 - prev, "bg", chart.stroke) | ||
} | ||
return out | ||
} | ||
|
||
var __create_tag_tree = function(elem) { | ||
var root = document.createElementNS("http://www.w3.org/2000/svg", elem[0]) | ||
var attr = elem[1] | ||
// Set attributes | ||
for (var i in attr) { | ||
var a = document.createAttribute(i) | ||
a.value = attr[i] | ||
root.setAttributeNode(a) | ||
} | ||
// Create children nodes | ||
if (elem.length > 2) { | ||
var children = elem[2] | ||
for (var i in children) { | ||
var c = __create_tag_tree(children[i]) | ||
root.appendChild(c) | ||
} | ||
} | ||
return root | ||
} | ||
|
||
|
||
/* Transformation matrix (rotate and mirror) to correct orientation: | ||
* \[ | ||
* \left[ | ||
* \begin{array}{ccc} | ||
* 0 & -1 & 0 \\ | ||
* -1 & 0 & 0 \\ | ||
* 0 & 0 & 1 | ||
* \end{array} | ||
* \right] | ||
* \] | ||
*/ | ||
var correct_orientation = "matrix(0 -1 -1 0 0 0)" | ||
|
||
var __gen_code = function(spec) { | ||
return __create_tag_tree( | ||
["svg", { | ||
transform: correct_orientation, | ||
class: "chart-donut", | ||
width: spec.r * 2, | ||
height: spec.r * 2, | ||
}, __gen_chart(spec)]) | ||
} | ||
|
||
var __is_dict = function(v) { | ||
return v && typeof v === "object" && !(v instanceof Array) | ||
} | ||
|
||
DonutChart.prototype.update = function(spec) { | ||
// Merge the new spec | ||
for (var i in spec) { | ||
this.spec[i] = spec[i] | ||
|
||
/* Transformation matrix (rotate and mirror) to correct orientation: | ||
* \[ | ||
* \left[ | ||
* \begin{array}{ccc} | ||
* 0 & -1 & 0 \\ | ||
* -1 & 0 & 0 \\ | ||
* 0 & 0 & 1 | ||
* \end{array} | ||
* \right] | ||
* \] | ||
*/ | ||
var correct_orientation = "matrix(0 -1 -1 0 0 0)"; | ||
|
||
var __get_def_radius_from_parent = function (parent) { | ||
if (parent.clientWidth < parent.clientHeight) | ||
return parent.clientWidth /2 | ||
else | ||
return parent.clientHeight /2 | ||
} | ||
|
||
var code = __gen_code(this.spec) | ||
// TODO can we switch the elements in place? | ||
if (this.element != undefined) { | ||
this.element.remove() | ||
var __polar2xy = function (a, radius) { | ||
return { | ||
x: Math.cos(a * 2 * Math.PI) * radius, | ||
y: -Math.sin(a * 2 * Math.PI) * radius | ||
}; | ||
}; | ||
|
||
var __gen_arc_path = function (cx, cy, radius, start, offset) { | ||
var end = __polar2xy(start + offset, radius); | ||
start = __polar2xy(start, radius); | ||
return [ | ||
"M", | ||
cx + start.x, | ||
cy + start.y, | ||
"A", | ||
radius, | ||
radius, | ||
0, | ||
+(offset > 0.5), | ||
0, | ||
cx + end.x, | ||
cy + end.y | ||
].join(" "); | ||
}; | ||
|
||
var __gen_chart_item = function (out, c, radius, prev, cur, i, stroke) { | ||
out.push([ | ||
"path", | ||
{ | ||
d: __gen_arc_path(c, c, radius, prev, cur), | ||
class: "chart-item-" + i, | ||
fill: "transparent", | ||
"stroke-width": stroke | ||
} | ||
]); | ||
}; | ||
|
||
var __gen_chart = function (chart) { | ||
var prev = 0, | ||
out = []; | ||
// FIXME get radius and stroke-width from CSS | ||
var c = chart.radius, | ||
radius = chart.radius - chart.stroke / 2; | ||
for (var i in chart.items) { | ||
cur = chart.items[i]; | ||
__gen_chart_item(out, c, radius, prev, cur.value, i, chart.stroke); | ||
prev += cur.value; | ||
} | ||
if (prev < 1) { | ||
__gen_chart_item(out, c, radius, prev, 1 - prev, "bg", chart.stroke); | ||
} | ||
return out; | ||
}; | ||
|
||
var __create_tag_tree = function (elem) { | ||
var root = document.createElementNS("http://www.w3.org/2000/svg", elem[0]); | ||
var attr = elem[1]; | ||
// Set attributes | ||
for (var i in attr) { | ||
var a = document.createAttribute(i); | ||
a.value = attr[i]; | ||
root.setAttributeNode(a); | ||
} | ||
// Create children nodes | ||
if (elem.length > 2) { | ||
var children = elem[2]; | ||
for (var i in children) { | ||
var c = __create_tag_tree(children[i]); | ||
root.appendChild(c); | ||
} | ||
} | ||
return root; | ||
}; | ||
|
||
// Need to fix spec values that will cause a broken SVG | ||
var __fix_spec_items = function (spec) { | ||
if (spec.items) { | ||
for (var i in spec.items) { | ||
if (spec.items[i].value == 1) spec.items[i].value = 0.9999999 | ||
if (spec.items[i].value == 0) spec.items[i].value = 0.0000001 | ||
} | ||
} | ||
return spec | ||
} | ||
this.element = this.parent.appendChild(code) | ||
} | ||
|
||
this.parent = parent | ||
this.spec = spec | ||
this.update({}) | ||
} | ||
var __gen_code = function (spec) { | ||
return __create_tag_tree([ | ||
"svg", | ||
{ | ||
transform: correct_orientation, | ||
class: "chart-donut", | ||
width: spec.radius * 2, | ||
height: spec.radius * 2 | ||
}, | ||
__gen_chart(spec) | ||
]); | ||
}; | ||
|
||
var __is_dict = function (v) { | ||
return v && typeof v === "object" && !(v instanceof Array); | ||
}; | ||
|
||
/** | ||
* Updates the state of the chart. | ||
* | ||
* @param {object} spec The chart items to update { items } (See README). | ||
*/ | ||
DonutChart.prototype.update = function (spec) { | ||
// Merge the new spec - A value of 1 will fail so need to make it as big as possible | ||
__fix_spec_items(spec) | ||
for (var i in spec) { | ||
this.spec[i] = spec[i]; | ||
} | ||
|
||
if (!this.parent) { | ||
throw new Error("No parent defined for the chart.") | ||
} else { | ||
var code = __gen_code(this.spec); | ||
// TODO can we switch the elements in place? | ||
if (this.element) this.element.remove(); | ||
this.element = this.parent.appendChild(code); | ||
} | ||
}; | ||
|
||
if (!parent) throw new TypeError("The parent is required.") | ||
if (!spec) throw new TypeError("The chart spec is required.") | ||
if (!spec.items) throw new Error("The spec must have items provided.") | ||
__fix_spec_items(spec) | ||
|
||
// Set defaults if spec elements not provided. | ||
if (!spec.radius) spec.radius = __get_def_radius_from_parent(parent) | ||
if (!spec.stroke) spec.stroke = 25 | ||
if (!spec.scale) spec.scale = 100 | ||
|
||
this.parent = parent; | ||
this.spec = spec; | ||
this.element = null; | ||
|
||
this.update({}); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
<html> | ||
<head> | ||
<style> | ||
.chart-item-bg {stroke: #ddd} | ||
.chart-item-bg {stroke: #000000} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am guessing this change slipped thru. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was intentional. Switching the stroke to black made it much clearer to debug at the very very small levels that I was dealing with where it would break trying to cover off the closest acceptable fraction close to 1 / 0. I wanted the highest possible contrast. |
||
.chart-item-0 {stroke: #dd0000} | ||
.chart-item-1 {stroke: #00cc00} | ||
.chart-item-2 {stroke: #0000ff} | ||
|
@@ -14,17 +14,19 @@ | |
<script type="text/javascript"> | ||
var chart_div = document.getElementById("mychart") | ||
var mychart = new DonutChart(chart_div, { | ||
r: 60, | ||
radius: 60, | ||
stroke: 16, | ||
scale: 100, | ||
items: [ | ||
//{ label: "ALL", value: 1 }, | ||
{ label: "A", value: .2 }, | ||
{ label: "B", value: .1 }, | ||
{ label: "C", value: .5 }, | ||
] | ||
}) | ||
mychart.update({ | ||
items: [ | ||
//{ label: "ALL", value: 1 } | ||
{ label: "J", value: .4 }, | ||
{ label: "Q", value: .3 }, | ||
] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't change the indentation in the same commit. Also, what's the rationale for changing it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not aware that I changed the indentation at all. I did move some methods around in the page order but I don't think I changed the indentation at all....