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
ref(ui): svg-based bar charts #8802
Conversation
|
50156de
to
90ec931
Compare
}); | ||
} | ||
}, | ||
} | ||
|
||
shouldComponentUpdate(nextProps, nextState) { | ||
return !_.isEqual(this.props, nextProps); |
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.
is this really necessary? seems like a) this would be close to the default behavior and b) it would be a confusing surprise to not re-render on state change.
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 genuinely asking tho (hence why I left it in)
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.
Difference is shallow vs deep compare, agreed with (b).
Since we're not updating on state changes... the values that are currently in state, should not be in state. I would leave this in here though and open a followup for cleanups.
…ose things can't be controlled with css in svg
…ontent from dissapearing
<rect | ||
x={index * pointWidth + '%'} | ||
width={pointWidth + '%'} | ||
height="105%" |
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 way we do stacked charts with min-height
s right now is similar to this. we set a min-height
in css and then it just stacks up and overflows the container.
A fancier and better version of this could apply the min-height
s to a base set and then calculate everything based on that, but that seemed out of scope since I was really just trying to replicate the old chart behavior in svg.
const StyledSvg = styled('svg')` | ||
width: calc(100% + ${p => p.gap}px); | ||
height: 100%; | ||
overflow: visible !important; /* overrides global declaration */ |
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.
we set overflow: hidden
globally on all svgs
@@ -345,36 +345,39 @@ | |||
border-bottom: 1px dotted @trim; | |||
} | |||
|
|||
.bar-chart figure a { | |||
.bar-chart figure a, | |||
.bar-chart figure g { |
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 css will all go away, but I want to do it in a follow up.
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.
Visually everything looks great, save for a handful of diffs... Any idea what's going on to cause the markers in the sidebar to be on the first bar instead of the last?
https://percy.io/getsentry/sentry/builds/1035439/view/63270274/1280?browser=firefox&mode=diff
https://percy.io/getsentry/sentry/builds/1035439/view/63270225/1280?browser=firefox&mode=diff
@ckj yeah I've been looking at that too. When I compare my branch directly to master it is almost identical...so I'm hoping this is a percy thing. I will probably dig around a bit more before I mash merge just to make sure it's production safe. |
@Chrissy tooltips are a bit off on the smaller charts |
@ckj good catch! that was added recently and should be an easy fix. |
…a bit of customization looks really similar
alrighty @ckj I addressed both of the bugs you found. I moved the circles into independent svgs that are moved using css, and then changed the bar graphs to stretch, so everything scales fluidly now both vertically and horizontally (but...you know...without the weird bugs). Everything looks good in comparison to master, so once I get a js review, this should be ready to go. |
}, | ||
} | ||
|
||
getInterval = series => { |
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.
none of these changed, i just moved them when I removed createClass
.
import PropTypes from 'prop-types'; | ||
import moment from 'moment-timezone'; | ||
import _ from 'lodash'; | ||
import styled from 'react-emotion'; | ||
import cx from 'classnames'; |
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.
fyi react-emotion
has a cx
as well (and would prefer that moving forward)
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.
was just reading about this. good call.
} | ||
|
||
getInterval = series => { | ||
// TODO(dcramer): not guaranteed correct |
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.
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.
RIGHT?!
let totalY = point.y.reduce((a, b) => a + b); | ||
let totalPct = totalY / maxval; | ||
let prevPct = 0; | ||
let pts = point.y.map((y, i) => { | ||
let pct = totalY && this.floatFormat(y / totalY * totalPct * 99, 2); | ||
let pct = Math.max( | ||
totalY && this.floatFormat(y / totalY * totalPct * 99, 2), |
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.
what does 99
mean here?
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.
(takes a long, deep breath...)
As best I can tell the "99" is used to reserve a little extra space for the min-heights
that were previously applied to bars with css (now applied with the prop). this didn't really work because 1% isn't always 1px and sometimes (like with issue release charts) the min-height is 4+ pixels.
However none of the charts have overflow: hidden so if the bars exceed 100% height it doesn't matter (so long as visually it doesn't look weird)
I kept the 99 in there to keep things similar to what they were before. Truthfully, the charts have never been that accurate lol. We could do 100 and nobody would notice.
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.
Also good for this to be in commentz
|
||
renderChart() { | ||
let {pointIndex, series} = this.state; | ||
let totalPoints = Math.max(...series.map(s => s.data.length)); | ||
let pointWidth = this.floatFormat(100.0 / totalPoints, 2) + '%'; | ||
let pointWidth = this.floatFormat((100.0 + this.props.gap + 0.1) / totalPoints, 2); |
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.
What does 0.1
mean here?
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.
it keeps a very subtle white line from appearing on the right edge of the svg at certain sizes. I could remove it and nobody would notice. it happens with regularity in production and nobody seems to care.
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 would explain this in some code commentz
barClasses: ['chart-bar'], | ||
}; | ||
}, | ||
minHeights: PropTypes.arrayOf(PropTypes.number), |
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.
Can we document what minHeights
does? It's not clear why it's an array of min heights.
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.
absolutely
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 also considered renaming it to minBarHeights
which might help
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.
lgtm, I would add some inline comments for places where magic numbers are involved.
|
|
Updates:
Changes:
Our current bar charts do all sorts of crazy things if odd numbers are involved. This is because divs aren't subject to sub-pixel aliasing (or rather, they are but the browser doesn't seem to couple the antialiasing process with the precise layout):
SVGs are capable of sub-pixel aliasing and even have several different options to fit different goals. Best of all, they take layout precision into account much better during the aliasing process
Here is what a complex example looks like before and after:
Circles also don't scale very well in the current charts:
This converts our circles to svg so it scales correctly:
Performance is equal at worst, and might be a little better based on a quick look at the performance tab. There is the opportunity to emphatically improve performance in tabular list views by converting bars to a sprite with
<use />
.As the charts get smaller and we move into sub-pixel layouts the improvements become more obvious:
todo:
other (existing) chart bugs for follow ups: