You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
555 lines
23 KiB
555 lines
23 KiB
require([
|
|
"/static/app/DA-ITSI-CP-vmware-dashboards/swc-vmware-cp/index.js",
|
|
"pm/PMLayoutView",
|
|
"pm/ThresholdCollection",
|
|
"pm/contrib/d3/d3.amd",
|
|
"pm/PMPinboardView",
|
|
"pm/PMTreeView",
|
|
'/static/app/DA-ITSI-CP-vmware-dashboards/libs/underscore.js',
|
|
],
|
|
function (
|
|
SWCVMware,
|
|
PMLayout,
|
|
ThresholdCollection,
|
|
d3,
|
|
PMPinboard,
|
|
PMTree,
|
|
_) {
|
|
const mvc = SWCVMware.MVC;
|
|
const DashboardController = SWCVMware.SimpleXML;
|
|
const HeaderView = SWCVMware.HeaderView;
|
|
const DropdownInput = SWCVMware.DropdownInput;
|
|
const utils = SWCVMware.MVCUtils;
|
|
const FooterView = SWCVMware.FooterView;
|
|
const TimeRangeInput = SWCVMware.TimerangeInput;
|
|
const SearchManager = SWCVMware.SearchManager;
|
|
const PostProcessManager = SWCVMware.PostProcessManager;
|
|
const SubmitButton = SWCVMware.SubmitInput;
|
|
const UrlTokenModel = SWCVMware.URLTokenModel;
|
|
|
|
var pageLoading = true;
|
|
|
|
|
|
//
|
|
// TOKENS
|
|
//
|
|
|
|
// Create token namespaces
|
|
var urlTokenModel = new UrlTokenModel();
|
|
mvc.Components.registerInstance('url', urlTokenModel);
|
|
var defaultTokenModel = mvc.Components.getInstance('default', {create: true});
|
|
var submittedTokenModel = mvc.Components.getInstance('submitted', {create: true});
|
|
|
|
|
|
// Initialize tokens
|
|
defaultTokenModel.set(urlTokenModel.toJSON());
|
|
var defaultUpdate = {};
|
|
|
|
var submitTokensSoon = _.debounce(function (replaceState) {
|
|
submittedTokenModel.set(defaultTokenModel.toJSON());
|
|
urlTokenModel.saveOnlyWithPrefix('form\\.', defaultTokenModel.toJSON(), {
|
|
replaceState: replaceState
|
|
});
|
|
});
|
|
|
|
var submitTokens = function () {
|
|
submitTokensSoon(pageLoading);
|
|
};
|
|
|
|
urlTokenModel.on('url:navigate', function () {
|
|
defaultTokenModel.set(urlTokenModel.toJSON());
|
|
if (!_.isEmpty(urlTokenModel.toJSON()) && !_.all(urlTokenModel.toJSON(), _.isUndefined)) {
|
|
submitTokens();
|
|
} else {
|
|
submittedTokenModel.clear();
|
|
}
|
|
});
|
|
|
|
|
|
//
|
|
// SEARCH MANAGERS
|
|
//
|
|
|
|
// Base Populating search for fields 'field2' and 'field3'
|
|
var metrics_search = new SearchManager({
|
|
"id": "metrics_search",
|
|
"latest_time": "2",
|
|
"earliest_time": "1",
|
|
"search": "| inputlookup VMWPerformanceMetrics",
|
|
"cancelOnUnload": true,
|
|
"status_buckets": 0,
|
|
"app": utils.getCurrentApp(),
|
|
"auto_cancel": 90,
|
|
"cache": 6000,
|
|
"preview": false
|
|
}, {tokens: true});
|
|
|
|
|
|
// Populating search for field 'field2'
|
|
var search1 = new PostProcessManager({
|
|
"managerid": "metrics_search",
|
|
"id": "search1",
|
|
"latest_time": "$latest$",
|
|
"search": "search entity=$entity_type$ | dedup perftype | table perftype",
|
|
"earliest_time": "$earliest$",
|
|
"cancelOnUnload": true,
|
|
"status_buckets": 0,
|
|
"app": utils.getCurrentApp(),
|
|
"auto_cancel": 90,
|
|
"preview": true
|
|
}, {tokens: true});
|
|
|
|
|
|
// Populating search for field 'field3'
|
|
var search2 = new PostProcessManager({
|
|
"managerid": "metrics_search",
|
|
"id": "search2",
|
|
"latest_time": "$latest$",
|
|
"search": "search entity=$entity_type$ perftype=$perf_type$ | table metric",
|
|
"earliest_time": "$earliest$",
|
|
"cancelOnUnload": true,
|
|
"status_buckets": 0,
|
|
"app": utils.getCurrentApp(),
|
|
"auto_cancel": 90,
|
|
"preview": true
|
|
}, {tokens: true});
|
|
|
|
|
|
//
|
|
// SPLUNK HEADER AND FOOTER
|
|
//
|
|
|
|
new HeaderView({
|
|
id: 'header',
|
|
section: 'dashboards',
|
|
el: $('.header'),
|
|
acceleratedAppNav: true
|
|
}, {tokens: true}).render();
|
|
|
|
new FooterView({
|
|
id: 'footer',
|
|
el: $('.footer')
|
|
}, {tokens: true}).render();
|
|
|
|
//
|
|
// VIEWS: FORM INPUTS
|
|
//
|
|
|
|
var field1 = new DropdownInput({
|
|
"id": "field1",
|
|
"choices": [
|
|
{"value": "virtualmachine", "label": "Virtual Machine"},
|
|
{"value": "hostsystem", "label": "Host System"}
|
|
],
|
|
"default": "virtualmachine",
|
|
"seed": "virtualmachine",
|
|
"value": "$form.entity_type$",
|
|
"showClearButton": false,
|
|
"el": $('#field1')
|
|
}, {tokens: true}).render();
|
|
|
|
field1.on("change", function (value, input, options) {
|
|
if (!field1.hasValue()) {
|
|
defaultUpdate['field1'] = true;
|
|
this.val(field1.settings.get("default"));
|
|
return;
|
|
}
|
|
|
|
var newValue = field1.val() || field1.settings.get("default");
|
|
var newComputedValue = newValue;
|
|
|
|
if (newComputedValue === "hostsystem") {
|
|
var perfSourceValue = "HostSystem";
|
|
var metricEntityValue = "esxihost";
|
|
}else {
|
|
var perfSourceValue = "VirtualMachine";
|
|
var metricEntityValue = "vm";
|
|
}
|
|
// Update computed value
|
|
defaultTokenModel.set("metric_entity", metricEntityValue);
|
|
defaultTokenModel.set("perf_source", perfSourceValue);
|
|
defaultTokenModel.set("entity_type", newComputedValue);
|
|
});
|
|
defaultUpdate['field1'] = true;
|
|
field1.trigger("change", field1.val(), field1);
|
|
|
|
var field2 = new DropdownInput({
|
|
"id": "field2",
|
|
"choices": [],
|
|
"default": "cpu",
|
|
"seed": "cpu",
|
|
"labelField": "perftype",
|
|
"valueField": "perftype",
|
|
"value": "$form.perf_type$",
|
|
"showClearButton": false,
|
|
"managerid": "search1",
|
|
"el": $('#field2')
|
|
}, {tokens: true}).render();
|
|
|
|
field2.on("change", function (value, input, options) {
|
|
if (!field2.hasValue()) {
|
|
defaultUpdate['field2'] = true;
|
|
this.val(field2.settings.get("default"));
|
|
return;
|
|
}
|
|
|
|
var newValue = field2.val() || field2.settings.get("default");
|
|
var newComputedValue = newValue;
|
|
if (newValue === "mem") {
|
|
newValue = "memory"
|
|
}
|
|
var newDisplayPerfType = newValue
|
|
|
|
// Update computed value
|
|
defaultTokenModel.set("perf_type", newComputedValue);
|
|
defaultTokenModel.set("display_perf_type", newDisplayPerfType);
|
|
});
|
|
defaultUpdate['field2'] = true;
|
|
field2.trigger("change", field2.val(), field2);
|
|
|
|
var field3 = new DropdownInput({
|
|
"id": "field3",
|
|
"choices": [],
|
|
"valueField": "metric",
|
|
"labelField": "metric",
|
|
"value": "$form.metric$",
|
|
"managerid": "search2",
|
|
"showClearButton": false,
|
|
"el": $('#field3'),
|
|
"width": 350 // If you change this, change the width in
|
|
// the corresponding HTML container
|
|
}, {
|
|
tokens: true
|
|
}).render();
|
|
|
|
field3.on("change", function (value, input, options) {
|
|
if (!field3.hasValue()) {
|
|
defaultUpdate['field3'] = true;
|
|
this.val(field3.settings.get("default"));
|
|
return;
|
|
}
|
|
|
|
var newValue = field3.val() || field3.settings.get("default");
|
|
var newComputedValue = newValue;
|
|
|
|
var metricPerfComponent = "";
|
|
if(newComputedValue){
|
|
metricPerfComponent = newComputedValue.split("_");
|
|
}
|
|
var metricAggregationValue = metricPerfComponent[0];
|
|
var metricTypeValue = metricPerfComponent[2];
|
|
var unitValue = metricPerfComponent[3];
|
|
|
|
// Update computed value
|
|
defaultTokenModel.set("metric_aggregation", metricAggregationValue);
|
|
defaultTokenModel.set("metric_type", metricTypeValue);
|
|
defaultTokenModel.set("unit", unitValue);
|
|
defaultTokenModel.set("metric", newComputedValue);
|
|
});
|
|
defaultUpdate['field3'] = true;
|
|
field3.trigger("change", field3.val(), field3);
|
|
//$("#field3 .select2-container").first().width(250);
|
|
|
|
|
|
var field4 = new TimeRangeInput({
|
|
"id": "field4",
|
|
"default": {"latest_time": "now", "earliest_time": "-24h@h"},
|
|
"earliest_time": "$earliest$",
|
|
"latest_time": "$latest$",
|
|
"el": $('#field4')
|
|
}, {tokens: true}).render();
|
|
|
|
|
|
field4.on("change", function (value, input, options) {
|
|
if (!field4.hasValue()) {
|
|
defaultUpdate['field4'] = true;
|
|
field4.updateValueWithDefault();
|
|
return;
|
|
}
|
|
|
|
// Submit the token only if it wasn't from setting the default
|
|
if (defaultUpdate['field4']) {
|
|
defaultUpdate['field4'] = false;
|
|
} else {
|
|
submitTokens();
|
|
}
|
|
});
|
|
defaultUpdate['field4'] = true;
|
|
field4.trigger("change", field4.val(), field4);
|
|
|
|
|
|
//
|
|
// SUBMIT FORM DATA
|
|
//
|
|
|
|
var submit = new SubmitButton({
|
|
id: 'submit',
|
|
el: $('#search_btn')
|
|
}, {tokens: true}).render();
|
|
|
|
submit.on("submit", function () {
|
|
//FIXME: make this alerting sexier
|
|
var field3_val = field3.val();
|
|
|
|
//In cupcake search results are stored at <view>.visualization._data, in bubbles they are at <view>.select._data, fun right?
|
|
var viz = field3.select || field3.visualization;
|
|
|
|
if (field3_val === undefined || _.find(viz._data, function (result) {
|
|
return result.metric === field3_val;
|
|
}) === undefined) {
|
|
alert("You must select a metric to kick off performance searches!");
|
|
}
|
|
else {
|
|
submitTokens();
|
|
}
|
|
});
|
|
|
|
if (!_.isEmpty(urlTokenModel.toJSON())) {
|
|
submitTokens();
|
|
}
|
|
|
|
|
|
//
|
|
// DASHBOARD READY
|
|
//
|
|
|
|
DashboardController.ready();
|
|
pageLoading = false;
|
|
|
|
//We good to go bro!
|
|
$("body").removeClass("preload");
|
|
|
|
//
|
|
// Proactive Monitoring Render
|
|
//
|
|
var main_container = $(".proactive-monitoring-container").first();
|
|
//
|
|
// Layout Creation
|
|
//
|
|
var layout = new PMLayout({el: main_container});
|
|
layout.render();
|
|
|
|
//
|
|
// Threshold Data Bindings
|
|
//
|
|
var thresholds = new ThresholdCollection();
|
|
//Keep modified threshold data on hand any time it changes (i.e. when it arrives)
|
|
//FIXME: there is a race condition here if the dynamic tokens are somehow set, may be possible via uri string
|
|
var submitted_tokens = mvc.Components.get('submitted');
|
|
var threshold_data = {};
|
|
thresholds.on("sync", function () {
|
|
threshold_data = this.reduce(function (memo, model) {
|
|
var entitytype = model.entry.content.attributes.entitytype.toLowerCase();
|
|
if (!memo.hasOwnProperty(entitytype)) {
|
|
memo[entitytype] = {};
|
|
}
|
|
memo[entitytype][model.entry.content.attributes.metric] = model.entry.content.attributes;
|
|
return memo;
|
|
}, threshold_data);
|
|
submitted_tokens.trigger('change:metric');
|
|
}, thresholds);
|
|
thresholds.fetch({
|
|
data: {
|
|
app: "DA-ITSI-CP-vmware-dashboards",
|
|
search: "p_*",
|
|
count: "0"
|
|
}
|
|
});
|
|
|
|
|
|
//Bind to the change in metric to get our thresholding search proper
|
|
submitted_tokens.on('change:metric', _.debounce(function () {
|
|
var cur_metric = submitted_tokens.get("metric");
|
|
var entitytype = submitted_tokens.get("entity_type");
|
|
var entity_thresholds = threshold_data[entitytype] || {};
|
|
if (cur_metric !== null && cur_metric !== undefined && entity_thresholds.hasOwnProperty("p_" + cur_metric)) {
|
|
var threshold = entity_thresholds["p_" + cur_metric];
|
|
var snippet = "eval threshold_severity=case(avg_metric" + threshold.comparator + threshold.critical + ', "critical", avg_metric' + threshold.comparator + threshold.warning + ', "warning", isnotnull(avg_metric), "normal", 1==1, "unknown")';
|
|
snippet = snippet + ' | eval threshold_index=case(threshold_severity=="critical", 0, threshold_severity=="warning", 1, threshold_severity=="normal", 2, threshold_severity=="unknown", 3) ';
|
|
submitted_tokens.set("threshold_snippet", snippet);
|
|
}
|
|
else {
|
|
submitted_tokens.set("threshold_snippet", 'eval threshold_severity="unknown" | eval threshold_index=3');
|
|
}
|
|
}));
|
|
|
|
|
|
//
|
|
// Search Managers
|
|
//
|
|
var vm_hierarchy_search = new SearchManager({
|
|
id: "virtualmachine-hierarchy",
|
|
earliest_time: "-8h",
|
|
latest_time: "now",
|
|
preview: false,
|
|
cache: 600,
|
|
search: '`vmwareinv-index` sourcetype=vmware_inframon:inv:hierarchy earliest=-8h latest=now "\\"type\\": \\"VirtualMachine\\"" OR "\\"type\\": \\"RootFolder\\"" OR "\\"type\\": \\"HostSystem\\"" OR "\\"type\\": \\"ClusterComputeResource\\"" ' +
|
|
'| spath changeSet.runtime.host.moid output=vmhost ' +
|
|
'| spath moid output=moid ' +
|
|
'| spath type output=type ' +
|
|
'| spath changeSet.name output=name ' +
|
|
'| search type="HostSystem" OR type="VirtualMachine" OR type="ClusterComputeResource" OR type="RootFolder" ' +
|
|
'| spath changeSet.parent.moid output=parent ' +
|
|
'| spath changeSet.parent.type output=parentType ' +
|
|
'| spath rootFolder.moid output=rootFolderMoid ' +
|
|
'| eval parent=if(type="VirtualMachine", vmhost, if(parentType="ComputeResource" OR parentType="Folder", rootFolderMoid, parent)) ' +
|
|
'| eval parentType=if(type="VirtualMachine", "HostSystem", if(parent=rootFolderMoid, "RootFolder", parentType)) ' +
|
|
'| stats first(name) as name first(type) as type first(parent) as parent first(parentType) as parentType by host, moid ' +
|
|
'| eval moid=if(type="RootFolder", "*", moid) ' +
|
|
'| eval parent=if(parentType="RootFolder", "*", parent)',
|
|
time_format: "%s.%Q"
|
|
}, {tokens: true, tokenNamespace: "submitted"});
|
|
|
|
var host_hierarchy_search = new SearchManager({
|
|
id: "hostsystem-hierarchy",
|
|
earliest_time: "-8h",
|
|
latest_time: "now",
|
|
preview: false,
|
|
cache: 600,
|
|
search: '`vmwareinv-index` sourcetype=vmware_inframon:inv:hierarchy earliest=-8h latest=now "\\"type\\": \\"RootFolder\\"" OR "\\"type\\": \\"HostSystem\\"" OR "\\"type\\": \\"ClusterComputeResource\\"" ' +
|
|
'| spath moid output=moid ' +
|
|
'| spath type output=type ' +
|
|
'| spath changeSet.name output=name ' +
|
|
'| search type="HostSystem" OR type="ClusterComputeResource" OR type="RootFolder" ' +
|
|
'| spath changeSet.parent.moid output=parent ' +
|
|
'| spath changeSet.parent.type output=parentType ' +
|
|
'| spath rootFolder.moid output=rootFolderMoid ' +
|
|
'| eval parent=if(parentType="ComputeResource" OR parentType="Folder", rootFolderMoid, parent) ' +
|
|
'| eval parentType=if(parent=rootFolderMoid, "RootFolder", parentType) ' +
|
|
'| stats first(name) as name first(type) as type first(parent) as parent first(parentType) as parentType by host, moid ' +
|
|
'| eval moid=if(type="RootFolder", "*", moid) ' +
|
|
'| eval parent=if(parentType="RootFolder", "*", parent)',
|
|
time_format: "%s.%Q"
|
|
}, {tokens: true, tokenNamespace: "submitted"});
|
|
|
|
var leaf_performance_search = new SearchManager({
|
|
id: "leaf-performance",
|
|
earliest_time: "$earliest$",
|
|
latest_time: "$latest$",
|
|
preview: false,
|
|
cache: 600,
|
|
status_buckets: 0,
|
|
search: '| mstats avg(_value) as avgValue max(_value) as maxValue ' +
|
|
'where metric_name=vsphere.$metric_entity$.$perf_type$.$metric_type$ AND `vmwareperf-metrics-index` AND source="VMPerf:$perf_source$" ' +
|
|
'AND instance="aggregated" AND unit="$unit$" by vmware_metric_aggregation host moid ' +
|
|
'| eval avg_$metric_type$_$unit$ =if(vmware_metric_aggregation="$metric_aggregation$",avgValue,NULL) ' +
|
|
'| eval max_$metric_type$_$unit$ =if(vmware_metric_aggregation="$metric_aggregation$",maxValue,NULL) ' +
|
|
'| stats avg(avg_$metric_type$_$unit$) AS avg_metric max(max_$metric_type$_$unit$) as max_metric by host, moid ' +
|
|
'| $threshold_snippet$',
|
|
time_format: "%s.%Q"
|
|
}, {tokens: true, tokenNamespace: "submitted"});
|
|
|
|
var performance_distribution_search = new SearchManager({
|
|
id: "leaf-performance-distribution",
|
|
earliest_time: "$earliest$",
|
|
latest_time: "$latest$",
|
|
preview: false,
|
|
cache: 600,
|
|
status_buckets: 0,
|
|
search: '| mstats span=1m median(_value) as medianValue perc25(_value) as perc25Value perc75(_value) as perc75Value ' +
|
|
'perc95(_value) as perc95Value min(_value) as minValue ' +
|
|
'where metric_name=vsphere.$metric_entity$.$perf_type$.$metric_type$ AND `vmwareperf-metrics-index` AND source="VMPerf:$perf_source$" ' +
|
|
'AND instance="aggregated" AND unit="$unit$" by vmware_metric_aggregation ' +
|
|
'| eval median_$metric_type$_$unit$ =if(vmware_metric_aggregation="$metric_aggregation$",medianValue,NULL) ' +
|
|
'| eval perc25_$metric_type$_$unit$ =if(vmware_metric_aggregation="$metric_aggregation$",perc25Value,NULL) ' +
|
|
'| eval perc75_$metric_type$_$unit$ =if(vmware_metric_aggregation="$metric_aggregation$",perc75Value,NULL) ' +
|
|
'| eval perc95_$metric_type$_$unit$ =if(vmware_metric_aggregation="$metric_aggregation$",perc95Value,NULL) ' +
|
|
'| eval min_$metric_type$_$unit$ =if(vmware_metric_aggregation="$metric_aggregation$",minValue,NULL) ' +
|
|
'| timechart minspan=1m median(median_$metric_type$_$unit$) AS center ' +
|
|
'perc25(perc25_$metric_type$_$unit$) as lower_quartile ' +
|
|
'perc75(perc75_$metric_type$_$unit$) as upper_quartile ' +
|
|
'perc95(perc95_$metric_type$_$unit$) as upper_extreme ' +
|
|
'min(min_$metric_type$_$unit$) as lower_extreme',
|
|
time_format: "%s.%Q"
|
|
}, {tokens: true, tokenNamespace: "submitted"});
|
|
|
|
/*
|
|
* Alternate Distribution searches:
|
|
* BOX AND WHISKER
|
|
* | `tstats` median($metric$) perc25($metric$) perc75($metric$) perc95($metric$) min($metric$) from vmw_perf_$display_perf_type$_$entity_type$ where instance="aggregated" $metric$>=0 groupby _time span=1m | timechart minspan=1m median($metric$) AS center perc25($metric$) as lower_quartile perc75($metric$) as upper_quartile perc95($metric$) as upper_extreme min($metric$) as lower_extreme
|
|
*
|
|
* NORMAL CURVE
|
|
* | `tstats` avg($metric$) stdev($metric$) from vmw_perf_$display_perf_type$_$entity_type$ where instance="aggregated" $metric$>=0 groupby _time span=1m | timechart minspan=1m avg($metric$) AS avg_metric stdev($metric$) as sigma | eval plus_sigma=avg_metric+sigma | eval plus_2sigma=avg_metric+sigma+sigma | eval minus_sigma=avg_metric-sigma | eval minus_2sigma=avg_metric-sigma-sigma | fields - sigma | rename minus_2sigma AS lower_extreme plus_2sigma AS upper_extreme plus_sigma AS upper_quartile minus_sigma AS lower_quartile avg_metric AS center
|
|
*
|
|
*/
|
|
|
|
var specific_performance_search = new SearchManager({
|
|
id: "specific-node-performance",
|
|
earliest_time: "$earliest$",
|
|
latest_time: "$latest$",
|
|
preview: false,
|
|
cache: 600,
|
|
status_buckets: 0,
|
|
search: '| mstats span=1m avg(_value) as avgValue where metric_name=vsphere.$metric_entity$.$perf_type$.$metric_type$ AND `vmwareperf-metrics-index` AND source="VMPerf:$perf_source$" ' +
|
|
'AND (moid="$tooltip_node$" AND host="$tooltip_tree$") OR (hypervisor="$tooltip_node$" AND host="$tooltip_tree$") OR (cluster="$tooltip_node$" AND host="$tooltip_tree$") ' +
|
|
'AND instance="aggregated" AND unit="$unit$" by vmware_metric_aggregation ' +
|
|
'| eval avg_$metric_type$_$unit$ =if(vmware_metric_aggregation="$metric_aggregation$",avgValue,NULL) ' +
|
|
'| timechart minspan=1m avg(avg_$metric_type$_$unit$) AS metric',
|
|
time_format: "%s.%Q"
|
|
}, {tokens: true, tokenNamespace: "submitted"});
|
|
|
|
//
|
|
// Main View Controllers
|
|
//
|
|
|
|
var pinboard = new PMPinboard({
|
|
el: layout.$sidebar
|
|
});
|
|
pinboard.render();
|
|
|
|
var tree = new PMTree({
|
|
el: layout.$main_stage,
|
|
managerid: "$entity_type$-hierarchy",
|
|
leaf_type: "$entity_type$",
|
|
metric: "$metric$",
|
|
threshold_data: threshold_data,
|
|
perf_managerid: "leaf-performance",
|
|
perf_message_container: $("#search_processing_indicator"),
|
|
tooltip_distribution_managerid: "leaf-performance-distribution",
|
|
tooltip_specific_managerid: "specific-node-performance",
|
|
tooltip_tree_token: "$tooltip_tree$",
|
|
tooltip_node_token: "$tooltip_node$",
|
|
tooltip_earliest: "$earliest$",
|
|
tooltip_latest: "$latest$"
|
|
}, {tokens: true, tokenNamespace: "submitted"});
|
|
|
|
|
|
//Christmas Tree Easter Egg, yes mixing holidays there
|
|
window.xmasMode = function () {
|
|
window.mode = 1;
|
|
return window.setInterval(function () {
|
|
if (window.mode === 1) {
|
|
d3.selectAll("circle").attr("opacity", 1);
|
|
window.mode = 2;
|
|
}
|
|
else if (window.mode === 2) {
|
|
d3.selectAll("circle").each(function (d, i) {
|
|
if (i % 2 === 0) {
|
|
d3.select(this).attr("opacity", 1);
|
|
}
|
|
else {
|
|
d3.select(this).attr("opacity", 1e-6);
|
|
}
|
|
});
|
|
window.mode = 3;
|
|
}
|
|
else if (window.mode === 3) {
|
|
d3.selectAll("circle").each(function (d, i) {
|
|
if (i % 2 === 1) {
|
|
d3.select(this).attr("opacity", 1);
|
|
}
|
|
else {
|
|
d3.select(this).attr("opacity", 1e-6);
|
|
}
|
|
});
|
|
window.mode = 4;
|
|
}
|
|
else {
|
|
d3.selectAll("circle").attr("opacity", 1e-6);
|
|
window.mode = 1;
|
|
}
|
|
}, 500);
|
|
};
|
|
}
|
|
);
|