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

Use a sanely sized canvas for the span mini-map #257

Merged
merged 1 commit into from
Sep 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import * as React from 'react';

import renderIntoCanvas, { CV_WIDTH } from './render-into-canvas';
import renderIntoCanvas from './render-into-canvas';
import colorGenerator from '../../../utils/color-generator';

import './CanvasSpanGraph.css';
Expand Down Expand Up @@ -57,13 +57,6 @@ export default class CanvasSpanGraph extends React.PureComponent<CanvasSpanGraph
}

render() {
return (
<canvas
className="CanvasSpanGraph"
ref={this._setCanvasRef}
width={CV_WIDTH}
height={this.props.items.length}
/>
);
return <canvas className="CanvasSpanGraph" ref={this._setCanvasRef} />;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,53 +15,48 @@
// limitations under the License.

// exported for tests
export const CV_WIDTH = 4000;
export const MIN_WIDTH = 16;
export const BG_COLOR = '#f5f5f5';
export const ITEM_ALPHA = 0.8;
export const MIN_ITEM_HEIGHT = 2;
export const MAX_TOTAL_HEIGHT = 200;
export const MIN_ITEM_WIDTH = 10;
export const MIN_TOTAL_HEIGHT = 60;
export const ALPHA = 0.8;

export default function renderIntoCanvas(
canvas: HTMLCanvasElement,
items: { valueWidth: number, valueOffset: number, serviceName: string }[],
totalValueWidth: number,
getFillColor: string => [number, number, number]
) {
// eslint-disable-next-line no-param-reassign
canvas.width = CV_WIDTH;
let itemHeight = 1;
let itemYChange = 1;
if (items.length < MIN_TOTAL_HEIGHT) {
// eslint-disable-next-line no-param-reassign
canvas.height = MIN_TOTAL_HEIGHT;
itemHeight = MIN_TOTAL_HEIGHT / items.length;
itemYChange = MIN_TOTAL_HEIGHT / items.length;
} else {
// eslint-disable-next-line no-param-reassign
canvas.height = items.length;
itemYChange = 1;
itemHeight = 1 / (MIN_TOTAL_HEIGHT / items.length);
}
const ctx = canvas.getContext('2d');
const fillCache: Map<string, ?string> = new Map();
const cHeight =
items.length < MIN_TOTAL_HEIGHT ? MIN_TOTAL_HEIGHT : Math.min(items.length, MAX_TOTAL_HEIGHT);
const cWidth = window.innerWidth * 2;
// eslint-disable-next-line no-param-reassign
canvas.width = cWidth;
// eslint-disable-next-line no-param-reassign
canvas.height = cHeight;
const itemHeight = Math.max(MIN_ITEM_HEIGHT, cHeight / items.length);
const itemYChange = cHeight / items.length;

const ctx = canvas.getContext('2d', { alpha: false });
ctx.fillStyle = BG_COLOR;
ctx.fillRect(0, 0, cWidth, cHeight);
for (let i = 0; i < items.length; i++) {
const { valueWidth, valueOffset, serviceName } = items[i];
// eslint-disable-next-line no-bitwise
const x = (valueOffset / totalValueWidth * CV_WIDTH) | 0;
// eslint-disable-next-line no-bitwise
let width = (valueWidth / totalValueWidth * CV_WIDTH) | 0;
if (width < MIN_WIDTH) {
width = MIN_WIDTH;
const x = valueOffset / totalValueWidth * cWidth;
let width = valueWidth / totalValueWidth * cWidth;
if (width < MIN_ITEM_WIDTH) {
width = MIN_ITEM_WIDTH;
}
let fillStyle = fillCache.get(serviceName);
if (fillStyle) {
ctx.fillStyle = fillStyle;
} else {
if (!fillStyle) {
fillStyle = `rgba(${getFillColor(serviceName)
.concat(ALPHA)
.concat(ITEM_ALPHA)
.join()})`;
fillCache.set(serviceName, fillStyle);
ctx.fillStyle = fillStyle;
}
ctx.fillStyle = fillStyle;
ctx.fillRect(x, i * itemYChange, width, itemHeight);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,24 @@

import _range from 'lodash/range';

import renderIntoCanvas, { ALPHA, CV_WIDTH, MIN_TOTAL_HEIGHT, MIN_WIDTH } from './render-into-canvas';
import renderIntoCanvas, {
BG_COLOR,
ITEM_ALPHA,
MIN_ITEM_HEIGHT,
MAX_TOTAL_HEIGHT,
MIN_ITEM_WIDTH,
MIN_TOTAL_HEIGHT,
} from './render-into-canvas';

const getCanvasWidth = () => window.innerWidth * 2;
const getBgFillRect = items => ({
fillStyle: BG_COLOR,
height:
!items || items.length < MIN_TOTAL_HEIGHT ? MIN_TOTAL_HEIGHT : Math.min(MAX_TOTAL_HEIGHT, items.length),
width: getCanvasWidth(),
x: 0,
y: 0,
});

describe('renderIntoCanvas()', () => {
const basicItem = { valueWidth: 100, valueOffset: 50, serviceName: 'some-name' };
Expand Down Expand Up @@ -72,7 +89,7 @@ describe('renderIntoCanvas()', () => {
const canvas = new Canvas();
expect(canvas.width !== canvas.width).toBe(true);
renderIntoCanvas(canvas, [basicItem], 150, getColorFactory());
expect(canvas.width).toBe(CV_WIDTH);
expect(canvas.width).toBe(getCanvasWidth());
});

describe('when there are limited number of items', () => {
Expand All @@ -83,6 +100,18 @@ describe('renderIntoCanvas()', () => {
expect(canvas.height).toBe(MIN_TOTAL_HEIGHT);
});

it('draws the background', () => {
const expectedDrawing = [getBgFillRect()];
const canvas = new Canvas();
const items = [];
const totalValueWidth = 4000;
const getFillColor = getColorFactory();
renderIntoCanvas(canvas, items, totalValueWidth, getFillColor);
expect(canvas.getContext.mock.calls).toEqual([['2d', { alpha: false }]]);
expect(canvas.contexts.length).toBe(1);
expect(canvas.contexts[0].fillRectAccumulator).toEqual(expectedDrawing);
});

it('draws the map', () => {
const totalValueWidth = 4000;
const items = [
Expand All @@ -95,19 +124,24 @@ describe('renderIntoCanvas()', () => {
{ input: items[1].serviceName, output: [1, 1, 1] },
{ input: items[2].serviceName, output: [2, 2, 2] },
];
const expectedDrawings = items.map((item, i) => {
const { valueWidth: width, valueOffset: x } = item;
const color = expectedColors[i].output;
const fillStyle = `rgba(${color.concat(ALPHA).join()})`;
const height = MIN_TOTAL_HEIGHT / items.length;
const y = height * i;
return { fillStyle, height, width, x, y };
});
const expectedDrawings = [
getBgFillRect(),
...items.map((item, i) => {
const { valueWidth, valueOffset } = item;
const color = expectedColors[i].output;
const fillStyle = `rgba(${color.concat(ITEM_ALPHA).join()})`;
const height = MIN_TOTAL_HEIGHT / items.length;
const width = valueWidth / totalValueWidth * getCanvasWidth();
const x = valueOffset / totalValueWidth * getCanvasWidth();
const y = height * i;
return { fillStyle, height, width, x, y };
}),
];
const canvas = new Canvas();
const getFillColor = getColorFactory();
renderIntoCanvas(canvas, items, totalValueWidth, getFillColor);
expect(getFillColor.inputOutput).toEqual(expectedColors);
expect(canvas.getContext.mock.calls).toEqual([['2d']]);
expect(canvas.getContext.mock.calls).toEqual([['2d', { alpha: false }]]);
expect(canvas.contexts.length).toBe(1);
expect(canvas.contexts[0].fillRectAccumulator).toEqual(expectedDrawings);
});
Expand All @@ -132,25 +166,28 @@ describe('renderIntoCanvas()', () => {
valueOffset: i,
serviceName: `service-name-${i}`,
}));
const itemHeight = 1 / (MIN_TOTAL_HEIGHT / items.length);
const expectedColors = items.map((item, i) => ({
input: item.serviceName,
output: [i, i, i],
}));
const expectedDrawings = items.map((item, i) => {
const { valueWidth, valueOffset: x } = item;
const width = Math.max(valueWidth, MIN_WIDTH);
const color = expectedColors[i].output;
const fillStyle = `rgba(${color.concat(ALPHA).join()})`;
const height = itemHeight;
const y = i;
return { fillStyle, height, width, x, y };
});
const expectedDrawings = [
getBgFillRect(items),
...items.map((item, i) => {
const { valueWidth, valueOffset } = item;
const color = expectedColors[i].output;
const fillStyle = `rgba(${color.concat(ITEM_ALPHA).join()})`;
const height = MIN_ITEM_HEIGHT;
const width = Math.max(MIN_ITEM_WIDTH, valueWidth / totalValueWidth * getCanvasWidth());
const x = valueOffset / totalValueWidth * getCanvasWidth();
const y = MAX_TOTAL_HEIGHT / items.length * i;
return { fillStyle, height, width, x, y };
}),
];
const canvas = new Canvas();
const getFillColor = getColorFactory();
renderIntoCanvas(canvas, items, totalValueWidth, getFillColor);
expect(getFillColor.inputOutput).toEqual(expectedColors);
expect(canvas.getContext.mock.calls).toEqual([['2d']]);
expect(canvas.getContext.mock.calls).toEqual([['2d', { alpha: false }]]);
expect(canvas.contexts.length).toBe(1);
expect(canvas.contexts[0].fillRectAccumulator).toEqual(expectedDrawings);
});
Expand Down