This tutorial will guide you through the construction of a custom view based on the raw table query API. The view will show:
Let’s start by opening the Hurricanes demo file from the “File > Open Demo” menu using the Omniscope “Classic” interface if prompted.
Create a new blank tab, then click on the “Add View > View Designer” icon to start creating our new custom view. In the browser View Designer app, click on “Create new” and give it a name (e.g. raw data view).
Select the newly created view and click on “edit view”. The first file we will edit is the manifest.json so we can customise our view capabilities and options.
We need to:
"autoQuery": false
as we will create our own custom queryIn the options -> items element:
remove the split and measures elements
add a fields item so we can pick which field to retrieve in the query :
"fields": {
"displayName": "Fields",
"type": "FIELD",
"list": true,
"minItems": 1,
"mandatory": true,
"unique": true
}
The item will allow to pick multiple fields from a list, with a mandatory minimum 1 field to be picked.
add a sorts item to sort the selected fields:
"sorts": {
"displayName": "Sorts",
"type": "FIELD",
"list": true,
"unique": true
}
```
add a sortsDirection item to be applied to all sorts:
"sortsDirection": {
"displayName": "Sorts direction",
"type": "CHOICE",
"mandatory": true,
"values": [
"ASCENDING",
"DESCENDING"
],
"unique": true
}
The item is a CHOICE type with custom values.
Now we can add all these items to the view toolbar by editing the structure -> toolbar element
"structure": {
"toolbar": [
"fields",
"sorts",
"sortsDirection"
],
"x": [
"paneX"
],
"y": [
"paneY"
]
}
Once we edited the manifest.json we can now edit the index.html file in the view designer.
The first step is to build the raw data query.
As we are providing sorts on selected fields, we need to ensure sorts are only configured on selected fields.
// get hold of the view context
var viewContext = omniscope.view.context();
var sorts = [];
if (viewContext.options.items.sorts) {
viewContext.options.items.sorts.forEach(function(sortItem) {
if (viewContext.options.items.fields.indexOf(sortItem) >= 0) {
sorts.push({ inputField: sortItem, direction: omniscope.view.context().options.items.sortsDirection });
} else {
// show some warnings to user.
document.getElementById("warnings").textContent += "Cannot order by '"+sortItem+"' as it is not selected in the Fields menu";
}
});
}
Then we can create the raw query
var rawQuery = {
"@visokiotype": "SimpleQuery",
"fields" : viewContext.options.items.fields,
"sorts" : sorts,
"filters" : viewContext.dataConfig.filter
};
Note that we need to add the @visokiotype element to specify the “SimpleQuery” value to avoid any ambiguity.
The query contains the fields and sorts specified by the user, and it also uses the filters provided by the view framework.
The following code snippet shows how to execute the query and create a html table with the result data.
We use the omniscope.view.queryBuilder() function that creates a query builder with pre-configured view’s filter state.
We insert it as function called on view load, update and resize (replace the existing one)
omniscope.view.on(["load", "update", "resize"], function() {
// get hold of the view context
var viewContext = omniscope.view.context();
var sorts = [];
if (viewContext.options.items.sorts) {
viewContext.options.items.sorts.forEach(function(sortItem) {
if (viewContext.options.items.fields.indexOf(sortItem) >= 0) {
sorts.push({ inputField: sortItem, direction: omniscope.view.context().options.items.sortsDirection });
} else {
// show some warnings to user.
document.getElementById("warnings").textContent += "Cannot order by '"+sortItem+"' as it is not selected in the Fields menu";
}
});
}
// create the query
var rawQuery = {
"@visokiotype": "SimpleQuery",
"fields" : viewContext.options.items.fields,
"sorts" : sorts,
"filters" : viewContext.dataConfig.filter
};
// execute the query
omniscope.view.queryBuilder().table(rawQuery)
.on("error", function(err) {
if (event.data.error) console.log(event.data.error);
omniscope.view.error(event.data.message, event.data.internal);
})
//on result
.on("load", function(event) {
document.getElementById("query").textContent = JSON.stringify(rawQuery, null, 2);
if (event.data.records) {
//create tabular view of result
var fields = event.data.schema.fields;
var records = event.data.records;
var table = document.createElement("table");
var header = table.insertRow(0);
header.style.fontWeight = "bold";
var col = 0;
fields.forEach(function(field) {
var cell = header.insertCell(col++);
cell.innerHTML = field.name;
});
var recordId = 1;
records.forEach(function(record) {
var col = 0;
var row = table.insertRow(recordId++);
record.forEach(function(column) {
var cell = row.insertCell(col++);
//truncate text
if (typeof column === "string" && column.length > 50) {
column = column.substring(0, 50) + "...";
}
cell.innerHTML = column;
});
});
document.getElementById("result").appendChild(table);
} else {
document.getElementById("result").textContent = "No records";
}
})
.execute();
});
Here we adjust the view style to make it look prettier. In the html style element we add some CSS rules for our view:
main {
width: 99%;
height: 99%;
font-family: monospace;
font-size: 11px;
overflow: scroll;
}
#query {
font-size: 11px;
overflow: scroll;
border: 1px dotted lightgrey;
height: 200px;
white-space: pre;
}
#result {
font-size: 12px;
}
#warnings {
color: red;
white-space: pre;
}
td {
border: 1px dotted lightgrey;
}
And we complete the index.html editing by adding the view structure in the HTML body element:
<main>
<div id="warnings"></div>
<h3>Query:</h3>
<div id="query"></div>
<h3>Result:</h3>
<div id="result"></div>
</main>
Finally, check the online demo for this tutorial Raw data custom view demo