Skip to content
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
1 change: 1 addition & 0 deletions config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ title = "The Development Seed Contributor Network"
author = "Pete Gadomski"
description = "An interactive visualization of contributors to Development Seed code and their connections to other repositories"
organization_name = "Development Seed"
organization_nickname = "DevSeed"
repositories = [
"developmentseed/titiler",
"developmentseed/lonboard",
Expand Down
1 change: 1 addition & 0 deletions public/data/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"author": "Pete Gadomski",
"description": "An interactive visualization of contributors to Development Seed code and their connections to other repositories",
"organization_name": "Development Seed",
"organization_nickname": "DevSeed",
"contributor_padding": 20,
"contributors": {
"AMSCamacho": "Angela Camacho",
Expand Down
1 change: 1 addition & 0 deletions python/contributor_network/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ def build(
"author": config.author,
"description": config.description,
"organization_name": config.organization_name,
"organization_nickname": config.organization_nickname,
"contributor_padding": config.contributor_padding,
"contributors": config.all_contributors,
}
Expand Down
2 changes: 2 additions & 0 deletions python/contributor_network/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class Config(BaseModel):
author: Author attribution
description: Description shown on the page
organization_name: Name of the organization (e.g., "Development Seed")
organization_nickname: Short name used in tooltips (e.g., "DevSeed")
repositories: List of GitHub repos to track (format: "owner/repo")
contributors: Nested dict of contributor categories, each mapping
GitHub username to display name
Expand All @@ -31,6 +32,7 @@ class Config(BaseModel):
author: str
description: str
organization_name: str
organization_nickname: str = ""
repositories: list[str]
contributors: dict[
str, dict[str, str]
Expand Down
4 changes: 3 additions & 1 deletion src/chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ export const createContributorNetworkVisual = (
container: HTMLElement,
contributor_padding: number,
masterContributorsList: Record<string, string>,
displayNameMap: Record<string, string>
displayNameMap: Record<string, string>,
orgNickname: string = 'DevSeed',
): ChartFunction => {
const PI = Math.PI;
const TAU = PI * 2;
Expand Down Expand Up @@ -887,6 +888,7 @@ export const createContributorNetworkVisual = (
COLOR_REPO,
COLOR_OWNER,
min,
orgNickname,
};
drawTooltipModule(
ctx,
Expand Down
4 changes: 3 additions & 1 deletion src/data/prepare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ export function prepareData(
d.archived = d.repo_archived === "true" || d.repo_archived === true;

d.totalContributors = +(d.repo_total_contributors ?? 0);
d.devseedContributors = +(d.repo_devseed_contributors ?? 0);
d.orgContributors = +(d.repo_devseed_contributors ?? 0);
d.externalContributors = +(d.repo_external_contributors ?? 0);
d.communityRatio = +(d.repo_community_ratio ?? 0);

Expand Down Expand Up @@ -325,6 +325,8 @@ export function prepareData(
contributors.find((r) => r.contributor_name === l.contributor_name),
)
.filter((c): c is ContributorData => c !== undefined);
d.totalCommits = d.repo_total_commits ? +d.repo_total_commits : undefined;
d.orgCommits = d3.sum(d.links_original, (l) => l.commit_count);
});

let owners: OwnerData[] = [];
Expand Down
5 changes: 4 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { createContributorNetworkVisual } from "./chart";

interface Config {
organization_name?: string;
organization_nickname?: string;
contributor_padding?: number;
contributors?: Record<string, string>;
title?: string;
Expand All @@ -18,6 +19,7 @@ if (!configResponse.ok) {
const config: Config = await configResponse.json();

const organizationName = config.organization_name || "Development Seed";
const orgNickname = config.organization_nickname || organizationName;
const contributor_padding = config.contributor_padding || 20;

const masterContributors: Record<string, string> = config.contributors || {};
Expand Down Expand Up @@ -51,7 +53,8 @@ const contributorNetworkVisual = createContributorNetworkVisual(
container,
contributor_padding,
masterContributors,
displayNameToUsername
displayNameToUsername,
orgNickname,
);
contributorNetworkVisual.width(size).height(size);

Expand Down
26 changes: 21 additions & 5 deletions src/render/repoCard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ export interface RepoCardData {
watchers?: number;
languages?: string[];
totalContributors?: number;
devseedContributors?: number;
orgContributors?: number;
externalContributors?: number;
communityRatio?: number;
totalCommits?: number;
orgCommits?: number;
license?: string | null;
archived?: boolean;
[key: string]: unknown;
Expand Down Expand Up @@ -279,8 +281,10 @@ export function renderCommunityMetrics(
x: number,
y: number,
SF: number,
orgNickname?: string,
): number {
const config = REPO_CARD_CONFIG;
const org = orgNickname ?? 'DevSeed';

if (!data.totalContributors || data.totalContributors === 0) {
return y;
Expand All @@ -297,24 +301,36 @@ export function renderCommunityMetrics(
setFont(context, config.valueFontSize * SF, 400, 'normal');

const total = data.totalContributors;
const devseed = data.devseedContributors || 0;
const orgContributors = data.orgContributors || 0;
const external = data.externalContributors || 0;

renderText(
context,
`${total} contributors (${devseed} DevSeed, ${external} community)`,
`${total} contributors (${orgContributors} ${org}, ${external} community)`,
x * SF,
y * SF,
1.25 * SF,
);

if (devseed === 1 && total > 0) {
if (data.totalCommits && data.totalCommits > 0) {
y += config.valueFontSize * config.lineHeight;
const orgPct = Math.round((data.orgCommits || 0) / data.totalCommits * 100);
renderText(
context,
`${data.totalCommits.toLocaleString()} total commits (${orgPct}% from ${org})`,
x * SF,
y * SF,
1.25 * SF,
);
}

if (orgContributors === 1 && total > 0) {
y += config.valueFontSize * config.lineHeight;
context.globalAlpha = config.warningOpacity;
setFont(context, config.valueFontSize * SF, 400, 'italic');
renderText(
context,
'⚠ Single DevSeed maintainer',
`⚠ Single ${org} maintainer`,
x * SF,
y * SF,
1.25 * SF,
Expand Down
48 changes: 40 additions & 8 deletions src/render/tooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ interface TooltipConfig {
COLOR_REPO: string;
COLOR_OWNER: string;
min: (...values: number[]) => number;
orgNickname?: string;
}

/**
Expand Down Expand Up @@ -81,7 +82,10 @@ function calculateRepoTooltipHeight(
if (data.totalContributors && data.totalContributors > 0) {
y += config.sectionSpacing;
y += config.valueFontSize * config.lineHeight + 4;
if (data.devseedContributors === 1 && data.totalContributors > 0) {
if (data.totalCommits && data.totalCommits > 0) {
y += config.valueFontSize * config.lineHeight;
}
if (data.orgContributors === 1 && data.totalContributors > 0) {
y += config.valueFontSize * config.lineHeight;
y += config.valueFontSize * config.lineHeight;
} else {
Expand Down Expand Up @@ -131,7 +135,9 @@ function calculateRepoTooltipWidth(
formatDate: (value: Date) => string,
formatDateExact: (value: Date) => string,
formatDigit: (value: number) => string,
orgNickname?: string,
): number {
const org = orgNickname ?? 'DevSeed';
const config = REPO_CARD_CONFIG;
let maxWidth = 0;

Expand Down Expand Up @@ -191,17 +197,26 @@ function calculateRepoTooltipWidth(
if (data.totalContributors && data.totalContributors > 0) {
setFont(context, config.valueFontSize * SF, 400, 'normal');
const total = data.totalContributors;
const devseed = data.devseedContributors || 0;
const orgContributors = data.orgContributors || 0;
const external = data.externalContributors || 0;
width =
context.measureText(
`${total} contributors (${devseed} DevSeed, ${external} community)`,
`${total} contributors (${orgContributors} ${org}, ${external} community)`,
).width * 1.25;
if (width > maxWidth) maxWidth = width;

if (devseed === 1 && total > 0) {
if (data.totalCommits && data.totalCommits > 0) {
const orgPct = Math.round((data.orgCommits || 0) / data.totalCommits * 100);
width =
context.measureText(
`${data.totalCommits.toLocaleString()} total commits (${orgPct}% from ${org})`,
).width * 1.25;
if (width > maxWidth) maxWidth = width;
}

if (orgContributors === 1 && total > 0) {
width =
context.measureText('⚠ Single DevSeed maintainer').width * 1.25;
context.measureText(`⚠ Single ${org} maintainer`).width * 1.25;
if (width > maxWidth) maxWidth = width;
}
}
Expand Down Expand Up @@ -282,7 +297,7 @@ export function drawTooltip(
formatDateExact: (value: Date) => string,
formatDigit: (value: number) => string,
): void {
const { SF, COLOR_BACKGROUND, COLOR_TEXT, COLOR_CONTRIBUTOR, COLOR_REPO, COLOR_OWNER } =
const { SF, COLOR_BACKGROUND, COLOR_TEXT, COLOR_CONTRIBUTOR, COLOR_REPO, COLOR_OWNER, orgNickname } =
config;

let line_height = 1.2;
Expand All @@ -298,7 +313,7 @@ export function drawTooltip(
let H: number, W: number;

if (d.type === 'contributor') {
H = 100;
H = 125;
W = 320;
} else if (d.type === 'owner') {
H = 155;
Expand All @@ -313,6 +328,7 @@ export function drawTooltip(
formatDate,
formatDateExact,
formatDigit,
orgNickname,
);
} else {
H = 116;
Expand Down Expand Up @@ -365,6 +381,12 @@ export function drawTooltip(
text = nodeData.contributor_name ?? nodeData.author_name;
let tW = context.measureText(text).width * 1.25;
if (tW + 40 * SF > W * SF) W = tW / SF + 40;
const repoCount = (nodeData.links_original as LinkData[] | undefined)?.length ?? 0;
const totalCommits = (nodeData.total_commits as number) || 0;
setFont(context, 14 * SF, 400, 'normal');
const statsText = `${repoCount} ${repoCount === 1 ? 'repo' : 'repos'} · ${totalCommits.toLocaleString()} commits`;
tW = context.measureText(statsText).width * 1.25;
if (tW + 40 * SF > W * SF) W = tW / SF + 40;
}

let H_OFFSET = d.y < 0 ? 20 : -H - 20;
Expand Down Expand Up @@ -415,6 +437,16 @@ export function drawTooltip(
setFont(context, font_size * SF, 700, 'normal');
text = nodeData.contributor_name ?? nodeData.author_name;
renderText(context, text, xLeft * SF, y * SF, 1.25 * SF);

y += 26;
const contribRepoCount = (nodeData.links_original as LinkData[] | undefined)?.length ?? 0;
const contribTotalCommits = (nodeData.total_commits as number) || 0;
font_size = 14;
context.globalAlpha = 0.6;
setFont(context, font_size * SF, 400, 'normal');
text = `${contribRepoCount} ${contribRepoCount === 1 ? 'repo' : 'repos'} · ${contribTotalCommits.toLocaleString()} commits`;
renderText(context, text, xLeft * SF, y * SF, 1.25 * SF);
context.globalAlpha = 1;
} else if (d.type === 'owner') {
font_size = 22;
setFont(context, font_size * SF, 700, 'normal');
Expand Down Expand Up @@ -509,7 +541,7 @@ export function drawTooltip(
if (nodeData.totalContributors && nodeData.totalContributors > 0) {
if (y > statsY) drawSectionDivider(context, y + 4, W, x, SF);
}
y = renderCommunityMetrics(context, repoData, xLeft, y, SF);
y = renderCommunityMetrics(context, repoData, xLeft, y, SF, orgNickname);

if (nodeData.license) {
if (y > statsY) drawSectionDivider(context, y + 4, W, x, SF);
Expand Down
5 changes: 4 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ export interface RepoData {
hasDiscussions: boolean;
archived: boolean;
totalContributors: number;
devseedContributors: number;
orgContributors: number;
externalContributors: number;
communityRatio: number;
totalCommits?: number;
orgCommits?: number;
createdAt: Date;
updatedAt: Date;
languages: string[];
Expand All @@ -46,6 +48,7 @@ export interface RepoData {
repo_has_discussions?: string | boolean;
repo_archived?: string | boolean;
repo_total_contributors?: string;
repo_total_commits?: string;
repo_devseed_contributors?: string;
repo_external_contributors?: string;
repo_community_ratio?: string;
Expand Down
Loading