Skip to content
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

Jamie/19 new line graph #3598

Merged
merged 71 commits into from
May 19, 2020
Merged

Jamie/19 new line graph #3598

merged 71 commits into from
May 19, 2020

Conversation

SEAjamieD
Copy link
Contributor

@SEAjamieD SEAjamieD commented May 5, 2020

🔩 Description: What code changed, and why?

This is a new line graph being built for desktop. In its current state it is not reusable, but can be converted to usable in a swift manner when we are ready.

⛓️ Related Resources

fixes: https://github.com/chef/chef-design-system/issues/19
fixes #3723

👍 Definition of Done

Line graph is ready to be used in desktop and matches UX mock ups

👟 How to Build and Test the Change

build component/automate-ui-devproxy && start_all_services
run load_compliance_reports in hab studio
(unfortunately, I do not know how to provide varied data at this time)

navigate to https://a2-dev.test/desktop
Scroll down to "Last Check in By day"
See a chart with a few data points, change from 3 to 7 to 14 and all around using the dropdown within the component.
At 14, the labels will turn to allow for space.

Please note - the styles we are concerned about right now are only those of the graph, not its larger container.
Another important note - in its current container, 7 days worth of labels will overlap. In its planned implementation, the container will be around 600px, and the labels fit fine. Will work with UX to adjust as requested.

✅ Checklist

📷 Screenshots, if applicable

it doesn't appear the GIF is running at full speed - so take with a grain of salt
Chef Automate (4)

