mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-07-18 14:45:25 +00:00
feat: set topology legend
This commit is contained in:
parent
83805b614f
commit
6bccb79eaf
@ -84,6 +84,8 @@ const msg = {
|
|||||||
endpointDashboard: "Dashboard name related with endpoints",
|
endpointDashboard: "Dashboard name related with endpoints",
|
||||||
callSettings: "Call settings",
|
callSettings: "Call settings",
|
||||||
nodeSettings: "Node Settings",
|
nodeSettings: "Node Settings",
|
||||||
|
conditions: "Conditions",
|
||||||
|
legendSettings: "Legend Settings",
|
||||||
hourTip: "Select Hour",
|
hourTip: "Select Hour",
|
||||||
minuteTip: "Select Minute",
|
minuteTip: "Select Minute",
|
||||||
secondTip: "Select Second",
|
secondTip: "Select Second",
|
||||||
|
@ -83,6 +83,8 @@ const msg = {
|
|||||||
endpointDashboard: "拓节点端点的实例的仪表板名称",
|
endpointDashboard: "拓节点端点的实例的仪表板名称",
|
||||||
callSettings: "拓扑线设置",
|
callSettings: "拓扑线设置",
|
||||||
nodeSettings: "拓扑点设置",
|
nodeSettings: "拓扑点设置",
|
||||||
|
conditions: "条件",
|
||||||
|
legendSettings: "图例设置",
|
||||||
hourTip: "选择小时",
|
hourTip: "选择小时",
|
||||||
minuteTip: "选择分钟",
|
minuteTip: "选择分钟",
|
||||||
secondTip: "选择秒数",
|
secondTip: "选择秒数",
|
||||||
|
@ -344,6 +344,29 @@ export const topologyStore = defineStore({
|
|||||||
this.setNodeMetrics(res.data.data);
|
this.setNodeMetrics(res.data.data);
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
|
async getLegendMetrics(param: {
|
||||||
|
queryStr: string;
|
||||||
|
conditions: { [key: string]: unknown };
|
||||||
|
}) {
|
||||||
|
const res: AxiosResponse = await query(param);
|
||||||
|
|
||||||
|
if (res.data.errors) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
const data = res.data.data;
|
||||||
|
const metrics = Object.keys(data);
|
||||||
|
this.nodes = this.nodes.map((d: Node | any) => {
|
||||||
|
for (const m of metrics) {
|
||||||
|
for (const val of data[m].values) {
|
||||||
|
if (d.id === val.id) {
|
||||||
|
d[m] = val.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
});
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
async getCallServerMetrics(param: {
|
async getCallServerMetrics(param: {
|
||||||
queryStr: string;
|
queryStr: string;
|
||||||
conditions: { [key: string]: unknown };
|
conditions: { [key: string]: unknown };
|
||||||
|
@ -177,3 +177,16 @@ export const ScopeType = [
|
|||||||
{ value: "Endpoint", label: "Endpoint", key: 3 },
|
{ value: "Endpoint", label: "Endpoint", key: 3 },
|
||||||
{ value: "ServiceInstance", label: "Service Instance", key: 3 },
|
{ value: "ServiceInstance", label: "Service Instance", key: 3 },
|
||||||
];
|
];
|
||||||
|
export const LegendConditions = [
|
||||||
|
{ label: "&&", value: "and" },
|
||||||
|
{ label: "||", value: "or" },
|
||||||
|
];
|
||||||
|
export const MetricConditions = [
|
||||||
|
{ label: ">", value: ">" },
|
||||||
|
{ label: "<", value: "<" },
|
||||||
|
];
|
||||||
|
export enum LegendOpt {
|
||||||
|
NAME = "name",
|
||||||
|
VALUE = "value",
|
||||||
|
CONDITION = "condition",
|
||||||
|
}
|
||||||
|
@ -20,18 +20,18 @@ limitations under the License. -->
|
|||||||
:style="`height: ${height}px`"
|
:style="`height: ${height}px`"
|
||||||
>
|
>
|
||||||
<div class="setting" v-show="showSetting">
|
<div class="setting" v-show="showSetting">
|
||||||
<Settings @update="updateSettings" />
|
<Settings @update="updateSettings" @updateNodes="freshNodes" />
|
||||||
</div>
|
</div>
|
||||||
<div class="tool">
|
<div class="tool">
|
||||||
<span class="switch-icon ml-5" title="Settings">
|
<span class="switch-icon ml-5" title="Settings" @click="setConfig">
|
||||||
<Icon @click="setConfig" size="middle" iconName="settings" />
|
<Icon size="middle" iconName="settings" />
|
||||||
</span>
|
</span>
|
||||||
<span class="switch-icon ml-5" title="Back to overview topology">
|
<span
|
||||||
<Icon
|
class="switch-icon ml-5"
|
||||||
@click="backToTopology"
|
title="Back to overview topology"
|
||||||
size="middle"
|
@click="backToTopology"
|
||||||
iconName="keyboard_backspace"
|
>
|
||||||
/>
|
<Icon size="middle" iconName="keyboard_backspace" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -239,7 +239,10 @@ function update() {
|
|||||||
topologyStore.nodeMetrics[m].values.filter(
|
topologyStore.nodeMetrics[m].values.filter(
|
||||||
(val: { id: string; value: unknown }) => val.id === data.id
|
(val: { id: string; value: unknown }) => val.id === data.id
|
||||||
)[0] || {};
|
)[0] || {};
|
||||||
return ` <div class="mb-5"><span class="grey">${m}: </span>${metric.value}</div>`;
|
const val = m.includes("_sla")
|
||||||
|
? metric.value / 100
|
||||||
|
: metric.value.value;
|
||||||
|
return ` <div class="mb-5"><span class="grey">${m}: </span>${val}</div>`;
|
||||||
});
|
});
|
||||||
return [
|
return [
|
||||||
` <div class="mb-5"><span class="grey">name: </span>${data.name}</div>`,
|
` <div class="mb-5"><span class="grey">name: </span>${data.name}</div>`,
|
||||||
@ -247,7 +250,8 @@ function update() {
|
|||||||
].join(" ");
|
].join(" ");
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
tip.value
|
tip.value,
|
||||||
|
settings.value.legend
|
||||||
).merge(node.value);
|
).merge(node.value);
|
||||||
// line element
|
// line element
|
||||||
link.value = link.value.data(topologyStore.calls, (d: Call) => d.id);
|
link.value = link.value.data(topologyStore.calls, (d: Call) => d.id);
|
||||||
@ -270,7 +274,8 @@ function update() {
|
|||||||
(val: { id: string; value: unknown }) => val.id === data.id
|
(val: { id: string; value: unknown }) => val.id === data.id
|
||||||
)[0];
|
)[0];
|
||||||
if (metric) {
|
if (metric) {
|
||||||
return ` <div class="mb-5"><span class="grey">${m}: </span>${metric.value}</div>`;
|
const val = m.includes("_sla") ? metric.value / 100 : metric.value;
|
||||||
|
return ` <div class="mb-5"><span class="grey">${m}: </span>${val}</div>`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const htmlClient = linkClientMetrics.map((m) => {
|
const htmlClient = linkClientMetrics.map((m) => {
|
||||||
@ -278,7 +283,8 @@ function update() {
|
|||||||
(val: { id: string; value: unknown }) => val.id === data.id
|
(val: { id: string; value: unknown }) => val.id === data.id
|
||||||
)[0];
|
)[0];
|
||||||
if (metric) {
|
if (metric) {
|
||||||
return ` <div class="mb-5"><span class="grey">${m}: </span>${metric.value}</div>`;
|
const val = m.includes("_sla") ? metric.value / 100 : metric.value;
|
||||||
|
return ` <div class="mb-5"><span class="grey">${m}: </span>${val}</div>`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const html = [
|
const html = [
|
||||||
@ -433,6 +439,11 @@ function updateSettings(config: any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async function freshNodes() {
|
||||||
|
svg.value.selectAll(".topo-svg-graph").remove();
|
||||||
|
await init();
|
||||||
|
update();
|
||||||
|
}
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
window.removeEventListener("resize", resize);
|
window.removeEventListener("resize", resize);
|
||||||
});
|
});
|
||||||
@ -445,7 +456,7 @@ onBeforeUnmount(() => {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 70px;
|
top: 70px;
|
||||||
right: 0;
|
right: 0;
|
||||||
width: 360px;
|
width: 380px;
|
||||||
height: 700px;
|
height: 700px;
|
||||||
background-color: #2b3037;
|
background-color: #2b3037;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
@ -24,15 +24,15 @@ limitations under the License. -->
|
|||||||
@change="changeDepth"
|
@change="changeDepth"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span class="switch-icon ml-5" title="Settings">
|
<span class="switch-icon ml-5" title="Settings" @click="setConfig">
|
||||||
<Icon @click="setConfig" size="middle" iconName="settings" />
|
<Icon size="middle" iconName="settings" />
|
||||||
</span>
|
</span>
|
||||||
<span class="switch-icon ml-5" title="Back to overview topology">
|
<span
|
||||||
<Icon
|
class="switch-icon ml-5"
|
||||||
@click="backToTopology"
|
title="Back to overview topology"
|
||||||
size="middle"
|
@click="backToTopology"
|
||||||
iconName="keyboard_backspace"
|
>
|
||||||
/>
|
<Icon size="middle" iconName="keyboard_backspace" />
|
||||||
</span>
|
</span>
|
||||||
<div class="settings" v-show="showSettings">
|
<div class="settings" v-show="showSettings">
|
||||||
<Settings @update="updateConfig" />
|
<Settings @update="updateConfig" />
|
||||||
|
@ -58,30 +58,30 @@ limitations under the License. -->
|
|||||||
size="small"
|
size="small"
|
||||||
placeholder="Select a scope"
|
placeholder="Select a scope"
|
||||||
@change="changeScope(index, $event)"
|
@change="changeScope(index, $event)"
|
||||||
class="item"
|
class="item mr-5"
|
||||||
/>
|
/>
|
||||||
<el-input
|
<el-input
|
||||||
v-model="item.dashboard"
|
v-model="item.dashboard"
|
||||||
placeholder="Please input a dashboard name for nodes"
|
placeholder="Please input a dashboard name for nodes"
|
||||||
@change="updateNodeDashboards(index, $event)"
|
@change="updateNodeDashboards(index, $event)"
|
||||||
size="small"
|
size="small"
|
||||||
class="item"
|
class="item mr-5"
|
||||||
/>
|
/>
|
||||||
<span>
|
<span>
|
||||||
<Icon
|
<Icon
|
||||||
class="cp mr-5"
|
class="cp mr-5"
|
||||||
v-show="index === items.length - 1 && items.length < 5"
|
|
||||||
iconName="add_circle_outlinecontrol_point"
|
|
||||||
size="middle"
|
|
||||||
@click="addItem"
|
|
||||||
/>
|
|
||||||
<Icon
|
|
||||||
class="cp"
|
|
||||||
v-show="items.length > 1"
|
v-show="items.length > 1"
|
||||||
iconName="remove_circle_outline"
|
iconName="remove_circle_outline"
|
||||||
size="middle"
|
size="middle"
|
||||||
@click="deleteItem(index)"
|
@click="deleteItem(index)"
|
||||||
/>
|
/>
|
||||||
|
<Icon
|
||||||
|
class="cp"
|
||||||
|
v-show="index === items.length - 1 && items.length < 5"
|
||||||
|
iconName="add_circle_outlinecontrol_point"
|
||||||
|
size="middle"
|
||||||
|
@click="addItem"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="label">{{ t("nodeMetrics") }}</div>
|
<div class="label">{{ t("nodeMetrics") }}</div>
|
||||||
@ -95,21 +95,94 @@ limitations under the License. -->
|
|||||||
@change="changeNodeMetrics"
|
@change="changeNodeMetrics"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="legend-settings">
|
||||||
|
<h5 class="title">{{ t("legendSettings") }}</h5>
|
||||||
|
<div class="label">{{ t("metrics") }}</div>
|
||||||
|
<Selector
|
||||||
|
class="item mr-5"
|
||||||
|
:value="legend.metric.name"
|
||||||
|
:options="states.nodeMetricList"
|
||||||
|
size="small"
|
||||||
|
placeholder="Select a metric"
|
||||||
|
@change="changeLegend(LegendOpt.NAME, $event)"
|
||||||
|
/>
|
||||||
|
<Selector
|
||||||
|
class="input-small mr-5"
|
||||||
|
:value="legend.metric.condition"
|
||||||
|
:options="MetricConditions"
|
||||||
|
size="small"
|
||||||
|
placeholder="Select a condition"
|
||||||
|
@change="changeLegend(LegendOpt.CONDITION, $event)"
|
||||||
|
/>
|
||||||
|
<el-input
|
||||||
|
v-model="legend.metric.value"
|
||||||
|
placeholder="Please input a value"
|
||||||
|
@change="changeLegend(LegendOpt.VALUE, $event)"
|
||||||
|
size="small"
|
||||||
|
class="item"
|
||||||
|
/>
|
||||||
|
<!-- <div class="label">{{ t("conditions") }}</div>
|
||||||
|
<Selector
|
||||||
|
class="inputs"
|
||||||
|
:value="legend.condition"
|
||||||
|
:options="LegendConditions"
|
||||||
|
size="small"
|
||||||
|
placeholder="Select a condition"
|
||||||
|
@change="changeCondition"
|
||||||
|
/> -->
|
||||||
|
<!-- <div class="label">{{ t("metrics") }}</div>
|
||||||
|
<Selector
|
||||||
|
class="item mr-5"
|
||||||
|
:value="legend.secondMetric.name"
|
||||||
|
:options="states.nodeMetricList"
|
||||||
|
size="small"
|
||||||
|
placeholder="Select a metric"
|
||||||
|
@change="changeLegendMetric(LegendOpt.NAME, $event)"
|
||||||
|
/>
|
||||||
|
<Selector
|
||||||
|
class="input-small mr-5"
|
||||||
|
:value="legend.secondMetric.value"
|
||||||
|
:options="states.nodeMetricList"
|
||||||
|
size="small"
|
||||||
|
placeholder="Select a metric"
|
||||||
|
@change="changeLegendMetric(LegendOpt.CONDITION, $event)"
|
||||||
|
/>
|
||||||
|
<el-input
|
||||||
|
v-model="legend.secondMetric.condidtion"
|
||||||
|
placeholder="Please input a value"
|
||||||
|
@change="changeLegendMetric(LegendOpt.VALUE, $event)"
|
||||||
|
size="small"
|
||||||
|
class="item"
|
||||||
|
/> -->
|
||||||
|
<el-button
|
||||||
|
@click="setLegend"
|
||||||
|
class="legend-btn"
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
>
|
||||||
|
set legend
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, ref } from "vue";
|
import { reactive } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { useTopologyStore } from "@/store/modules/topology";
|
import { useTopologyStore } from "@/store/modules/topology";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { MetricCatalog, ScopeType } from "../../../data";
|
import {
|
||||||
|
MetricCatalog,
|
||||||
|
ScopeType,
|
||||||
|
MetricConditions,
|
||||||
|
LegendConditions,
|
||||||
|
} from "../../../data";
|
||||||
import { Option } from "@/types/app";
|
import { Option } from "@/types/app";
|
||||||
import { useQueryTopologyMetrics } from "@/hooks/useProcessor";
|
import { useQueryTopologyMetrics } from "@/hooks/useProcessor";
|
||||||
import { Node, Call } from "@/types/topology";
|
import { Node, Call } from "@/types/topology";
|
||||||
import { EntityType } from "../../../data";
|
import { EntityType, LegendOpt } from "../../../data";
|
||||||
|
|
||||||
/*global defineEmits */
|
/*global defineEmits */
|
||||||
const emit = defineEmits(["update"]);
|
const emit = defineEmits(["update", "updateNodes"]);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const topologyStore = useTopologyStore();
|
const topologyStore = useTopologyStore();
|
||||||
@ -121,7 +194,10 @@ const items = reactive<
|
|||||||
>([{ scope: "", dashboard: "" }]);
|
>([{ scope: "", dashboard: "" }]);
|
||||||
const states = reactive<{
|
const states = reactive<{
|
||||||
linkDashboard: string;
|
linkDashboard: string;
|
||||||
nodeDashboard: string;
|
nodeDashboard: {
|
||||||
|
scope: string;
|
||||||
|
dashboard: string;
|
||||||
|
}[];
|
||||||
linkServerMetrics: string[];
|
linkServerMetrics: string[];
|
||||||
linkClientMetrics: string[];
|
linkClientMetrics: string[];
|
||||||
nodeMetrics: string[];
|
nodeMetrics: string[];
|
||||||
@ -129,13 +205,18 @@ const states = reactive<{
|
|||||||
linkMetricList: Option[];
|
linkMetricList: Option[];
|
||||||
}>({
|
}>({
|
||||||
linkDashboard: "",
|
linkDashboard: "",
|
||||||
nodeDashboard: "",
|
nodeDashboard: [],
|
||||||
linkServerMetrics: [],
|
linkServerMetrics: [],
|
||||||
linkClientMetrics: [],
|
linkClientMetrics: [],
|
||||||
nodeMetrics: [],
|
nodeMetrics: [],
|
||||||
nodeMetricList: [],
|
nodeMetricList: [],
|
||||||
linkMetricList: [],
|
linkMetricList: [],
|
||||||
});
|
});
|
||||||
|
const legend = reactive<{
|
||||||
|
metric: any;
|
||||||
|
condition: string;
|
||||||
|
secondMetric: any;
|
||||||
|
}>({ metric: {}, condition: "", secondMetric: {} });
|
||||||
|
|
||||||
getMetricList();
|
getMetricList();
|
||||||
async function getMetricList() {
|
async function getMetricList() {
|
||||||
@ -159,6 +240,26 @@ async function getMetricList() {
|
|||||||
e + "Relation" === (MetricCatalog as any)[d.catalog]
|
e + "Relation" === (MetricCatalog as any)[d.catalog]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
async function setLegend() {
|
||||||
|
updateSettings();
|
||||||
|
const ids = topologyStore.nodes.map((d: Node) => d.id);
|
||||||
|
const param = await useQueryTopologyMetrics([legend.metric.name], ids);
|
||||||
|
const res = await topologyStore.getLegendMetrics(param);
|
||||||
|
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
}
|
||||||
|
emit("updateNodes");
|
||||||
|
}
|
||||||
|
function changeLegend(type: string, opt: any) {
|
||||||
|
legend.metric[type] = opt[0].value || opt;
|
||||||
|
}
|
||||||
|
function changeCondition(opt: Option[]) {
|
||||||
|
legend.condition = opt[0].value;
|
||||||
|
}
|
||||||
|
function changeLegendMetric(type: string, opt: any) {
|
||||||
|
legend.secondMetric[type] = opt[0].value || opt;
|
||||||
|
}
|
||||||
function changeScope(index: number, opt: Option[]) {
|
function changeScope(index: number, opt: Option[]) {
|
||||||
items[index].scope = opt[0].value;
|
items[index].scope = opt[0].value;
|
||||||
items[index].dashboard = "";
|
items[index].dashboard = "";
|
||||||
@ -183,6 +284,7 @@ function updateSettings() {
|
|||||||
linkServerMetrics: states.linkServerMetrics,
|
linkServerMetrics: states.linkServerMetrics,
|
||||||
linkClientMetrics: states.linkClientMetrics,
|
linkClientMetrics: states.linkClientMetrics,
|
||||||
nodeMetrics: states.nodeMetrics,
|
nodeMetrics: states.nodeMetrics,
|
||||||
|
legend,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
async function changeLinkServerMetrics(options: Option[]) {
|
async function changeLinkServerMetrics(options: Option[]) {
|
||||||
@ -242,12 +344,16 @@ async function changeNodeMetrics(options: Option[]) {
|
|||||||
|
|
||||||
.inputs {
|
.inputs {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
width: 330px;
|
width: 350px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
width: 137px;
|
width: 140px;
|
||||||
margin: 5px 5px 0 0;
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-small {
|
||||||
|
width: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
@ -258,4 +364,9 @@ async function changeNodeMetrics(options: Option[]) {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.legend-btn {
|
||||||
|
margin-top: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -18,7 +18,7 @@ import icons from "@/assets/img/icons";
|
|||||||
import { Node } from "@/types/topology";
|
import { Node } from "@/types/topology";
|
||||||
|
|
||||||
icons["KAFKA-CONSUMER"] = icons.KAFKA;
|
icons["KAFKA-CONSUMER"] = icons.KAFKA;
|
||||||
export default (d3: any, graph: any, funcs: any, tip: any) => {
|
export default (d3: any, graph: any, funcs: any, tip: any, legend: any) => {
|
||||||
const nodeEnter = graph
|
const nodeEnter = graph
|
||||||
.append("g")
|
.append("g")
|
||||||
.call(
|
.call(
|
||||||
@ -46,9 +46,25 @@ export default (d3: any, graph: any, funcs: any, tip: any) => {
|
|||||||
.attr("x", 2)
|
.attr("x", 2)
|
||||||
.attr("y", 10)
|
.attr("y", 10)
|
||||||
.attr("style", "cursor: move;")
|
.attr("style", "cursor: move;")
|
||||||
.attr("xlink:href", (d: { isReal: number; sla: number; cpm: number }) =>
|
.attr("xlink:href", (d: { [key: string]: number }) => {
|
||||||
d.sla < 95 && d.isReal && d.cpm > 1 ? icons.CUBEERROR : icons.CUBE
|
if (!legend) {
|
||||||
);
|
return icons.CUBE;
|
||||||
|
}
|
||||||
|
const val = legend.metric.name.includes("_sla")
|
||||||
|
? d[legend.metric.name] / 100
|
||||||
|
: d[legend.metric.name];
|
||||||
|
if (legend.metric.condition === "<") {
|
||||||
|
return val < Number(legend.metric.value) && d.isReal
|
||||||
|
? icons.CUBEERROR
|
||||||
|
: icons.CUBE;
|
||||||
|
}
|
||||||
|
if (legend.metric.condition === ">") {
|
||||||
|
return val > Number(legend.metric.value) && d.isReal
|
||||||
|
? icons.CUBEERROR
|
||||||
|
: icons.CUBE;
|
||||||
|
}
|
||||||
|
return icons.CUBE;
|
||||||
|
});
|
||||||
nodeEnter
|
nodeEnter
|
||||||
.append("image")
|
.append("image")
|
||||||
.attr("width", 32)
|
.attr("width", 32)
|
||||||
|
Loading…
Reference in New Issue
Block a user