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

22 #30

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

22 #30

wants to merge 2 commits into from

Conversation

SuperConfuserUser
Copy link

Added static designs for the vApp visual component.

Netlify Demo

// handled by the parent
if (this._fontWeight) {
super.setFontWeight('bold');
}
Copy link
Author

@SuperConfuserUser SuperConfuserUser Sep 25, 2019

Choose a reason for hiding this comment

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

feels like there may be a better way of changing label's font style and having the label background update.

most of the questions for any label type components are essentially based on how to inherit or derive from the base LabelComponent.

Copy link
Member

Choose a reason for hiding this comment

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

we could probably add an on('frame') event handler for the label component that checks if clipping/resizing is needed on every frame.. then text properties could be updated naturally without having to worry about ensuring that the clipping and sizing are updated explicitly. (Or every N frames if the logic is too expensive, but it looks cheap to me at the moment).

Copy link
Author

Choose a reason for hiding this comment

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

setting all text properties in a LabelTextComponent first. the label background draws afterwards without having to update

}

// TODO: maxWidth and clip is reused from the generic label component. is there a better way to share these?
/**
Copy link
Author

Choose a reason for hiding this comment

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

would it be better to extend this component from the LabelComponent? the label style is fairly different and it doesn't need the label background at all

Copy link
Member

Choose a reason for hiding this comment

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

it would be nice to share this logic in one way or another. if this component doesn't need most of what the label component offers, it might be good to break out an even more abstract component for just the text clipping piece, that can be extended by boht.

Copy link
Author

Choose a reason for hiding this comment

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

new LabelTextComponent handles text styling and clipping

this._label.fontWeight = weight;
this.clip();
this._background.bounds.width = this._label.bounds.width + (LABEL_HORIZONTAL_PADDING * 2);
}
Copy link
Author

Choose a reason for hiding this comment

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

would it be better to make this more generic and pass in a configuration object? ex. setFontStyle({ weight: 'bold' })

Copy link
Member

Choose a reason for hiding this comment

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

if we keep it like this, then yeah probably so. I'm thinking the frame event handler is probably the way to go here, though

// vms and vnics list
this.vms = new VmAndVnicListComponent(
this._vapp.vms,
this.vappNetworks && this.vappNetworks.networkPositionsByName,
Copy link
Author

Choose a reason for hiding this comment

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

passing 'networkPositionsByName' derived from vappNetworks component here. is there a better way or naming convention to use? more documentation? // networkPositionsByName have x position data for matching vnics

Copy link
Member

Choose a reason for hiding this comment

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

it was clear to me but might be helpful to be more explicit about the fact that it's the X position. maybe networkXPositionsByName

Copy link
Author

Choose a reason for hiding this comment

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

since it's clear, i'll leave it as is. there's a possibility that positions might need to be converted (local, global, parent, child) later on, so i'll keep full position data


// finish VappNetworks - draw the top external segment and internal segment based on matching vnic positions
if (vappNetworkCount) {
this.vappNetworks.setTopAndBottomSegments(this.vms.lowestVnicPointByNetworkName);
Copy link
Author

Choose a reason for hiding this comment

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

passing 'lowestVnicPointByNetworkName' derived from vmsAndVnicList component here. is there a better way or naming convention to use? more documentation? // lowestVnicPointByNetworkName contains the lowest point data for matching vapp networks

Copy link
Member

Choose a reason for hiding this comment

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

made sense to me, so I think it's OK

* Virtual Application Visual Component.
*/
export class VappComponent extends paper.Group {

Copy link
Author

Choose a reason for hiding this comment

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

this is the major parent component that encapsulates everything else and handles most of the interdependent and shared data

// reusable calculations
const vappNetworkCount = Object.keys(this.vappNetworkPositionsByName).length;
this.lastNetworkPositionX = vappNetworkCount && (vappNetworkCount - 1) * VAPP_NETWORK_RIGHT_MARGIN
+ CONNECTOR_RADIUS - DEFAULT_STROKE_WIDTH;
Copy link
Author

Choose a reason for hiding this comment

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

could also loop through vappNetworkPositionsByName from line 36 to find max position instead of calculating it like this. does it matter?

Copy link
Author

Choose a reason for hiding this comment

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

actually, there's an even simpler way of getting it from the bounds of the VappNetworkListComponent from the main VappComponent.

Copy link
Member

Choose a reason for hiding this comment

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

yeah, probably better to get it that way vs. having this calculation that is dependent on other, previous calulations

this._vapp.vapp_networks,
new paper.Point(VAPP_PADDING + CONNECTOR_RADIUS, 0));
this.addChild(this.vappNetworks);
}
Copy link
Author

