aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js/apps/projects/visualizations/SimpleBubbleChart.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'server/sonar-web/src/main/js/apps/projects/visualizations/SimpleBubbleChart.tsx')
-rw-r--r--server/sonar-web/src/main/js/apps/projects/visualizations/SimpleBubbleChart.tsx135
1 files changed, 135 insertions, 0 deletions
diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/SimpleBubbleChart.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/SimpleBubbleChart.tsx
new file mode 100644
index 00000000000..0b3a866353e
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/projects/visualizations/SimpleBubbleChart.tsx
@@ -0,0 +1,135 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import ColorRatingsLegend from '../../../components/charts/ColorRatingsLegend';
+import BubbleChart from '../../../components/charts/BubbleChart';
+import { formatMeasure } from '../../../helpers/measures';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
+import { RATING_COLORS } from '../../../helpers/constants';
+import { getProjectUrl } from '../../../helpers/urls';
+import { Project } from '../types';
+
+export interface Metric {
+ key: string;
+ type: string;
+}
+
+interface Props {
+ colorMetric?: string;
+ displayOrganizations: boolean;
+ projects: Project[];
+ sizeMetric: Metric;
+ xMetric: Metric;
+ yDomain?: [number, number];
+ yMetric: Metric;
+}
+
+export default class SimpleBubbleChart extends React.PureComponent<Props> {
+ getMetricTooltip(metric: Metric, value?: number) {
+ const name = translate('metric', metric.key, 'name');
+ const formattedValue = value != null ? formatMeasure(value, metric.type) : '–';
+ return `<div>${name}: ${formattedValue}</div>`;
+ }
+
+ getTooltip(project: Project, x?: number, y?: number, size?: number, color?: number) {
+ const fullProjectName =
+ this.props.displayOrganizations && project.organization
+ ? `${project.organization.name} / <strong>${project.name}</strong>`
+ : `<strong>${project.name}</strong>`;
+
+ const inner = [
+ `<div class="little-spacer-bottom">${fullProjectName}</div>`,
+ this.getMetricTooltip(this.props.xMetric, x),
+ this.getMetricTooltip(this.props.yMetric, y),
+ this.getMetricTooltip(this.props.sizeMetric, size)
+ ];
+
+ if (color) {
+ // if `color` is defined then `this.props.colorMetric` is defined too
+ this.getMetricTooltip({ key: this.props.colorMetric!, type: 'RATING' }, color);
+ }
+
+ return `<div class="text-left">${inner.join('')}</div>`;
+ }
+
+ render() {
+ const { xMetric, yMetric, sizeMetric, colorMetric } = this.props;
+
+ const items = this.props.projects
+ .filter(project => colorMetric == null || project.measures[colorMetric] !== null)
+ .map(project => {
+ const x =
+ project.measures[xMetric.key] != null ? Number(project.measures[xMetric.key]) : undefined;
+ const y =
+ project.measures[yMetric.key] != null ? Number(project.measures[yMetric.key]) : undefined;
+ const size =
+ project.measures[sizeMetric.key] != null
+ ? Number(project.measures[sizeMetric.key])
+ : undefined;
+ const color = colorMetric ? Number(project.measures[colorMetric]) : undefined;
+ return {
+ x: x || 0,
+ y: y || 0,
+ size: size || 0,
+ color: color ? RATING_COLORS[color - 1] : undefined,
+ key: project.key,
+ tooltip: this.getTooltip(project, x, y, size, color),
+ link: getProjectUrl(project.key)
+ };
+ });
+
+ const formatXTick = (tick: number) => formatMeasure(tick, xMetric.type);
+ const formatYTick = (tick: number) => formatMeasure(tick, yMetric.type);
+
+ return (
+ <div>
+ <BubbleChart
+ formatXTick={formatXTick}
+ formatYTick={formatYTick}
+ height={600}
+ items={items}
+ padding={[colorMetric ? 80 : 40, 20, 60, 100]}
+ yDomain={this.props.yDomain}
+ />
+ <div className="measure-details-bubble-chart-axis x">
+ {translate('metric', xMetric.key, 'name')}
+ </div>
+ <div className="measure-details-bubble-chart-axis y">
+ {translate('metric', yMetric.key, 'name')}
+ </div>
+ <div className="measure-details-bubble-chart-axis size">
+ {colorMetric != null && (
+ <span className="spacer-right">
+ {translateWithParameters(
+ 'component_measures.legend.color_x',
+ translate('metric', colorMetric, 'name')
+ )}
+ </span>
+ )}
+ {translateWithParameters(
+ 'component_measures.legend.size_x',
+ translate('metric', sizeMetric.key, 'name')
+ )}
+ {colorMetric != null && <ColorRatingsLegend className="big-spacer-top" />}
+ </div>
+ </div>
+ );
+ }
+}