diff --git a/client/app/scripts/charts/node-container.js b/client/app/scripts/charts/node-container.js index dc92b46bc..8f5817026 100644 --- a/client/app/scripts/charts/node-container.js +++ b/client/app/scripts/charts/node-container.js @@ -4,7 +4,7 @@ import { connect } from 'react-redux'; import { Motion, spring } from 'react-motion'; import { NODES_SPRING_ANIMATION_CONFIG } from '../constants/animation'; -import { NODE_BASE_SIZE, NODE_BLUR_OPACITY } from '../constants/styles'; +import { NODE_BLUR_OPACITY } from '../constants/styles'; import Node from './node'; const transformedNode = (otherProps, { x, y, k }) => ( @@ -13,10 +13,9 @@ const transformedNode = (otherProps, { x, y, k }) => ( class NodeContainer extends React.Component { render() { - const { dx, dy, isAnimated, magnified, blurred } = this.props; - const forwardedProps = omit(this.props, 'dx', 'dy', 'isAnimated', 'magnified', 'blurred'); + const { dx, dy, isAnimated, scale, blurred } = this.props; + const forwardedProps = omit(this.props, 'dx', 'dy', 'isAnimated', 'scale', 'blurred'); const opacity = blurred ? NODE_BLUR_OPACITY : 1; - const scale = magnified * NODE_BASE_SIZE; // NOTE: Controlling blurring from here seems to re-render faster // than adding a CSS class and controlling it from there. diff --git a/client/app/scripts/charts/node-networks-overlay.js b/client/app/scripts/charts/node-networks-overlay.js index b8af48b36..ae1b45710 100644 --- a/client/app/scripts/charts/node-networks-overlay.js +++ b/client/app/scripts/charts/node-networks-overlay.js @@ -3,15 +3,17 @@ import { scaleBand } from 'd3-scale'; import { List as makeList } from 'immutable'; import { getNetworkColor } from '../utils/color-utils'; import { isContrastMode } from '../utils/contrast-utils'; +import { NODE_BASE_SIZE } from '../constants/styles'; // Min size is about a quarter of the width, feels about right. const minBarWidth = 0.25; const barHeight = 0.08; const innerPadding = 0.04; const borderRadius = 0.01; +const offset = 0.67; const x = scaleBand(); -function NodeNetworksOverlay({offset, stack, networks = makeList()}) { +function NodeNetworksOverlay({ stack, networks = makeList() }) { const barWidth = Math.max(1, minBarWidth * networks.size); const yPosition = offset - (barHeight * 0.5); @@ -37,7 +39,7 @@ function NodeNetworksOverlay({offset, stack, networks = makeList()}) { const translateY = stack && isContrastMode() ? 0.15 : 0; return ( - + {bars.toJS()} ); diff --git a/client/app/scripts/charts/node-shape-cloud.js b/client/app/scripts/charts/node-shape-cloud.js index 61af2f392..3278ea651 100644 --- a/client/app/scripts/charts/node-shape-cloud.js +++ b/client/app/scripts/charts/node-shape-cloud.js @@ -4,17 +4,18 @@ import { NODE_SHAPE_BORDER_RADIUS, NODE_SHAPE_SHADOW_RADIUS, NODE_SHAPE_DOT_RADIUS, + NODE_BASE_SIZE, } from '../constants/styles'; -// This path is already normalized so no rescaling is needed. -const CLOUD_PATH = 'M-1.25 0.233Q-1.25 0.44-1.104 0.587-0.957 0.733-0.75 0.733H0.667Q0.908 ' - + '0.733 1.079 0.562 1.25 0.391 1.25 0.15 1.25-0.022 1.158-0.164 1.065-0.307 0.914-0.377q' - + '0.003-0.036 0.003-0.056 0-0.276-0.196-0.472-0.195-0.195-0.471-0.195-0.206 0-0.373 0.115' - + '-0.167 0.115-0.244 0.299-0.091-0.081-0.216-0.081-0.138 0-0.236 0.098-0.098 0.098-0.098 ' - + '0.236 0 0.098 0.054 0.179-0.168 0.039-0.278 0.175-0.109 0.136-0.109 0.312z'; +// This path is already normalized so no dynamic rescaling is needed. +const CLOUD_PATH = 'M-125 23.333Q-125 44.036-110.352 58.685-95.703 73.333-75 73.333H66.667Q90.755 ' + + '73.333 107.878 56.211 125 39.089 125 15 125-2.188 115.755-16.445 106.51-30.703 91.406-37.734q' + + '0.26-3.646 0.261-5.599 0-27.604-19.532-47.136-19.531-19.531-47.135-19.531-20.573 0-37.305 ' + + '11.458-16.732 11.458-24.414 29.948-9.115-8.073-21.614-8.073-13.802 0-23.568 9.766-9.766 9.766-' + + '9.766 23.568 0 9.766 5.339 17.968-16.797 3.906-27.735 17.513-10.938 13.607-10.937 31.185z'; export default function NodeShapeCloud({highlighted, color}) { - const pathProps = r => ({ d: CLOUD_PATH, transform: `scale(${r})` }); + const pathProps = r => ({ d: CLOUD_PATH, transform: `scale(${r / NODE_BASE_SIZE})` }); return ( diff --git a/client/app/scripts/charts/node.js b/client/app/scripts/charts/node.js index dabed89e6..9cd392749 100644 --- a/client/app/scripts/charts/node.js +++ b/client/app/scripts/charts/node.js @@ -7,6 +7,7 @@ import { clickNode, enterNode, leaveNode } from '../actions/app-actions'; import { getNodeColor } from '../utils/color-utils'; import MatchedText from '../components/matched-text'; import MatchedResults from '../components/matched-results'; +import { NODE_BASE_SIZE } from '../constants/styles'; import NodeShapeCircle from './node-shape-circle'; import NodeShapeStack from './node-shape-stack'; @@ -17,11 +18,7 @@ import NodeShapeCloud from './node-shape-cloud'; import NodeNetworksOverlay from './node-networks-overlay'; -function stackedShape(Shape) { - const factory = React.createFactory(NodeShapeStack); - return props => factory(Object.assign({}, props, {shape: Shape})); -} - +const labelWidth = 1.4 * NODE_BASE_SIZE; const nodeShapes = { circle: NodeShapeCircle, hexagon: NodeShapeHexagon, @@ -30,6 +27,11 @@ const nodeShapes = { cloud: NodeShapeCloud }; +function stackedShape(Shape) { + const factory = React.createFactory(NodeShapeStack); + return props => factory(Object.assign({}, props, {shape: Shape})); +} + function getNodeShape({ shape, stack }) { const nodeShape = nodeShapes[shape]; if (!nodeShape) { @@ -65,9 +67,9 @@ class Node extends React.Component { renderSvgLabels(labelClassName, subLabelClassName, labelOffsetY) { const { label, subLabel } = this.props; return ( - - {label} - + + {label} + {subLabel} @@ -81,7 +83,12 @@ class Node extends React.Component { const matchedNodeDetails = matchedMetadata.concat(matchedParents); return ( - +
@@ -103,7 +110,6 @@ class Node extends React.Component { const color = getNodeColor(rank, label, pseudo); const truncate = !focused && !hovered; const labelOffsetY = (showingNetworks && networks) ? 40 : 28; - const networkOffset = 0.67; const nodeClassName = classnames('node', { highlighted, @@ -126,7 +132,7 @@ class Node extends React.Component { return ( - {useSvgLabels || false ? + {useSvgLabels ? this.renderSvgLabels(labelClassName, subLabelClassName, labelOffsetY) : this.renderStandardLabels(labelClassName, subLabelClassName, labelOffsetY, mouseEvents)} @@ -134,11 +140,7 @@ class Node extends React.Component { - {showingNetworks && } + {showingNetworks && } ); } diff --git a/client/app/scripts/charts/nodes-chart-nodes.js b/client/app/scripts/charts/nodes-chart-nodes.js index eecfce22c..9ce3c1181 100644 --- a/client/app/scripts/charts/nodes-chart-nodes.js +++ b/client/app/scripts/charts/nodes-chart-nodes.js @@ -71,7 +71,7 @@ class NodesChartNodes extends React.Component { metric={metric(node)} rank={node.get('rank')} isAnimated={isAnimated} - magnified={node.get('focused') ? selectedScale : 1} + scale={node.get('focused') ? selectedScale : 1} dx={node.get('x')} dy={node.get('y')} />)} diff --git a/client/app/scripts/constants/styles.js b/client/app/scripts/constants/styles.js index e7d6a16cf..3a68e0564 100644 --- a/client/app/scripts/constants/styles.js +++ b/client/app/scripts/constants/styles.js @@ -9,8 +9,6 @@ export const DETAILS_PANEL_MARGINS = { export const DETAILS_PANEL_OFFSET = 8; -export const CANVAS_METRIC_FONT_SIZE = 0.19; - export const CANVAS_MARGINS = { top: 160, left: 40, @@ -19,16 +17,18 @@ export const CANVAS_MARGINS = { }; // Node shapes -export const NODE_SHAPE_HIGHLIGHT_RADIUS = 0.7; -export const NODE_SHAPE_BORDER_RADIUS = 0.5; -export const NODE_SHAPE_SHADOW_RADIUS = 0.45; -export const NODE_SHAPE_DOT_RADIUS = 0.125; +export const NODE_SHAPE_HIGHLIGHT_RADIUS = 70; +export const NODE_SHAPE_BORDER_RADIUS = 50; +export const NODE_SHAPE_SHADOW_RADIUS = 45; +export const NODE_SHAPE_DOT_RADIUS = 10; export const NODE_BLUR_OPACITY = 0.2; -// NOTE: Modifying this value shouldn't actually change much in the way -// nodes are rendered, as long as its kept >> 1. The idea was to draw all -// the nodes in a unit scale and control their size just through scaling -// transform, but the problem is that dagre only works with integer coordinates, -// so this constant basically serves as a precision factor for dagre. +// NOTE: This value represents the node unit radius (in pixels). Since zooming is +// controlled at the top level now, this renormalization would be obsolete (i.e. +// value 1 could be used instead), if it wasn't for the following factors: +// 1. `dagre` library only works with integer coordinates, +// so >> 1 value is used to increase layout precision. +// 2. Fonts don't behave nicely (especially on Firefox) if they +// are given on a small unit scale as foreign objects in SVG. export const NODE_BASE_SIZE = 100; // Node details table constants diff --git a/client/app/scripts/selectors/nodes-chart-zoom.js b/client/app/scripts/selectors/nodes-chart-zoom.js index ca0db11dd..ede1e9c45 100644 --- a/client/app/scripts/selectors/nodes-chart-zoom.js +++ b/client/app/scripts/selectors/nodes-chart-zoom.js @@ -48,9 +48,9 @@ const defaultZoomSelector = createSelector( // Maximal allowed zoom will always be such that a node covers 1/5 of the viewport. const maxZoomScale = Math.min(width, height) / NODE_BASE_SIZE / 5; - // Initial zoom is such that the graph covers 90% of either - // the viewport, respecting the maximal zoom constraint. - const zoomScale = Math.min(xFactor, yFactor, maxZoomScale) * 0.9; + // Initial zoom is such that the graph covers 90% of either the viewport, + // or one half of maximal zoom constraint, whichever is smaller. + const zoomScale = Math.min(xFactor, yFactor, maxZoomScale / 2) * 0.9; // Finally, we always allow zooming out exactly 5x compared to the initial zoom. const minZoomScale = zoomScale / 5; diff --git a/client/app/scripts/utils/metric-utils.js b/client/app/scripts/utils/metric-utils.js index f27a56760..e67852a3f 100644 --- a/client/app/scripts/utils/metric-utils.js +++ b/client/app/scripts/utils/metric-utils.js @@ -2,14 +2,14 @@ import { includes } from 'lodash'; import { scaleLog } from 'd3-scale'; import React from 'react'; -import { NODE_SHAPE_DOT_RADIUS } from '../constants/styles'; +import { NODE_BASE_SIZE, NODE_SHAPE_DOT_RADIUS } from '../constants/styles'; import { formatMetricSvg } from './string-utils'; import { colors } from './color-utils'; export function getClipPathDefinition(clipId, height) { return ( - + diff --git a/client/app/styles/_base.scss b/client/app/styles/_base.scss index aaaea5f16..01e7df8df 100644 --- a/client/app/styles/_base.scss +++ b/client/app/styles/_base.scss @@ -319,9 +319,6 @@ .node-labels-container { transform: scale($node-text-scale); pointer-events: none; - height: 5em; - x: -0.5 * $node-labels-max-width; - width: $node-labels-max-width; } .node-label-wrapper { diff --git a/client/app/styles/_contrast-overrides.scss b/client/app/styles/_contrast-overrides.scss index a62c5de5f..1ae13c32b 100644 --- a/client/app/styles/_contrast-overrides.scss +++ b/client/app/styles/_contrast-overrides.scss @@ -14,8 +14,8 @@ $white: white; $node-opacity-blurred: 0.6; $node-highlight-fill-opacity: 0.3; $node-highlight-stroke-opacity: 0.5; -$node-highlight-stroke-width: 0.06; -$node-border-stroke-width: 0.1; +$node-highlight-stroke-width: 8; +$node-border-stroke-width: 10; $node-pseudo-opacity: 1; $edge-highlight-opacity: 0.3; $edge-opacity-blurred: 0; diff --git a/client/app/styles/_variables.scss b/client/app/styles/_variables.scss index 14c434d06..778322088 100644 --- a/client/app/styles/_variables.scss +++ b/client/app/styles/_variables.scss @@ -33,11 +33,10 @@ $terminal-header-height: 44px; $node-opacity-blurred: 0.25; $node-highlight-fill-opacity: 0.1; $node-highlight-stroke-opacity: 0.4; -$node-highlight-stroke-width: 0.02; -$node-border-stroke-width: 0.06; +$node-highlight-stroke-width: 2; +$node-border-stroke-width: 6; $node-pseudo-opacity: 0.8; -$node-text-scale: 0.02; -$node-labels-max-width: 120px; +$node-text-scale: 2; $edge-highlight-opacity: 0.1; $edge-opacity-blurred: 0.2; $edge-opacity: 0.5;