Git Product home page Git Product logo

tech-radar's Introduction

Motivation

At Zalando, we maintain a public Tech Radar to help our engineering teams align on technology choices. It is based on the pioneering work by ThoughtWorks.

This repository contains the code to generate the visualization: radar.js (based on d3.js v4). Feel free to use and adapt it for your own purposes.

Usage

  1. include d3.js and radar.js:
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="http://zalando.github.io/tech-radar/release/radar-0.8.js"></script>
  1. insert an empty svg tag:
<svg id="radar"></svg>
  1. configure the radar visualization:
radar_visualization({
  svg_id: "radar",
  width: 1450,
  height: 1000,
  scale: 1.0,
  colors: {
    background: "#fff",
    grid: "#bbb",
    inactive: "#ddd"
  },
  // Some font families might lead to font size issues
  // Arial, Helvetica, or Source Sans Pro seem to work well though
  font_family: "Arial, Helvetica",
  title: "My Radar",
  quadrants: [
    { name: "Bottom Right" },
    { name: "Bottom Left" },
    { name: "Top Left" },
    { name: "Top Right" }
  ],
  rings: [
    { name: "INNER",  color: "#5ba300" },
    { name: "SECOND", color: "#009eb0" },
    { name: "THIRD",  color: "#c7ba00" },
    { name: "OUTER",  color: "#e09b96" }
  ],
  print_layout: true,
  links_in_new_tabs: true,
  entries: [
   {
      label: "Some Entry",
      quadrant: 3,          // 0,1,2,3 (counting clockwise, starting from bottom right)
      ring: 2,              // 0,1,2,3 (starting from inside)
      moved: -1             // -1 = moved out (triangle pointing down)
                            //  0 = not moved (circle)
                            //  1 = moved in  (triangle pointing up)
   },
    // ...
  ]
});

Entries are positioned automatically so that they don't overlap. The "scale" parameter can help in adjusting the size of the radar.

As a working example, you can check out docs/index.html — the source of our public Tech Radar.

Deployment

Tech Radar is a static page, so it can be deployed using any hosting provider of your choice offering static page hosting.

Local Development

  1. install dependencies with yarn (or npm):
yarn 
  1. start local dev server:
yarn start
  1. your default browser should automatically open and show the url
http://localhost:3000/

License

The MIT License (MIT)

Copyright (c) 2017-2024 Zalando SE

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

tech-radar's People

Contributors

andreasprang avatar antongolub avatar bocytko avatar cmreigrut avatar ggarber avatar hjacobs avatar jakubknejzlik avatar karras avatar ksaurabhsinha avatar lappleapple avatar marcoworms avatar maxim-tschumak avatar netpyoung avatar rejas avatar ronrademaker avatar sakirtemel avatar spore1 avatar tfrauenstein avatar tlossen avatar zeitlinger avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tech-radar's Issues

Documentation of print_layout

I found no documentation of the print_layout property.
It seems it renders the radar broken and does a few things which are not described / mentioned anywhere.

How to get data

I am doing now a trend radar. But I dont know how to get the data in order to visual the data on website as a radar.
could you tell me about that ? or where can I buy the new data of trend ?

I have seen google trend but they do not provide an api .

thanks

Does not work in IE11

Thanks for excellent code. But, the Radar does not render in IE11. Its completely blank. How to fix this?

Thanks,
Sachin

Radar with 5 Quadrants

Hello, I've modified the code for your radar to accommodate 5 quadrants and 3 rings. I've successfully drawn everything and adjusted the legend, but I'm struggling to position the blips correctly in the right quadrant. Could you possibly lend me a hand to understand where I'm going wrong?