Choose a reason for hiding this comment

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

max (furthest right) vapp network position can be derived from this component's bounds to pass to the vmAndVnicListComponent

Copy link
Author

Choose a reason for hiding this comment

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

nevermind, edge labels can throw the width off

Copy link
Author

Choose a reason for hiding this comment

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

simplifying even more by using the value straight from the vappNetworkList.lastNetworkPosition

Copy link
Member

@cfsnyder cfsnyder left a comment

Choose a reason for hiding this comment

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

I finished an initial review but I need to come back and look at a few things more closely when I have time. Nice job, looking good so far!

);
if (scrollbar.isEnabled) {
canvas.onmouseenter = scrollbar.containerMouseEnter;
Copy link
Member

Choose a reason for hiding this comment

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

I don't like this pattern where you're requiring the parent component to bind the event handlers. That should be internal to the scrollbar at the time it is created. I suggest creating a wrapper for the canvas that you're rendering to which exposes Observables that are bound to those event handlers so that any component can easily subscribe to them.

Copy link
Author

Choose a reason for hiding this comment

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

event handlers are internal to the scrollbar now


const content = new paper.Group({ applyMatrix: false });
// create origin paper Item for vapps to base position from
const origin = new paper.Path.Circle({
Copy link
Member

Choose a reason for hiding this comment

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

what is this about?

Copy link
Author

Choose a reason for hiding this comment

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

VApps base their x position on the last child of the content group (line 44 - content.lastChild.bounds.right). Most vApps will have the previous vApp to refer to, but the very first one won't. The origin was created to be the first vApp's reference point. One way it could also be avoided is by doing a check in the loop at line 43:

vapps.forEach((vappData, index) => {
  const position = new paper.Point(index === 0 ? 'explicit number' : content.lastChild.bounds.right), VERTICAL_POSITION);
    ...
}

/**
* Gets isEnabled state. The scrollbar is enabled when content does not fit the container.
*/
get isEnabled(): boolean {
Copy link
Member

Choose a reason for hiding this comment

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

typically a boolean field on a class (or a property accessor, like you have here) would just be named enabled. Names like isEnabled are usually used for getter methods

@@ -1,4 +1,7 @@
/* You can add global styles to this file, and also import other style files */

@import (css) url('https://fonts.googleapis.com/css?family=Roboto:400,500,700&display=swap');
Copy link
Member

Choose a reason for hiding this comment

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

where are we at with this? did you end up handling the issues that we talked about, where the font loads too slow and calculation of component positioning is based upon the wrong font sizes? Perfectly fine if that's still a TODO, I'm just curious

Copy link
Author

Choose a reason for hiding this comment

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

yes. still a TODO right now. The delayed font loading seems to affect the label background sizes for the most part and could be solved with the onFrame solution suggested earlier. Another option I was thinking of looking into was using the Angular lifecycle methods to wait for the font to load completely before rendering the canvas. Or have an observable/promise that waits for the font to load, and then redraw. There are a few other font loading techniques too that I haven't dug into yet.

import { VAPP_BACKGROUND_COLOR, CANVAS_BACKGROUND_COLOR } from '../constants/colors';
import * as paper from 'paper';

describe('connector component', () => {
Copy link
Member

Choose a reason for hiding this comment

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

nice!

* Clones the bottom segment of vapp networks to separate for scrolling and removes the original segment.
* @param splitPositionY vertical point where the network path should be split for cloning and separation
*/
cloneVmListSegments(splitPositionY: number) {
Copy link
Member

Choose a reason for hiding this comment

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

missing return type

// vms and vnics list
this.vms = new VmAndVnicListComponent(
this._vapp.vms,
this.vappNetworks && this.vappNetworks.networkPositionsByName,
Copy link
Member

Choose a reason for hiding this comment

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

it was clear to me but might be helpful to be more explicit about the fact that it's the X position. maybe networkXPositionsByName


// finish VappNetworks - draw the top external segment and internal segment based on matching vnic positions
if (vappNetworkCount) {
this.vappNetworks.setTopAndBottomSegments(this.vms.lowestVnicPointByNetworkName);
Copy link
Member

Choose a reason for hiding this comment

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

made sense to me, so I think it's OK

*/
// TODO: add scroll listener with a better method. it's in parent demo component for now. could create a native canvas
// event observable service similar to the paper.event service?
setScrollListening(event: WheelEvent) {
Copy link
Member

Choose a reason for hiding this comment

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

yeah we definitely need to do something different for these event bindings, this is going to get out of hand like this

// reusable calculations
const vappNetworkCount = Object.keys(this.vappNetworkPositionsByName).length;
this.lastNetworkPositionX = vappNetworkCount && (vappNetworkCount - 1) * VAPP_NETWORK_RIGHT_MARGIN
+ CONNECTOR_RADIUS - DEFAULT_STROKE_WIDTH;
Copy link
Member

Choose a reason for hiding this comment

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

yeah, probably better to get it that way vs. having this calculation that is dependent on other, previous calulations

* Clips and adds scrolling to the VmAndVnicList component when it's too large for the view.
*/
private clipAndScrollVmList() {
// create drop shadow at the top of the vm list that fades in or out onScroll
Copy link
Author

Choose a reason for hiding this comment

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

add return type

return expectedVnicPoints;
}

test.only('basic properties and vnics on different networks', () => {
Copy link
Author

Choose a reason for hiding this comment

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

remove only

Copy link
Author

Choose a reason for hiding this comment

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

from all the tests

@SuperConfuserUser
Copy link
Author

@mathieupkf - Could you also review the visuals? Netlify Demo

The request to display scrollbars only on scroll area hover has also been implemented. There's a lot going on for visibility and opacity with the scrollbar system. Trying to add the 1s delay/fade in with all of that made the visuals very buggy unfortunately.

The extra edge cases that aren't explicitly in the InVision designs are for a visual check on some of the layout logic. Let me know if the different vApp cases could be arranged better too. Thanks!

@mathieupkf
Copy link

@SuperConfuserUser - thanks Chely.
The scrollbar apparition is really nice. Can we add an opacity delay ? 0 to 100%. Duration 0.3s.
I have another suggestion for the scroll area (I'm not 100% sure so keep what we have right now). The shadow element looks a little bit too strong, I don't really like it. Can we try without it? Can we try by starting the scroll area just below the vApp Name / the Edge Name?

@SuperConfuserUser
Copy link
Author

@mathieupkf - a few updated scrollbar demos ready. 2 or 3 would be my personal pick. The more subtle drop shadow would be a nice touch to show the fold. Can do more variations as well if you have more ideas.

  1. no margins
  2. 10px margin
  3. 10px margin and lighter and smaller drop shadow

@mathieupkf
Copy link

mathieupkf commented Oct 9, 2019

Thanks @SuperConfuserUser !
I'm not 100% sure yet... This scroll area looks a little bit odd to me, don't you think? I have a last suggestion and I'll make my final choice after that ;)
Can you create another variation where the whole height of the vApp will be scrollable ? vApp titles / Edge titles will scroll like the content.

@SuperConfuserUser
Copy link
Author

@mathieupkf - Thanks for the review! The scrollbar dragging bug is fixed in this demo. We can definitely explore more scrollbar improvements when the project picks back up.

network_name: '',
is_connected: false
network_name: 'A',
is_connected: true
},
Copy link
Author

Choose a reason for hiding this comment

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

testing a case for when connected and disconnected vnics are out of order


// draw vms and their vnics
this._vms.forEach((vmData, index) => {
const pointY = (LABEL_HEIGHT + VM_MARGIN_VERTICAL) * index;
const sharedPointY = (LABEL_HEIGHT + VM_MARGIN_VERTICAL) * index;
let xPositionMultiplier = hasVappNetworks ? 1 : 0;
Copy link
Author

Choose a reason for hiding this comment

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

this would also work as let xPositionMultiplier = hasVappNetworks since it's a boolean, but i wanted to be super explicit about where values come from

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

Successfully merging this pull request may close these issues.

3 participants