Browse Source

feat(profiling): improve color scheme (#42823)

Improve span color scheme

<img width="1068" alt="CleanShot 2023-01-05 at 13 37 25@2x"
src="https://user-images.githubusercontent.com/9317857/210856414-9e40b847-0831-4227-88c3-d01440d0bd1b.png">
Jonas 2 years ago
parent
commit
53faeadaed

+ 12 - 2
static/app/components/profiling/flamegraph/flamegraphSpans.tsx

@@ -1,4 +1,12 @@
-import {Fragment, useCallback, useEffect, useMemo, useRef, useState} from 'react';
+import {
+  CSSProperties,
+  Fragment,
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from 'react';
 import styled from '@emotion/styled';
 import {vec2} from 'gl-matrix';
 
@@ -275,6 +283,7 @@ export function FlamegraphSpans({
         onMouseLeave={onCanvasMouseLeave}
         onMouseUp={onCanvasMouseUp}
         onMouseDown={onCanvasMouseDown}
+        cursor={lastInteraction === 'pan' ? 'grabbing' : 'default'}
       />
       {/* transaction loads after profile, so we want to show loading even if it's in initial state */}
       {profiledTransaction.type === 'loading' ||
@@ -338,11 +347,12 @@ const LoadingIndicatorContainer = styled('div')`
   height: 100%;
 `;
 
-const Canvas = styled('canvas')`
+const Canvas = styled('canvas')<{cursor?: CSSProperties['cursor']}>`
   width: 100%;
   height: 100%;
   position: absolute;
   left: 0;
   top: 0;
   user-select: none;
+  cursor: ${p => p.cursor};
 `;

+ 1 - 3
static/app/utils/profiling/colors/utils.spec.tsx

@@ -64,9 +64,7 @@ describe('makeStackToColor', () => {
     const frames = [f(0, 'a')];
 
     const {colorBuffer} = makeFn(frames, makeColorMap, makeColorBucketTheme(LCH_LIGHT));
-    expect(colorBuffer.slice(0, 4)).toEqual([
-      0.9750000000000001, 0.7250000000000001, 0.7250000000000001, 1,
-    ]);
+    expect(colorBuffer.slice(0, 4)).toEqual([0.9625, 0.7125, 0.7125, 1]);
     expect(
       getDominantColor(colorBuffer.slice(0, 4) as [number, number, number, number])
     ).toBe('red');

+ 9 - 7
static/app/utils/profiling/colors/utils.tsx

@@ -43,7 +43,7 @@ export function fromLumaChromaHue(L: number, C: number, H: number): ColorChannel
       ? [X, 0, C]
       : [C, 0, X];
 
-  const m = L - (0.3 * R1 + 0.59 * G1 + 0.11 * B1);
+  const m = L - (0.35 * R1 + 0.35 * G1 + 0.35 * B1);
 
   return [clamp(R1 + m, 0, 1), clamp(G1 + m, 0, 1), clamp(B1 + m, 0, 1.0)];
 }
@@ -140,7 +140,8 @@ export function makeColorBucketTheme(
 ): (t: number) => ColorChannels {
   return t => {
     const x = triangle(30.0 * t);
-    const H = spectrum < 360 ? offset + spectrum * (0.9 * t) : spectrum * 0.9 * t;
+    const tx = 0.9 * t;
+    const H = spectrum < 360 ? offset + spectrum * tx : spectrum * tx;
     const C = lch.C_0 + lch.C_d * x;
     const L = lch.L_0 - lch.L_d * x;
     return fromLumaChromaHue(L, C, H);
@@ -305,14 +306,15 @@ export function makeSpansColorMapByOpAndDescription(
   colorBucket: FlamegraphTheme['COLORS']['COLOR_BUCKET']
 ): Map<SpanChartNode['node']['span']['span_id'], ColorChannels> {
   const colors = new Map<SpanChartNode['node']['span']['span_id'], ColorChannels>();
+  const uniqueSpans = uniqueBy(spans, s => s.node.span.op ?? '');
 
-  const uniqueSpans = uniqueBy(
-    spans,
-    s => s.node.span.op ?? '' + s.node.span.description ?? ''
-  );
+  for (let i = 0; i < uniqueSpans.length; i++) {
+    const key = uniqueSpans[i].node.span.op ?? '';
+    colors.set(key, colorBucket(i / uniqueSpans.length));
+  }
 
   for (let i = 0; i < spans.length; i++) {
-    colors.set(spans[i].node.span.span_id, colorBucket(i / uniqueSpans.length));
+    colors.set(spans[i].node.span.span_id, colors.get(spans[i].node.span.op ?? '')!);
   }
 
   return colors;

+ 16 - 2
static/app/utils/profiling/flamegraph/flamegraphTheme.tsx

@@ -106,6 +106,20 @@ export const LCH_DARK = {
   L_d: 0.1,
 };
 
+const SPAN_LCH_LIGHT = {
+  C_0: 0.25,
+  C_d: 0.2,
+  L_0: 0.7,
+  L_d: 0.25,
+};
+
+const SPANS_LCH_DARK = {
+  C_0: 0.2,
+  C_d: 0.1,
+  L_0: 0.2,
+  L_d: 0.1,
+};
+
 const SIZES: FlamegraphTheme['SIZES'] = {
   BAR_FONT_SIZE: 11,
   BAR_HEIGHT: 20,
@@ -137,7 +151,7 @@ export const LightFlamegraphTheme: FlamegraphTheme = {
   COLORS: {
     BAR_LABEL_FONT_COLOR: '#000',
     COLOR_BUCKET: makeColorBucketTheme(LCH_LIGHT),
-    SPAN_COLOR_BUCKET: makeColorBucketTheme(LCH_LIGHT, 120, 220),
+    SPAN_COLOR_BUCKET: makeColorBucketTheme(SPAN_LCH_LIGHT, 140, 220),
     COLOR_MAP: makeColorMap,
     CURSOR_CROSSHAIR: '#bbbbbb',
     DIFFERENTIAL_DECREASE: [0.309, 0.2058, 0.98],
@@ -167,7 +181,7 @@ export const DarkFlamegraphTheme: FlamegraphTheme = {
   COLORS: {
     BAR_LABEL_FONT_COLOR: 'rgb(255 255 255 / 80%)',
     COLOR_BUCKET: makeColorBucketTheme(LCH_DARK),
-    SPAN_COLOR_BUCKET: makeColorBucketTheme(LCH_DARK, 120, 220),
+    SPAN_COLOR_BUCKET: makeColorBucketTheme(SPANS_LCH_DARK, 140, 220),
     COLOR_MAP: makeColorMap,
     CURSOR_CROSSHAIR: '#828285',
     DIFFERENTIAL_DECREASE: [0.309, 0.2058, 0.98],

+ 1 - 1
static/app/utils/profiling/renderers/flamegraphRenderer.spec.tsx

@@ -143,7 +143,7 @@ describe('flamegraphRenderer', () => {
     );
 
     expect(renderer.getColorForFrame(flamegraph.frames[0])).toEqual([
-      0.9750000000000001, 0.7250000000000001, 0.7250000000000001,
+      0.9625, 0.7125, 0.7125,
     ]);
     expect(
       renderer.getColorForFrame({

+ 3 - 1
static/app/views/profiling/profileFlamechart.tsx

@@ -74,7 +74,9 @@ function ProfileFlamegraph(): React.ReactElement {
   const profiledTransaction = useProfileTransaction();
 
   const hasFlameChartSpans = useMemo(() => {
-    return organization.features.includes('organizations:profiling-flamechart-spans');
+    return (
+      organization.features.includes('organizations:profiling-flamechart-spans') || true
+    );
   }, [organization.features]);
 
   const spanTree: SpanTree = useMemo(() => {