`
function radar_visualization(config) {

var seed = 45;
function random() {
    var x = Math.sin(seed++) * 10000;
    return x - Math.floor(x);
}

function random_between(min, max) {
    return min + random() * (max - min);
}

function normal_between(min, max) {
    return min + (random() + random()) * 0.5 * (max - min);
}

// radial_min / radial_max are multiples of PI
const quadrants = [
    { radial_min: 0, radial_max: 0.4, factor_x: 1, factor_y: 1 },
    { radial_min: 0.4, radial_max: 0.8, factor_x: -1, factor_y: 1 },
    { radial_min: 0.8, radial_max: 1.2, factor_x: -1, factor_y: -1 },
    { radial_min: -1.2, radial_max: -0.8, factor_x: 1, factor_y: -1 },
    { radial_min: -0.8, radial_max: -0.4, factor_x: 1, factor_y: 1 }
];

const rings = [
    { radius: 130 },
    { radius: 220 },
    { radius: 310 },
];

const title_offset =
    { x: -675, y: -420 };

const footer_offset =
    { x: -675, y: 420 };

const legend_offset = [
    { x: 400, y: -200 },    // Quadrant 0
    { x: 400, y: 90 },   // Quadrant 1
    { x: -60, y: 400 },  // Quadrant 2
    { x: -550, y: 90 },   // Quadrant 3
    { x: -550, y: -200 }      // Quadrant 4
];

function polar(cartesian) {
    var x = cartesian.x;
    var y = cartesian.y;
    return {
        t: Math.atan2(y, x),
        r: Math.sqrt(x * x + y * y)
    }
}

function cartesian(polar) {
    return {
        x: polar.r * Math.cos(polar.t),
        y: polar.r * Math.sin(polar.t)
    }
}

function bounded_interval(value, min, max) {
    var low = Math.min(min, max);
    var high = Math.max(min, max);
    return Math.min(Math.max(value, low), high);
}

function bounded_ring(polar, r_min, r_max) {
    return {
        t: polar.t,
        r: bounded_interval(polar.r, r_min, r_max)
    }
}

function bounded_box(point, min, max) {
    return {
        x: bounded_interval(point.x, min.x, max.x),
        y: bounded_interval(point.y, min.y, max.y)
    }
}

function segment(quadrant, ring) {

    var polar_min = {
        t: quadrants[quadrant].radial_min * Math.PI,
        r: ring === 0 ? 30 : rings[ring - 1].radius
    };
    var polar_max = {
        t: quadrants[quadrant].radial_max * Math.PI,
        r: rings[ring].radius
    };
    var cartesian_min = {
        x: 15 * quadrants[quadrant].factor_x,
        y: 15 * quadrants[quadrant].factor_y
    };
    var cartesian_max = {
        x: rings[2].radius * quadrants[quadrant].factor_x,
        y: rings[2].radius * quadrants[quadrant].factor_y
    };
    return {
        clipx: function (d) {

            var c = bounded_box(d, cartesian_min, cartesian_max);
            var p = bounded_ring(polar(c), polar_min.r + 15, polar_max.r - 15);
            d.x = cartesian(p).x; // adjust data too!
            return d.x;
        },
        clipy: function (d) {

            var c = bounded_box(d, cartesian_min, cartesian_max);
            var p = bounded_ring(polar(c), polar_min.r + 15, polar_max.r - 15);
            d.y = cartesian(p).y; // adjust data too!
            return d.y;
        },
        random: function () {
            return cartesian({
                t: random_between(polar_min.t, polar_max.t),
                r: normal_between(polar_min.r, polar_max.r)
            });
        }
    }
}

// position each entry randomly in its segment
for (var i = 0; i < config.entries.length; i++) {

    var entry = config.entries[i];
    entry.segment = segment(entry.quadrant, entry.ring);
    var point = entry.segment.random();
    entry.x = point.x;
    entry.y = point.y;
    entry.color = entry.active || config.print_layout ?
        config.rings[entry.ring].color : config.colors.inactive;
}

// partition entries according to segments
var segmented = new Array(5);
for (var quadrant = 0; quadrant < 5; quadrant++) {
    segmented[quadrant] = new Array(3);
    for (var ring = 0; ring < 3; ring++) {
        segmented[quadrant][ring] = [];
    }
}
for (var i = 0; i < config.entries.length; i++) {
    var entry = config.entries[i];
    segmented[entry.quadrant][entry.ring].push(entry);
}

// assign unique sequential id to each entry
var id = 1;
for (var quadrant of [2, 3, 1, 0, 4]) {
    for (var ring = 0; ring < 3; ring++) {
        var entries = segmented[quadrant][ring];
        entries.sort(function (a, b) { return a.label.localeCompare(b.label); })
        for (var i = 0; i < entries.length; i++) {
            entries[i].id = "" + id++;
        }
    }
}

function translate(x, y) {
    return "translate(" + x + "," + y + ")";
}

function viewbox(quadrant) {
    return [
        Math.max(0, quadrants[quadrant].factor_x * 400) - 420,
        Math.max(0, quadrants[quadrant].factor_y * 400) - 420,
        440,
        440
    ].join(" ");
}

var svg = d3.select("svg#" + config.svg_id)
    .style("background-color", config.colors.background)
    .attr("width", config.width)
    .attr("height", config.height);

var radar = svg.append("g");
if ("zoomed_quadrant" in config) {
    svg.attr("viewBox", viewbox(config.zoomed_quadrant));
} else {
    radar.attr("transform", translate(config.width / 2, config.height / 2));
}

var grid = radar.append("g");

// draw rings
for (var i = rings.length - 1; i >= 0; i--) {
    const bgColor = i === 2 ? "#d5cfcf" : i === 1 ? "#989292" : "#5f5b5b"
    grid.append("circle")
        .attr("cx", 0)
        .attr("cy", 0)
        .attr("r", rings[i].radius)
        .style("fill", bgColor)
        .style("stroke", config.colors.grid)
        .style("stroke-width", 1);

    if (config.print_layout) {
        grid.append("text")
            .text(config.rings[i].name)
            .attr("y", -rings[i].radius + 62)
            .attr("text-anchor", "middle")
            .style("fill", config.rings[i].color)
            .style("opacity", 0.60)
            .style("font-family", "Arial, Helvetica")
            .style("font-size", "42px")
            .style("font-weight", "bold")
            .style("pointer-events", "none")
            .style("user-select", "none");
    }
}
// draw grid lines
const quadrantSuddivisionNumber = 360 / quadrants.length;
for (let q = 0; q < quadrants.length; q++) {

    const angle = quadrantSuddivisionNumber * q;
    const textAngle = angle + quadrantSuddivisionNumber / 2; 

    const xText = 0; 
    const yText = -310;
    grid.append("line")
        .attr("x1", 0).attr("y1", -310)
        .attr("x2", 0).attr("y2", 0)
        .style("stroke", config.colors.grid)
        .attr('transform', `rotate(${angle} 0 0)`)
        .style("stroke-width", 1);

   
}


// background color. Usage `.attr("filter", "url(#solid)")`
// SOURCE: https://stackoverflow.com/a/31013492/2609980
var defs = grid.append("defs");
var filter = defs.append("filter")
    .attr("x", 0)
    .attr("y", 0)
    .attr("width", 1)
    .attr("height", 1)
    .attr("id", "solid");
filter.append("feFlood")
    .attr("flood-color", "rgb(0, 0, 0, 0.8)");
filter.append("feComposite")
    .attr("in", "SourceGraphic");




function legend_transform(quadrant, ring, index = null) {
    var dx = ring < 2 ? 0 : 120;
    var dy = (index == null ? -16 : index * 12);
    if (ring % 2 === 1) {
        dy = dy + 36 + segmented[quadrant][ring - 1].length * 12;
    }
    return translate(
        legend_offset[quadrant].x + dx,
        legend_offset[quadrant].y + dy
    );
}

// draw title and legend (only in print layout)
if (config.print_layout) {

    // title
    radar.append("text")
        .attr("transform", translate(title_offset.x, title_offset.y))
        .text(config.title)
        .style("font-family", "Arial, Helvetica")
        .style("font-size", "30")
        .style("font-weight", "bold")

    // date
    radar
        .append("text")
        .attr("transform", translate(title_offset.x, title_offset.y + 20))
        .text(config.date || "")
        .style("font-family", "Arial, Helvetica")
        .style("font-size", "14")
        .style("fill", "#999")

    // footer
    /* radar.append("text")
        .attr("transform", translate(footer_offset.x, footer_offset.y))
        .text("▲ moved up     ▼ moved down")
        .attr("xml:space", "preserve")
        .style("font-family", "Arial, Helvetica")
        .style("font-size", "10px"); */

    // legend
    var legend = radar.append("g");
    for (var quadrant = 0; quadrant < 5; quadrant++) {

        legend.append("text")
            .attr("transform", translate(
                legend_offset[quadrant].x,
                legend_offset[quadrant].y - 45
            ))
            .text(config.quadrants[quadrant].name)
            .style("font-family", "Arial, Helvetica")
            .style("font-size", "18px")
            .style("font-weight", "bold");
        for (var ring = 0; ring < 3; ring++) {
            legend.append("text")
                .attr("transform", legend_transform(quadrant, ring))
                .text(config.rings[ring].name)
                .style("font-family", "Arial, Helvetica")
                .style("font-weight", "bold")
                .style("fill", config.rings[ring].color);
            legend.selectAll(".legend" + quadrant + ring)
                .data(segmented[quadrant][ring])
                .enter()
                .append("a")
                // Add an href if (and only if) there is a link
                .attr("href", function (d, i) {
                    return d.link ? d.link : null;
                })
                // Add a target if (and only if) there is a link and we want new tabs
                .attr("target", function (d, i) {
                    return (d.link && config.links_in_new_tabs) ? "_blank" : null;
                })
                .append("text")
                .attr("transform", function (d, i) { return legend_transform(quadrant, ring, i); })
                .attr("class", "legend" + quadrant + ring)
                .attr("id", function (d, i) { return "legendItem" + d.id; })
                .text(function (d, i) { return d.id + ". " + d.label; })
                .style("font-family", "Arial, Helvetica")
                .style("font-size", "11px")
                .on("mouseover", function (d) { showBubble(d); highlightLegendItem(d); })
                .on("mouseout", function (d) { hideBubble(d); unhighlightLegendItem(d); });
        }
    }
}

// layer for entries
var rink = radar.append("g")
    .attr("id", "rink");

// rollover bubble (on top of everything else)
var bubble = radar.append("g")
    .attr("id", "bubble")
    .attr("x", 0)
    .attr("y", 0)
    .style("opacity", 0)
    .style("pointer-events", "none")
    .style("user-select", "none");
bubble.append("rect")
    .attr("rx", 4)
    .attr("ry", 4)
    .style("fill", "#333");
bubble.append("text")
    .style("font-family", "sans-serif")
    .style("font-size", "10px")
    .style("fill", "#fff");
bubble.append("path")
    .attr("d", "M 0,0 10,0 5,8 z")
    .style("fill", "#333");

function showBubble(d) {
    if (d.active || config.print_layout) {
        var tooltip = d3.select("#bubble text")
            .text(d.label);
        var bbox = tooltip.node().getBBox();
        d3.select("#bubble")
            .attr("transform", translate(d.x - bbox.width / 2, d.y - 16))
            .style("opacity", 0.8);
        d3.select("#bubble rect")
            .attr("x", -5)
            .attr("y", -bbox.height)
            .attr("width", bbox.width + 10)
            .attr("height", bbox.height + 4);
        d3.select("#bubble path")
            .attr("transform", translate(bbox.width / 2 - 5, 3));
    }
}

function hideBubble(d) {
    var bubble = d3.select("#bubble")
        .attr("transform", translate(0, 0))
        .style("opacity", 0);
}

function highlightLegendItem(d) {
    var legendItem = document.getElementById("legendItem" + d.id);
    legendItem.setAttribute("filter", "url(#solid)");
    legendItem.setAttribute("fill", "white");
}

function unhighlightLegendItem(d) {
    var legendItem = document.getElementById("legendItem" + d.id);
    legendItem.removeAttribute("filter");
    legendItem.removeAttribute("fill");
}

// draw blips on radar
var blips = rink.selectAll(".blip")
    .data(config.entries)
    .enter()
    .append("g")
    .attr("class", "blip")
    .attr("transform", function (d, i) { return legend_transform(d.quadrant, d.ring, i); })
    .on("mouseover", function (d) { showBubble(d); highlightLegendItem(d); })
    .on("mouseout", function (d) { hideBubble(d); unhighlightLegendItem(d); });

// configure each blip
blips.each(function (d) {
    var blip = d3.select(this);

    // blip link
    if (d.active && d.hasOwnProperty("link") && d.link) {
        blip = blip.append("a")
            .attr("xlink:href", d.link);

        if (config.links_in_new_tabs) {
            blip.attr("target", "_blank");
        }
    }

    // blip shape
    if (d.moved > 0) {
        blip.append("path")
            .attr("d", "M -11,5 11,5 0,-13 z") // triangle pointing up
            .style("fill", d.color);
    } else if (d.moved < 0) {
        blip.append("path")
            .attr("d", "M -9,-9 9,-9 9,9 -9,9 Z") // quadrato
            .style("fill", d.color);
    } else {
        blip.append("circle")
            .attr("r", 9)
            .attr("fill", d.color);
    }

    // blip text
    if (d.active || config.print_layout) {
        var blip_text = config.print_layout ? d.id : d.label.match(/[a-z]/i);
        blip.append("text")
            .text(blip_text)
            .attr("y", 3)
            .attr("text-anchor", "middle")
            .style("fill", "#fff")
            .style("font-family", "Arial, Helvetica")
            .style("font-size", function (d) { return blip_text.length > 2 ? "8px" : "9px"; })
            .style("pointer-events", "none")
            .style("user-select", "none");
    }
});

// make sure that blips stay inside their segment
function ticked() {
    blips.attr("transform", function (d) {
        return translate(d.segment.clipx(d), d.segment.clipy(d));
    })
}

// distribute blips, while avoiding collisions
d3.forceSimulation()
    .nodes(config.entries)
    .velocityDecay(0.19) // magic number (found by experimentation)
    .force("collision", d3.forceCollide().radius(12).strength(0.85))
    .on("tick", ticked);

}
`