@SEAjamieD SEAjamieD self-assigned this May 5, 2020
@SEAjamieD SEAjamieD marked this pull request as ready for review May 5, 2020 21:02
@SEAjamieD SEAjamieD requested review from apriofrost and a team May 5, 2020 21:02
@@ -25,20 +27,22 @@ import { DesktopRoutingModule } from './desktop-routing.module';
ChefPipesModule
],
exports: [
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no major changes - just alphabetized them while I was here

Comment on lines +6 to +7
<defs>
<linearGradient id="chef-gradient-purple" x1="0%" y1="0%" x2="100%" y2="0%" gradientTransform="rotate(315)">
<stop id="stop1" offset="0%" />
<stop id="stop2" offset="100%" />
</linearGradient>
</defs>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is placed within the SVG so that we can reuse it as a gradient across any items needing to have our gradient

background: linear-gradient(315deg, #3023AE, #C86DD7);

.inner {
color: white;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noticing a few of these and other colors that need variable treatment... will fix up


it('contains an svg area for the chart', () => {
expect(d3.select(component.svg)).not.toBeNull();
});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really wanted to test the items getting appended to the graph, but I was having a difficult time selecting anything within the svg or outside of it that was being appended via d3. Any thoughts might be helpful. I was attempting to queryAll using By.css

@Input() data: DayPercentage[] = [];
@Input() width = 900;
@Input() height = 156; // we want a 116px height on the ticks, this minus margins
private locked: number = null;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

locked stores a number to reference when the graph is being redrawn or resized, so that it can re-attach to whatever the selected number was.

Comment on lines 28 to 36
get margin() {
return { right: 20, left: 20, top: 20, bottom: 20 };
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While it seems like you would just want to say return 20, its important to store each of these individually, so that if you change just one number - like the right margin, the math is correct across the rest of the file.

Comment on lines +64 to +73
get domainY(): [number, number] {
const min = 0;
const max = 100; // since this based on a percentage we are doing 0 to 100;
return [min, max];
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leaving these values as variables to make flexible in the future if we desire.

Comment on lines 117 to 145
const theLine = this.svgSelection.selectAll('.line').data([this.data], d => d.daysAgo);
theLine.exit().remove();
theLine.enter().append('path').attr('class', 'line').merge(theLine)
.transition().duration(1000)
.attr('d', line);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the d3 standard update pattern. You will see it a lot in this file. In order to update, this is needed, in this order.
It first searches for a selector that may or may not exist and passes it our data
Then it removes any of the elements from that search that are no longer needed.
Then it adds any new items from data its being passed and merges them.


private renderPoints(): void {
const points = this.svgSelection.selectAll('circle.point')
.data(this.data, d => d.daysAgo);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you will notice that many of the d3 update patterns are passing a second parameter to .data(). in this case i'm referring to d => d.daysAgo. This provides d3 a key to index the data on, which allows us to keep a reference when we're animating the data around.

Comment on lines 151 to 181
// these numbers are specific to its container
const localWidth = this.width - this.margin.right - this.margin.left - 34;
const thisRange = [localWidth, -this.margin.right];
const thisScale = d3.scaleLinear()
.domain(this.domainX)
.range(thisRange);

Copy link
Contributor Author

@SEAjamieD SEAjamieD May 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the tooltips have been a bit difficult to work with. The reason is that we cannot append html elements to an SVG, instead we have to attach them somewhere else in the dom. If we attach to the body, the positioning is easier, but we have unintended scroll issues, i.e. a tooltip scrolls with us when it shouldnt.
Instead I've chosen to attach it to the svg parent container. The best thing I could come up with to make the scaling fit across the X axis is to adjust the scaling down to roughly what the svg container is.

Comment on lines 174 to 202
// these numbers are specific to its container
const thisRange = [this.width - 48, 53];
const thisScale = d3.scaleLinear()
.domain(this.domainX)
.range(thisRange);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I applied the same trick for the buttons for the same reason, however the given UX styles required this anyways.

}
}

private renderGrid() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All through rendering the grid is where you'll see the margin variables come into play. This is standard d3.

Comment on lines 301 to 327
private getHoveredElement(d3Event): number {
const classes = d3.select(d3Event.target).attr('class');
const match = classes.match(/elem-([0-9]{1,2})/g)[0];
const num = match.split('-')[1];
return num;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function is used to gather which number element is being highlighted, which we can then use to highlight all of our other elements in pairing.

@SEAjamieD SEAjamieD force-pushed the jamie/19-new-line-graph branch 2 times, most recently from 6ce896c to 5db3e71 Compare May 8, 2020 17:26
Copy link
Contributor

@msorens msorens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize you're not yet in review, but just a few comments.

@SEAjamieD SEAjamieD force-pushed the jamie/19-new-line-graph branch from a4ec8fd to 0862a29 Compare May 11, 2020 16:15
@SEAjamieD SEAjamieD requested review from msorens and a team May 11, 2020 19:11
@SEAjamieD
Copy link
Contributor Author

Updated with stronger typing, named constants, and feedback from UI team

@scottopherson
Copy link
Contributor

Fluid width behavior lookin good 👍

@scottopherson
Copy link
Contributor

Tooltips seem to be a tad offset from center:
Screen Shot 2020-05-11 at 3 36 01 PM

@@ -0,0 +1,13 @@
<svg #svg [attr.viewBox]="viewBox"
[ngStyle]="{'width': width}"
(window:resize)="onResize()">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reminds me of a potential future issue with the compliance line chart as well. If the parent container of the chart should change its width for whatever reason (maybe an extra panel opens or something) then the chart will not resize itself because the overall viewport is not being resized:

However with the current dashboard layout and how it resizes its layout when opening side panels, the parent container of this chart still remains the same size so relying on window:resize is okay for now just like it's currently okay in the compliance reports view. But it could perhaps be an issue in the future should things change with the design so wanted to make a note of this elsewhere besides my own brain. It'll be trickier to implement but I know there are ways to avoid needing to manually redraw based on viewport or parent container width, giving us more flexible and performant charts to work with.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a really good snag. Thanks for documenting. I'll leave for now because of the reasons you mention, but will keep in mind. I'll do a little research on this when I have the opportunity.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh interesting! 👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ResizeObserver could offer a solution if a polyfill exists for IE.

@SEAjamieD
Copy link
Contributor Author

Tooltips seem to be a tad offset from center:
Screen Shot 2020-05-11 at 3 36 01 PM

Yeah - I've been having a rough time getting them lined up exact. I'll give it another look.

@SEAjamieD SEAjamieD force-pushed the jamie/19-new-line-graph branch from 97f2e76 to 4f3fe2c Compare May 15, 2020 20:49
@SEAjamieD
Copy link
Contributor Author

Waiting til desktop updates are merged to pull this one in

seajamied added 20 commits May 18, 2020 12:08
its gets a little unweildy with d3, and I can't seem to find good
, solid resources on how to apply typescript to d3, so i'm leaving as
is for now

Signed-off-by: seajamied <[email protected]>
Signed-off-by: seajamied <[email protected]>
Signed-off-by: seajamied <[email protected]>
Signed-off-by: seajamied <[email protected]>
Signed-off-by: seajamied <[email protected]>
Signed-off-by: seajamied <[email protected]>
Signed-off-by: seajamied <[email protected]>
Signed-off-by: seajamied <[email protected]>
Signed-off-by: seajamied <[email protected]>
Signed-off-by: seajamied <[email protected]>
Signed-off-by: seajamied <[email protected]>
@SEAjamieD SEAjamieD force-pushed the jamie/19-new-line-graph branch from 4f3fe2c to 7bc0be3 Compare May 18, 2020 19:19
@SEAjamieD SEAjamieD force-pushed the jamie/19-new-line-graph branch from 7bc0be3 to 99d2255 Compare May 18, 2020 19:22
Copy link
Contributor

@msorens msorens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good!
Two small things:

  1. I am assuming that the name changed somewhere along the line? (Instructions said go to "Last Check in By day".)

  2. The "100%" is partially obscured:

image

Comment on lines +110 to +112
if (this.data && this.data.length > 0) {
this.renderChart();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if you can do away with this by deleting the guard against changes.data.firstChange in ngOnChanges ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like I can't - I always end up with errors in the console if I don't check for firstChange

@SEAjamieD
Copy link
Contributor Author

image

@apriofrost - This is a simple change so can always update later, but wanted to make sure you've seen that whenever the last 2 check ins are in high percentages, the 100% gets obscured. Thanks for pointing out @msorens

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

dotted line graph
4 participants