mirror of
https://github.com/weaveworks/scope.git
synced 2026-08-18 03:46:45 +00:00
Fixed the node labels bug on Firefox.
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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 (
|
||||
<g transform={`translate(0, ${translateY})`}>
|
||||
<g transform={`translate(0, ${translateY}) scale(${NODE_BASE_SIZE})`}>
|
||||
{bars.toJS()}
|
||||
</g>
|
||||
);
|
||||
|
||||
@@ -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 (
|
||||
<g className="shape shape-cloud">
|
||||
|
||||
@@ -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 (
|
||||
<g className="node-labels-container" y={labelOffsetY}>
|
||||
<text className={labelClassName} y={13} textAnchor="middle">{label}</text>
|
||||
<text className={subLabelClassName} y={30} textAnchor="middle">
|
||||
<g className="node-labels-container">
|
||||
<text className={labelClassName} y={13 + labelOffsetY} textAnchor="middle">{label}</text>
|
||||
<text className={subLabelClassName} y={30 + labelOffsetY} textAnchor="middle">
|
||||
{subLabel}
|
||||
</text>
|
||||
</g>
|
||||
@@ -81,7 +83,12 @@ class Node extends React.Component {
|
||||
const matchedNodeDetails = matchedMetadata.concat(matchedParents);
|
||||
|
||||
return (
|
||||
<foreignObject className="node-labels-container" y={labelOffsetY}>
|
||||
<foreignObject
|
||||
className="node-labels-container"
|
||||
y={labelOffsetY}
|
||||
x={-0.5 * labelWidth}
|
||||
width={labelWidth}
|
||||
height="5em">
|
||||
<div className="node-label-wrapper" {...mouseEvents}>
|
||||
<div className={labelClassName}>
|
||||
<MatchedText text={label} match={matches.get('label')} />
|
||||
@@ -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 (
|
||||
<g className={nodeClassName} transform={transform}>
|
||||
{useSvgLabels || false ?
|
||||
{useSvgLabels ?
|
||||
this.renderSvgLabels(labelClassName, subLabelClassName, labelOffsetY) :
|
||||
this.renderStandardLabels(labelClassName, subLabelClassName, labelOffsetY, mouseEvents)}
|
||||
|
||||
@@ -134,11 +140,7 @@ class Node extends React.Component {
|
||||
<NodeShapeType color={color} {...this.props} />
|
||||
</g>
|
||||
|
||||
{showingNetworks && <NodeNetworksOverlay
|
||||
offset={networkOffset}
|
||||
networks={networks}
|
||||
stack={stack}
|
||||
/>}
|
||||
{showingNetworks && <NodeNetworksOverlay networks={networks} stack={stack} />}
|
||||
</g>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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')}
|
||||
/>)}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 (
|
||||
<defs>
|
||||
<clipPath id={clipId}>
|
||||
<clipPath id={clipId} transform={`scale(${NODE_BASE_SIZE})`}>
|
||||
<rect width={1} height={1} x={-0.5} y={0.5 - height} />
|
||||
</clipPath>
|
||||
</defs>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user