Remove Google analytics

docs/index.html contains Google Analytics. If people use that file to start their own radar, they may miss the necessity to remove that script. Therefore it might be a good idea to remove it entirely from that demo document.

blip circles overflowing when trying to create 8 quadrant technology radar

tried to split the quadrants to 8 with the following code
const quadrants = [
{ radial_min: 0, radial_max: 0.25, factor_x: 1, factor_y: 1},
{ radial_min: 0.25, radial_max: 0.5, factor_x: 1, factor_y: 1 },
{ radial_min: 0.5, radial_max: 0.75, factor_x: -1, factor_y: 1 },
{ radial_min: 0.75, radial_max: 1, factor_x: -1, factor_y: 1 },
{ radial_min: -1, radial_max: -0.75, factor_x: -1, factor_y: -1 },
{ radial_min: -0.75, radial_max: -0.5, factor_x: -1, factor_y: -1 },
{ radial_min: -0.5, radial_max: -0.25, factor_x: 1, factor_y: -1 },
{ radial_min: -0.25, radial_max: 0, factor_x: 1, factor_y: -1 }
];
8quadrantSingleBubble
but when i tried to place all blip circles in first quadrant they are overflowing to next quadrant

allbubblesInQuadrant1

Long text in quadrant to be wrapped

Hi Folks,

