diff --git a/data/config.json b/data/config.json
index 0a09df9..591c043 100644
--- a/data/config.json
+++ b/data/config.json
@@ -36,22 +36,22 @@
"description": "We can clearly recommend this technology. We have used it for longer period of time in many teams and it has proven to be stable and useful.",
"color": "#5cb449",
"radius": 0.5,
- "strokeWidth": 6
+ "strokeWidth": 5
},
{
"id": "trial",
"title": "Trial",
"description": "We have used it with success and recommend to have a closer look at the technology in this ring. The goal of items here is to look at them more closely, with the goal to bring them to the adopt level.",
"color": "#faa03d",
- "radius": 0.7,
- "strokeWidth": 4
+ "radius": 0.69,
+ "strokeWidth": 3
},
{
"id": "assess",
"title": "Assess",
"description": "We have tried it out and we find it promising. We recommend having a look at these items when you face a specific need for the technology in your project.",
"color": "#029df7",
- "radius": 0.88,
+ "radius": 0.85,
"strokeWidth": 2
},
{
@@ -60,7 +60,7 @@
"description": "This category is a bit special. Unlike the others, we recommend to stop doing or using something. That does not mean that they are bad and it often might be ok to use them in existing projects. But we move things here if we think we shouldn't do them anymore - because we see better options or alternatives now.",
"color": "#688190",
"radius": 1,
- "strokeWidth": 1
+ "strokeWidth": 0.75
}
],
"flags": {
@@ -74,5 +74,9 @@
"title": "Changed",
"titleShort": "C"
}
+ },
+ "chart": {
+ "size": 800,
+ "blipSize": 12
}
}
diff --git a/next.config.mjs b/next.config.mjs
index aa3388e..9aee55f 100644
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -1,7 +1,8 @@
-/** @type {import('next').NextConfig} */
+/** @type {import("next").NextConfig} */
const nextConfig = {
output: "export",
// basePath: '/techradar',
+ trailingSlash: true,
reactStrictMode: true,
};
diff --git a/scripts/buildData.ts b/scripts/buildData.ts
index c930de5..636e8b5 100644
--- a/scripts/buildData.ts
+++ b/scripts/buildData.ts
@@ -144,6 +144,8 @@ function postProcessItems(items: Item[]): {
const processedItems = items.map((item) => ({
...item,
+ // @todo: Maybe we should use a better random number generator to avoid overlapping of blips
+ random: [Math.sqrt(Math.random()), Math.random()] as [number, number],
flag: getFlag(item, latestRelease),
// only keep revision which ring or body is different
revisions: item.revisions?.filter((revision, index, revisions) => {
diff --git a/src/components/Radar/Blip.tsx b/src/components/Radar/Blip.tsx
new file mode 100644
index 0000000..9cb99cf
--- /dev/null
+++ b/src/components/Radar/Blip.tsx
@@ -0,0 +1,58 @@
+import React from "react";
+
+import { getChartConfig } from "@/lib/data";
+import { Flag } from "@/lib/types";
+
+const { blipSize } = getChartConfig();
+const halfBlipSize = blipSize / 2;
+
+interface BlipProps {
+ color: string;
+ x: number;
+ y: number;
+}
+
+export function Blip({ flag, color, x, y }: BlipProps & { flag: Flag }) {
+ switch (flag) {
+ case Flag.New:
+ return ;
+ case Flag.Changed:
+ return ;
+ default:
+ return ;
+ }
+}
+
+function BlipNew({ x, y, color }: BlipProps) {
+ x = Math.round(x - halfBlipSize);
+ y = Math.round(y - halfBlipSize);
+ return (
+
+ );
+}
+
+function BlipChanged({ x, y, color }: BlipProps) {
+ x = Math.round(x - halfBlipSize);
+ y = Math.round(y - halfBlipSize);
+ return (
+
+ );
+}
+
+function BlipDefault({ x, y, color }: BlipProps) {
+ return ;
+}
diff --git a/src/components/Radar/Radar.module.css b/src/components/Radar/Radar.module.css
index 40e3695..20e5bae 100644
--- a/src/components/Radar/Radar.module.css
+++ b/src/components/Radar/Radar.module.css
@@ -1,5 +1,6 @@
.radar {
- padding: 50px;
+ padding: 0 15px;
+ margin-bottom: 60px;
position: relative;
}
diff --git a/src/components/Radar/Radar.tsx b/src/components/Radar/Radar.tsx
index 1056907..f2ed4b0 100644
--- a/src/components/Radar/Radar.tsx
+++ b/src/components/Radar/Radar.tsx
@@ -1,16 +1,24 @@
+import Link from "next/link";
import React, { FC } from "react";
import styles from "./Radar.module.css";
-import { Quadrant, Ring } from "@/lib/types";
+import { Blip } from "@/components/Radar/Blip";
+import { Item, Quadrant, Ring } from "@/lib/types";
export interface RadarProps {
size?: number;
quadrants: Quadrant[];
rings: Ring[];
+ items: Item[];
}
-export const Radar: FC = ({ size = 800, quadrants, rings }) => {
+export const Radar: FC = ({
+ size = 800,
+ quadrants = [],
+ rings = [],
+ items = [],
+}) => {
const viewBoxSize = size;
const center = size / 2;
const startAngles = [270, 0, 180, 90]; // Corresponding to positions 1, 2, 3, and 4 respectively
@@ -22,8 +30,8 @@ export const Radar: FC = ({ size = 800, quadrants, rings }) => {
): { x: number; y: number } => {
const angleInRadians = ((angleInDegrees - 90) * Math.PI) / 180.0;
return {
- x: center + radius * Math.cos(angleInRadians),
- y: center + radius * Math.sin(angleInRadians),
+ x: Math.round(center + radius * Math.cos(angleInRadians)),
+ y: Math.round(center + radius * Math.sin(angleInRadians)),
};
};
@@ -71,6 +79,41 @@ export const Radar: FC = ({ size = 800, quadrants, rings }) => {
);
};
+ // Function to place items inside their rings and quadrants
+ const renderItem = (item: Item) => {
+ const ring = rings.find((r) => r.id === item.ring);
+ const quadrant = quadrants.find((q) => q.id === item.quadrant);
+ if (!ring || !quadrant) return null; // If no ring or quadrant, don't render item
+
+ const padding = 15; // Padding in pixels
+ const paddingAngle = 10; // Padding in degrees
+
+ // Random factors to determine position within the ring
+ const [randomRadius, randomAngleFactor] = item.random || [
+ Math.sqrt(Math.random()),
+ Math.random(),
+ ];
+ const innerRadius =
+ (rings[rings.indexOf(ring) - 1]?.radius || 0) + padding / center; // Add inner padding
+ const outerRadius = (ring.radius || 1) - padding / center; // Subtract outer padding
+ const ringWidth = (outerRadius - innerRadius) * center; // Width of the ring in the SVG
+
+ // Calculate the position within the ring
+ const itemRadius = innerRadius * center + randomRadius * ringWidth;
+ // Calculate the angle with padding offset, avoiding the exact edges
+ const startAngle = startAngles[quadrant.position - 1] + paddingAngle;
+ const endAngle = startAngle + 90 - 2 * paddingAngle; // Subtract padding from both sides
+ const itemAngle = startAngle + (endAngle - startAngle) * randomAngleFactor;
+
+ // Convert polar coordinates to cartesian for the item's position
+ const { x, y } = polarToCartesian(itemRadius, itemAngle);
+ return (
+
+
+
+ );
+ };
+
return (
);
diff --git a/src/lib/data.ts b/src/lib/data.ts
index 637cb5b..33950dc 100644
--- a/src/lib/data.ts
+++ b/src/lib/data.ts
@@ -12,6 +12,10 @@ export function getAppName() {
return messages.radarName;
}
+export function getChartConfig() {
+ return config.chart;
+}
+
export function getFlag(flag: Exclude) {
return config.flags[flag];
}
diff --git a/src/lib/types.ts b/src/lib/types.ts
index fd4b5c8..a008a9e 100644
--- a/src/lib/types.ts
+++ b/src/lib/types.ts
@@ -23,6 +23,7 @@ export interface Item {
flag: Flag;
tags: string[];
revisions?: Revision[];
+ random?: [radius: number, angle: number];
}
export interface Ring {
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index 07f959b..6ce6ac6 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -21,7 +21,7 @@ const Home: CustomPage = () => {
{appName}{" "}
Version #{version}
-
+
>
);