-
Notifications
You must be signed in to change notification settings - Fork 74
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
Color legend widget #731
Color legend widget #731
Conversation
… Adds container style;
…nt, don't add unnecessary precision;
this is looking awesome @MatthewMa |
…ng and removing categories; other improvements;
This is ready for review |
src/ui/colorLegendWidget.js
Outdated
var registerWidget = require('../registry').registerWidget; | ||
|
||
/** | ||
* @typedef {object} [geo.gui.colorLegendWidget.category] |
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.
You don't want the []
around the typedef.
src/ui/colorLegendWidget.js
Outdated
* @alias geo.gui.colorLegendWidget | ||
* @extends geo.gui.domWidget | ||
* @param {object} [arg] Widget options. | ||
* @param {object} [args.position] Position setting relatively to the map container. |
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.
This should be arg.position
not args.position
(and similar on lines below).
src/ui/colorLegendWidget.js
Outdated
/** | ||
* @typedef {object} [geo.gui.colorLegendWidget.category] | ||
* @property {string} name The text label of the legend. | ||
* @property {string} type The type of the legend, either discrete or continuous. |
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.
Should there be a default value? Perhaps default this to continuous
and and the scale
to linear
.
src/ui/colorLegendWidget.js
Outdated
* @property {string} scale The scale of the legend. For discrete type, | ||
* linear, log, sqrt, pow, ordinal, and quantile is supported. | ||
* For continuous type, linear, log, sqrt, and pow is supported. | ||
* @property {number[]|string[]} domain Only for ordinal scale legend, string values are acceptable. For ordinal legend, the number in the domain array should be the same number of colors. For quantile scale legend, the domain should be an array of all values. For other scales, the domain needs to be an array of two number for marking the upper bound and lower bound. |
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.
Elsewhere we've wrapped comments at 80 columns (and in general, @aashish24 at least has preferred wrapped lines).
src/ui/colorLegendWidget.js
Outdated
* linear, log, sqrt, pow, ordinal, and quantile is supported. | ||
* For continuous type, linear, log, sqrt, and pow is supported. | ||
* @property {number[]|string[]} domain Only for ordinal scale legend, string values are acceptable. For ordinal legend, the number in the domain array should be the same number of colors. For quantile scale legend, the domain should be an array of all values. For other scales, the domain needs to be an array of two number for marking the upper bound and lower bound. | ||
* @property {string[]} colors The colors of the legend. All valid svg color can be used. For discrete type, multiple values are accepted. For continuous type, an array of two values is supported. |
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.
Perhaps add a note that this corresponds to the d3.scale.range
parameter. Also, allowing only svg colors is more restrictive then how colors are supported elsewhere. We should pass the colors through geo.util.convertColorToHex
with allowAlpha
set to true
. This would ensure a consistent color definition in geojs. In which, the parameter type can be changed to geo.geoColor
.
src/ui/colorLegendWidget.js
Outdated
m_this._renderAxis(svg, axis); | ||
} | ||
|
||
function createAxis(axisScale) { |
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 document.
src/ui/colorLegendWidget.js
Outdated
* For continuous type, linear, log, sqrt, and pow is supported. | ||
* @property {number[]|string[]} domain Only for ordinal scale legend, string values are acceptable. For ordinal legend, the number in the domain array should be the same number of colors. For quantile scale legend, the domain should be an array of all values. For other scales, the domain needs to be an array of two number for marking the upper bound and lower bound. | ||
* @property {string[]} colors The colors of the legend. All valid svg color can be used. For discrete type, multiple values are accepted. For continuous type, an array of two values is supported. | ||
*/ |
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 see some other properties that are optional on categories (base
and exponent
, I think). They should be added to the typedef as well.
tests/cases/colorLegend.js
Outdated
it('Create basic color legend widget', function (done) { | ||
expect($(container).find('.legend').length).toBe(1); | ||
done(); | ||
}); |
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.
For synchronous tests, you don't need to use the done
parameter -- just use function ()
and don't call done()
.
tests/cases/colorLegend.js
Outdated
$(legends[1]).find('svg>rect')[0].dispatchEvent(mouseout); | ||
done(); | ||
}); | ||
}); |
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.
The code coverage misses a few things: calling categories()
without a parameter and testing that you get the values you set; quantile
rendering discrete colors; testing against an unsupported scale; hiding the popup (should that have been triggered by a mouse movement?); mouseenter
and mouseleave
; a scale with zero categories.
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.
Wow, how do you notice such small misses, thank you for such careful review.
I think I tested popup mouseout event, did the coverage says otherwise? Do you know how to see the line by line code coverage for the colorLegend file?
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.
https://codecov.io/gh/OpenGeoscience/geojs/src/2d_legend/src/ui/colorLegendWidget.js
Also, if you run the tests with coverage on locally, it will dump an html coverage report that you can browse.
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.
@jbeezley, Thank you! That's really helpful.
examples/color-legend/example.json
Outdated
{ | ||
"path": "color-legend", | ||
"title": "Color legends", | ||
"exampleCss": ["main.css"], |
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.
For examples with empty css files, we really should set exampleCss: []
and shouldn't include a blank css file.
bb2c552
to
9f0e27f
Compare
9f0e27f
to
8e9e5b8
Compare
@manthey, Thank you very much for your detailed previous reviews. They totally make sense. (I don't know why codecov indicates two line is not covered, I have a expect() that tests the results from that two lines) |
src/ui/colorLegendWidget.js
Outdated
* container. | ||
* @param {geo.gui.colorLegendWidget.category[]} [arg.categories] An array | ||
* of category definitions for the initial color legends | ||
* @param {number} [arg.width] The pixel width of the wiget in number. Default is 300px. |
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.
jsdoc lets you specify defaults as part of an optional parameter:
@param {number} [arg.width=300] The width of the widget in pixels.
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.
Currently height
and margins are hard-coded too. I think that rather than just specifying width
and ticks
, we should allow width
, height
, horizontal_margin
(or perhaps hmargin
), vertical_margin
, and ticks
. I think that it would be more intuitive if width
and height
were the size of the color scale, and the horizontal_margin
(or whatever we call it) would be the spacing at either end and the vertical_margin
would be the spacing at the bottom for the ticks and labels.
src/ui/colorLegendWidget.js
Outdated
|
||
if (arg.categories) { | ||
this.categories(arg.categories); | ||
} | ||
}; | ||
|
||
// clear the DOM container and create legends | ||
/** | ||
* clear the DOM container and create legends |
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.
This should fail the jsdoc function description template rules, which require a capital letter and terminal punctuation. Please check for other jsdoc errors on this file (they are reported as warnings).
src/ui/colorLegendWidget.js
Outdated
}; | ||
|
||
// Draw an individual discrete type legend | ||
this._prepareCategories = function (categories) { |
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 comment the function.
src/ui/colorLegendWidget.js
Outdated
@@ -270,8 +297,9 @@ var colorLegendWidget = function (arg) { | |||
if (category.scale === 'pow' && category.exponent) { | |||
axisScale.exponent(category.exponent); | |||
} | |||
var randomString = Math.random().toString(36).substring(5); | |||
var precision = Math.max.apply(null, category.domain.map(function (number) { return getPrecision(number); })); | |||
var randomString = util.randomString(5); |
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 should have noticed before. We already have a function in d3/uniqueID
for this purpose, so we should use that.
src/ui/widget.js
Outdated
* @property {string|number} bottom The position to the bottom of the container. | ||
* Value is used similarly to the top property. | ||
* @property {string|number} left The position to the left of the container. | ||
* Value is used similarly to the top property. |
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.
All of these properties are optional. Further, we should add:
@property {*} [...] Additional css properties that affect position are
allowed. See the css specification for details.
With PR #733, you can remove |
bed3844
to
63bee9a
Compare
63bee9a
to
b8f5c71
Compare
OMG, I finally fixed the build. @manthey, could you take a quick look? |
src/ui/colorLegendWidget.js
Outdated
* Formatter of number that tries to maximize the precision | ||
* while making the output shorter. | ||
* @param {number} number to be formatted | ||
* @param {precision} precision number of decimal precision will be tried to be kept |
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 think the data type should just be number
. I'd recommend changing this to @param {number} precision Maximum number of decimal places that are kept.
.
src/ui/colorLegendWidget.js
Outdated
return this; | ||
}; | ||
|
||
function getPrecision(a) { |
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.
This function needs to be commented (while you at it, _hidePopup, above, needs it too).
src/ui/colorLegendWidget.js
Outdated
function getPrecision(a) { | ||
if (!isFinite(a)) return 0; | ||
var e = 1, p = 0; | ||
while (Math.round(a * e) / e !== a) { e *= 10; p++; } |
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.
If you pass a value with a magnitude less than 1 / Number.MAX_VALUE
, the process can get stuck in an infinite loop (if Number.MIN_VALUE
is less than 1 / Number.MAX_VALUE
, which is true in my version of Chrome). Perhaps we should return if isFinite(a * e)
is false.
I realize this is closed, however I have a question regarding how to use this. When I add a contour plot as well as one of these legends, the colouring of the contour plot doesn't match the legend's colour. Is this to be expected? |
Are you using the same colors for the contour plot and the legend? They can be specified independently; there is nothing that forces them to be the same, though you should be able to use the same colors for both. If you have a code snippet, we can advise further. |
Implementation of color legend widget.
Support both discrete and continuous scale.
Scale calculation is based on d3 scale.
Discrete color scale supports linear log, sqrt, pow, quantile, ordinal.
Continuous color supports linear log, sqrt, pow. Continuous color supports two color transition.
This is is WIP PR, will test use this widget in a project first.