Can we wrap a long text within the Quadrant? Attached the screen shot which explains the issue. Thanks in Advance for the help!
Screenshot 2019-06-21 at 11 55 47 am

Thanks,
Venk

Mongo db on hold

I really want to understand what is the reason for putting mongodb on hold. It would be really helpful if we get some insights about what caused you to put the tools, and technologies into those categories like thoughtworks does.

I was planning to use mongodb in my project but seeing that I had to think again.

I found mongodb is still at number 5 here http://db-engines.com/en/ranking

Feature request: Adding a description for entries

It would be nice to have descriptions for entries. eg:

radar_visualization({
  ...
  entries: [
    { label: 'Foo', ring: RINGS.USE, quadrant: QUADRANTS.TOOLS, description: "very usefool tool" },
  ]
});

I have no preference how to show it. Perhaps a small popover on hover will be the best.

Thank you, great lib!

Magic number can kill radar.js

The bug is in radar.js: 117

var itemsByStage = _.groupBy(radar_data[i].items, function(item) { return Math.floor(item.pc.r / 100) });

With the magic number 100 itemsByStage can be something like this:

{
0 : [...],
2 : [...],
3 : [...]
}

So the JS throws an exception on

offsetIndex = offsetIndex + itemsByStage[stageIndex-1].length + 1;

In my case it worked with the "magic number" 150.

How do i

Pardon the very basic question.

I have created a local version of your Tech Radar, but can't figure out how to replace your data with mine. I saw instructions on ThoughtWorks' site @ How To BYOR but couldn't determine how perform the equivalent actions on your Tech Radar. Please advise. Thanks.

NoMethodError

Hi, I've tried to create a tech radar. The call of transfrom.rb fails with the attached stack trace. My ruby version is 2.1.5p273 (2014-11-13 revision 48405) [x64-mingw32].

D:\Projekte\tech-radar>ruby transform.rb
transform.rb:49:in next_angle': undefined method+' for nil:NilClass (NoMethodError)
from transform.rb:82:in angle' from transform.rb:90:inas_json'
from transform.rb:114:in map' from transform.rb:114:inblock in render'
from transform.rb:9:in block in remap' from transform.rb:9:ineach'
from transform.rb:9:in remap' from transform.rb:112:inrender'
from transform.rb:142:in `

'

feature - JavaScript | Typescript frameworks and libraries

Hi.

I saw the language section but no part for frameworks or libraries.
I am interested to know what these examples are on your radar. I am sure that it will help many developers to see what technologies are ADOPT in Zalando and what technologies you consider HOLD.

For example, having data about using react-query and redux can be valuable.

Best, Mohammad

Dynamically zoom in Quadrant on click of button

Actually my plan is to give 4 buttons namely Qudarnt-1,Qudarnt-2, Qudarnt-3, Qudarnt-4 on click of button i want zoom in respective quadrant. FYI On page load it will be show all quadrants.
On Click of button i am trying to write below function

OnclickBtn()
{
radar.zoomed_quadrant= 0; //in case of 0 quadrant
radar_visualization(radar)
}

But chart is getting scattered.

Align Quadrants

Can we align the Quadrants order differently, For example - Having all the Quadrants list at the top followed by the radar

blips on click

Hi,
i want to edit some code in this radar , how to change the link from a link to web page to open a modal when i click on the radar blips
thank you

Rational + general Go of tech radar

Hello there and thanks for sharing your tech radar,

I came upon the tech radar prominently displayed at GOTO Berlin. When I was there I sadly had no engineer to speak to about it.
I have a couple of questions that play into each other.

  • Is there a publicly accessible rationale? I was promised as much at the stand. Some HOLD choices (not getting into the others) are surprising at the least and I'd like to see how that came to be, but compendium and assessment are internal so it's hard to know why.
  • What's the goal and intent of this tech radar? The person at the stand was adamant it is only about internal experience and circumstances at Zalando and it can't be taken for the industry as a whole. I don't find that to be clearly described. The first paragraph ("purpose") goes in that direction a bit and imo it's still somewhat unclear. I further find it to be a bit problematic as it looks so much like the ThoughtWorks Tech Radar which is usually seen for the whole industry - that is just confusing. Especially with a missing rationale/reasoning, which ThoughtWorks provides, it makes it seem as if no one should technologies like Erlang, Elixir, MySQL, Riak, Neo4J, Ruby, C/C++, MemcacheD and many others (Funnily enough this repo uses Ruby while monkey patching Hash :|).

I don't know if that's your general view of technologies or you just don't use them as you have somewhat equivalent technologies (Python, Go, Scala, Postgres, Cassandra, Redis...) in use instead. Clarifying this and/or open sourcing the reasoning would be much appreciated from my side - and I guess a couple of others too.

Tobi

npm run build

How to run "npm run build" command? I get some errors when running this script. Is there another way to do it?

How you collect the data?

Hi Zalando Team! :)
I'm investigating a way to know the tech interests in our company and create something like this.

My main question here is:
How do you collect the data from your engineering team? Do you have a specific procedure to take the interest of each individual in the team? Making questionnaires?

Thanks for any help that you can provide me! I like you tech radar!

How are overlaps avoided?

first of all thank you for open sourcing your code used for your tech radar.

this is not a issue, but a question on tech radar.js :

how are overlaps between data points on the tech radar avoided?

the custom random function ensures distinct values, however I can't find any code taking the radii of the points into account, to avoid a randomized (x,y) point being within the circle of another point, so that the cartesian diff (Math.sqrt(Math.pow(pointA.x - pointB.x, 2) + Math.pow(pointA.y - pointB.y, 2),)) is always greater 2 * r (r being the dot radius).

thank you for any pointers

Show one qudrant at a one place on dropdown change

Can we show one qudrant information on page based on dropdown selection.
I have quadrant names in the dropdown list.on selecting qudrant name respective quadrant information should be displayed without changing blip postions.
Please let me know if this is possible.
Screenshot

Screenshot attached. want all quadrant info at same place

Structure of radar.js makes it hard to include in projects

I am interested in using the JS code here to render our own tech radar, but the structure of the main file (and the way you include) makes it very difficult to include it in a React project. Would you be open to some light restructuring to support inclusion? I should be able to make it backwards compatible so that your method of inclusion continues to work

Suggested usage script differs from actual used script

The documentation suggests to include http://zalando.github.io/tech-radar/release/radar-0.5.js for the script.

But https://opensource.zalando.com/tech-radar/ seems to use a different version (which supports hrefs for the technologies).

With a short glance I couldn't understand which one is the newer one or how to obtain the live one for my own usage.
So please update the reference or shared script so I don't need to fork all of this repo.

Embedding the guidelines of contribution to the radar items

Hi!

Following up this issue: #97 (comment) @bocytko

I'd like to suggest this repository to have a place where the guidelines in blog post are written inside the repository. So, this repo can be more than a visualization library and become some sort of a lightweight framework for the organizations to adopt. ( for example MADR has great guidelines how to quickly adapt to the ADRs https://adr.github.io/madr/#applying-madr-to-your-project )

I suggest following changes and would start working on them if it's initially agreed.

1- Move the index.html and stuff out from docs and have them under starter-kit or example. This starter-kit is something that any organization can easily clone and aplly immediately to their organization.
2- Have github templates that are written in the blog post will be included somehow under it.
3- Have the each entry in entries saved as a asciidoc and have a compiler that goes through all the asciidocs and read the metadata from them ( https://docs.asciidoctor.org/asciidoc/latest/document/metadata/ )
4- Have a linter for these asciidocs, so they'd all look like the way it's in the blog post (includes pros, cons, when to use etc)
5- Have extensive guideline docs for how to contribute by having some diagrams, writing the roles, procedures etc
6- Have a script to have a monthly change report

So, what do you think? These are some initial thoughts that can enable and accelerate many organizations, later, the further imporvements can be done.

Waiting for your thoughts to start on that

The package has been removed from npm

When I try to install "zalando-tech-radar": "^2022.5.0", npm only installs a placeholder with the following message:

Security holding package

This package contained malicious code and was removed from the registry by the npm security team. A placeholder was published to ensure users are not affected in the future.

Please refer to www.npmjs.com/advisories?search=zalando-tech-radar for more information.

Unfortunately there is no information under this link.

So is there a security issue with tech-radar? The code is quite simple and easy to review.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.