Firefox Web Extension bug - Unable to render Highcharts - javascript

I believe there's a bug in Firefox addons where Highcharts within web-extensions cannot be rendered.
I'm porting a Chrome extension into Firefox. When you click on the extension icon, the popup window renders some charts using Highcharts dynamically. This works in Chrome & Safari. However, with Firefox, the tabbrowser.xml at line 5828 (shown below) script becomes unresponsive. If the Highcharts are NOT used, the extension loads fine.
Here's the minimal code (from the github link below) to generate simple HighCharts in my extension. I used this to reproduce the issue. https://github.com/bluechips23/FirefoxTesting
Libraries Used:
JQuery: Version 1.12.4 from https://code.jquery.com/jquery-1.12.4.js
Highcharts: version 5.0.10 from http://www.highcharts.com/download
JQuery UI: Version 1.12.1 from https://jqueryui.com/resources/download/jquery-ui-1.12.1.zip
Code from extension
manifest.json
{
"manifest_version": 2,
"name": "AppDebugging",
"description": "Testing app",
"version": "2.0.0.0",
"icons": {
"16": "16.png",
"48": "48.png",
"128": "128.png"
},
"background": {
"scripts": ["browser.js", "eventPage.js"],
"persistent": false
},
"page_action": {
"default_icon": "icon4.png",
"default_popup": "popup.html",
"default_title": "Testing App"
},
"permissions": [
"http://*/*",
"https://*/*",
"tabs"
]
}
2. popup.html
<!doctype html>
<html>
<head>
<title>Test Popup</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/bootstrap-theme.min.css">
<link rel="stylesheet" href="css/jquery-ui.css">
<link rel="stylesheet" href="css/style.css">
<script src="popup.js"></script>
<script src="js/jquery-1.12.4.js"></script>
<script src="js/jquery-ui.js"></script>
<script src="js/highcharts.js"></script>
</head>
<body>
<div class='header' id="header">
<h1 id="banner">TESTING</h1>
</div>
<div class="bodyContainer" id="bodyId">
<div class="container" id="container-0"></div>
<div class="container" id="container-1"></div>
<div class="container" id="container-2"></div>
</div>
</body>
</html>
3. popup.js
function getCurrentTabUrl(callback) {
var queryInfo = {
active: true,
currentWindow: true
};
browser.tabs.query(queryInfo, function(tabs) {
var tab = tabs[0];
var url = tab.url;
console.assert(typeof url == 'string', 'tab.url should be a string');
callback(url);
});
}
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('a[href]').forEach(function (el) {
el.addEventListener('click', function (event) {
event.preventDefault();
browser.tabs.create({
url: event.target.getAttribute('href')
});
});
});
getCurrentTabUrl(function(url) {
generateData();
});
var generateData = function() {
console.debug("inside generate data.....");
var categoryData = new Array();
for(var index = 0; index < 10; index++) {
var category = "Category " + index;
categoryData.push(category);
}
for(var index = 0; index < 3; index++) {
var positiveData = getRandomArray();
var negativeData = getRandomArray();
var neutralData = getRandomArray();
var containerID = "container-" + index;
console.debug("Container id : " + containerID);
createChart(name, categoryData, positiveData, negativeData, neutralData, containerID);
}
};
var getRandomNumber = function(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
};
var getRandomArray = function() {
var min = 0;
var max = 50;
var myArray = new Array();
for(var index = 0; index < 10; index++) {
var random = getRandomNumber(min, max);
myArray.push(parseInt(random));
}
return myArray;
};
var createChart = function(name, categoryData, positiveData,
negativeData, neutralData, container) {
var titleString = "Chart " + name;
var subTitleString = "This is a test";
Highcharts.chart(container, {
chart: {
type: 'bar',
style: {
color: '#333'
},
backgroundColor: "#f2f2f2"
},
title: {
text: titleString,
style: {
color: '#333'
}
},
subtitle: {
text: subTitleString,
style: {
color: '#333',
fontSize: "15px"
}
},
xAxis: {
categories: categoryData,
labels: {
style: {
fontSize: "12px"
}
},
},
yAxis: {
min: 0,
title: {
text: 'Values',
align: 'high',
style: {
fontSize: '18px',
}
},
labels: {
overflow: 'justify',
style: {
fontSize: '14px',
}
},
tickPositioner: function () {
var positions = [],
tick = Math.floor(this.dataMin),
increment = Math.ceil((this.dataMax - this.dataMin) / 6);
if (this.dataMax !== null && this.dataMin !== null) {
for (tick; tick - increment <= this.dataMax; tick += increment) {
positions.push(tick);
}
}
return positions;
},
gridLineWidth: 0,
},
colors: [
'#4be8a1',
'#ed6764',
'#adadad',
],
plotOptions: {
series: {
pointWidth: 5, //width of the column bars irrespective of the chart size
groupPadding: 0.1,
pointPadding: 0
},
column: {
colorByPoint: true
},
},
legend: {
enabled: false
},
credits: {
enabled: false
},
tooltip: {
shadow: true,
useHTML: true,
shared: true,
backgroundColor: '#f2f2f2'
},
series: [{
name: 'Positive',
data: positiveData
}, {
name: 'Negative',
data: negativeData
}, {
name: 'Neutral',
data: neutralData
}]
});
};});
Here's the full error stack on debugger:
Error: Script terminated by timeout at:
handleEvent#chrome://browser/content/tabbrowser.xml:5828:1
_handleDOMChange#chrome://extensions/content/ext-browser-content.js:203:7
tabbrowser.xml:5828:1
NS_ERROR_ILLEGAL_VALUE: Component returned failure code: 0x80070057 (NS_ERROR_ILLEGAL_VALUE) [nsIMessageSender.sendAsyncMessage] ext-browser-content.js:213
Here's the tabbrowser.xml:5828:
<method name="handleEvent">
<parameter name="aEvent"/>
<body><![CDATA[ // This switch statement throws error.
switch (aEvent.type) {
case "load":
this.updateVisibility();
TabsInTitlebar.init();
break;
case "resize":
if (aEvent.target != window)
break;
TabsInTitlebar.updateAppearance();
....
</method>
Here's the code at ext-browser-content.js:203
_handleDOMChange(detail) {
let doc = content.document;
.... [truncated code]....
// LINE BELOW THROWS ERROR
contentViewer.getContentSizeConstrained(this.maxWidth * ratio,
this.maxHeight * ratio,
w, h);
let width = Math.ceil(w.value / ratio);
let height = Math.ceil(h.value / ratio);
result = {width, height, detail};
}
sendAsyncMessage("Extension:BrowserResized", result);
},
};

Related

how to run a python file in Typescript file

I have a typescript extension that needs to run a python file. after a file dialog is opened the extension uses exec to run the following command.
python C:\\Users\\schriste\\.vscode\\extensions\\consolidatedExtension\\src\\testingFile.py C:\\EquipVsCode\\5G_ServingCell_Rsrp_Rsrq_Sinr_RSSI_B974_all.isf
I thought exec would work since ive tired exec using the windows command dir and it worked just fine.
all I need is the right function to run the command shown above. has anyone done this? it seems like such a simple and common task but im having so much difficulty finding information on how this can be done.
below is the code from extension.ts
perhaps someone has information on how the following work for what I am trying to accomplish but I have not found a way for these to work as of right now: execFile spawn
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';
import { open } from 'fs';
import * as path from 'path';
import { json } from 'stream/consumers';
const { ChildProcess, exec } = require('child_process');
const { execFile } = require('node:child_process');
const { spawn } = require('node:child_process');
const { stdout, stderr } = require('process');
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
//File Dialog
let disposable = vscode.commands.registerCommand('consolidatedExtension.openFile', function () {
const options = {
canSelectMany: false,
openLabel: 'Open'
};
vscode.window.showOpenDialog(options).then(fileUri => {
if (fileUri && fileUri[0]) {
console.log('Selected file: ' + fileUri[0].fsPath);
let cmd = `python C:\\Users\\schriste\\.vscode\\extensions\\consolidatedExtension\\src\\testingFile.py` + ` ` + fileUri[0].fsPath
exec(cmd2, (...args: any[])=>{
console.log(args);
});
}
});
});
//open graphView
let openWebview = vscode.commands.registerCommand('consolidatedExtension.openWebview', () => {
const panel = vscode.window.createWebviewPanel(
'openWebview', // Identifies the type of the webview. Used internally
'Example Page', // Title of the panel displayed to the user
vscode.ViewColumn.One, // Editor column to show the new webview panel in.
{ // Enable scripts in the webview
enableScripts: true //Set this to true if you want to enable Javascript.
});
//get path to json on disk
const onDiskPath = vscode.Uri.file(
path.join(context.extensionPath, 'src', 'data.json')
);
//get vegaLite js on disk
const JsonDiskPath = vscode.Uri.file(
path.join(context.extensionPath, 'src', 'vegaLiteGraphs.js')
);
//and get the special URI to use with the webview
const jsonSRC = panel.webview.asWebviewUri(onDiskPath);
const jsSRC = panel.webview.asWebviewUri(JsonDiskPath);
panel.webview.html = getWebviewContent(jsonSRC, jsSRC);
});
context.subscriptions.push(openWebview);
context.subscriptions.push(disposable);
}
// this method is called when your extension is deactivated
export function deactivate() {}
function getWebviewContent(jsonSRC:vscode.Uri, jsSRC:vscode.Uri) {
return `<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdn.jsdelivr.net/npm/vega#5.21.0"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-lite#5.2.0"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-embed#6.20.2"></script>
</head>
<body>
<script type = "module">
import users from '${jsonSRC}' assert {type: 'json'};
const graphDataContainer = []
let dataPoints = []
for(let i = 0; i < users.length; i += 2)
{
for (let j = 1; j < users[i].length; j++) {
dataPoints.push({
x: users[i][j],
y: users[i + 1][j]
});
}
graphDataContainer.push(dataPoints)
dataPoints = []
}
console.log(graphDataContainer)
window.onload = function() {
let i = 0
var chart1 = new CanvasJS.Chart("chart1", {
animationEnabled: true,
zoomEnabled: true,
theme: "light2",
"title": { "text": "RSRP" },
axisX: {
gridThickness: 0,
tickLength: 0,
lineThickness: 0,
labelFormatter: function(){ return " "; },
crosshair: {
enabled: true,
color: "black",
labelFontColor: "#F8F8F8"
},
//interval: 10,
//intervalType: "millisecond",
//valueFormatString: "##.##.####"
},
axisY: {
crosshair: {
enabled: true,
color: "black",
labelFontColor: "#F8F8F8"
},
title: "Serving Cell RSRP (dBm)",
minimum: -100,
maximum: 0,
interval: 16.67
},
data: [{
type: "line",
//yValueFormatString: "#,### Units",
dataPoints: graphDataContainer[i]
}],
rangeChanged: syncHandler
});
chart1.render();
i++
var rsrqChart = new CanvasJS.Chart("chart2", {
animationEnabled: true,
zoomEnabled: true,
theme: "light2",
axisX: {
valueFormatString:"##:##:##.###",
crosshair: {
enabled: true,
color: "black",
labelFontColor: "#F8F8F8"
},
},
axisY: {
crosshair: {
enabled: true,
color: "black",
labelFontColor: "#F8F8F8"
},
title: "Serving Cell RSRQ",
minimum: -15,
interval: 2.5
},
data: [{
type: "line",
dataPoints: graphDataContainer[i]
}],
rangeChanged: syncHandler
});
rsrqChart.render();
// var chart3 = new CanvasJS.Chart("chartContainer3", {
// animationEnabled: true,
// theme: "light2",
// data: [{
// type: "line",
// dataPoints: sinrPoints
// }]
// });
// chart3.render();
var charts = [chart1, rsrqChart];
function syncHandler(e){
for (var i = 0; i < charts.length; i++) {
var chart = charts[i];
if (!chart.options.axisX)
chart.options.axisX = {};
if (!chart.options.axisY)
chart.options.axisY = {};
if (e.trigger === "reset") {
chart.options.axisX.viewportMinimum = chart.options.axisX.viewportMaximum = null;
chart.options.axisY.viewportMinimum = chart.options.axisY.viewportMaximum = null;
chart.render();
} else if (chart !== e.chart) {
chart.options.axisX.viewportMinimum = e.axisX[0].viewportMinimum;
chart.options.axisX.viewportMaximum = e.axisX[0].viewportMaximum;
chart.options.axisY.viewportMinimum = e.axisY[0].viewportMinimum;
chart.options.axisY.viewportMaximum = e.axisY[0].viewportMaximum;
chart.render();
}
}
}
}
</script>
<script type = "module" src = "${jsSRC}"></script>
<div id="chart1" style="height: 370px; width: 100%;"></div>
<div id="chart2" style="height: 370px; width: 100%;"></div>
<div id="vis"></div>
<!-- <div id="chartContainer3" style="height: 370px; width: 100%;"></div> -->
<script src="https://canvasjs.com/assets/script/canvasjs.min.js"> </script>
</body>
</html>
`;
}

Display only certain labels with chart.js

The X axis of this graph represents time in milliseconds.
I basically need to display only one 5 labels, one each second (1,2,3,4 and 5), however the graph contains too many elements and not every label is shown.
I tried looking on the Chart.js documentation but haven't found anything useful to my case.
Do you guys have any ideas on how can I do it?
Im gonna post my code below:
<head>
<script>
$(document).ready(function () {
function generateLabels() {
var chartLabels = [];
for (x = 0; x < 5000; x++) {
if(x%1000 == 0)
chartLabels.push(x/1000);
else
chartLabels.push('');
}
return chartLabels;
}
function generateData() {
var chartData = [];
for (x = 0; x < 5000; x++) {
chartData.push(Math.floor((Math.random() * 100) + 1));
}
return chartData;
}
function addData(numData, chart) {
for (var i = 0; i < numData; i++) {
chart.data.datasets[0].data.push(Math.random() * 100);
chart.data.labels.push("Label" + i);
var newwidth = $('.chartAreaWrapper2').width(); // + 60
$('.chartAreaWrapper2').width(newwidth);
}
}
var chartData = {
labels: generateLabels(),
datasets: [{
label: "Test Data Set",
lineTension: 0,
fill:false,
pointBackgroundColor: "green", //Point Color
pointBorderColor: "green",
borderColor: "green", //Line Color
pointStyle: "point",
data: generateData()
}]
};
$(function () {
var rectangleSet = false;
var canvasTest = $('#chart-Test');
var chartTest = new Chart(canvasTest, {
type: 'line',
data: chartData,
maintainAspectRatio: false,
responsive: true,
options: {
elements:{
point:{
radius:1
}
},
tooltips: {
titleFontSize: 0,
titleMarginBottom: 0,
bodyFontSize: 12
},
legend: {
display: false
},
scales: {
xAxes: [{
ticks: {
fontSize: 12,
display: true
}
}],
yAxes: [{
ticks: {
fontSize: 12,
beginAtZero: true
}
}]
}
}
});
addData(5, chartTest);
});
});
</script>
</head>
<body>
<div class="chartWrapper">
<div class="chartAreaWrapper">
<canvas id="chart-Test" height="300" width="5000"></canvas>
</div>
<canvas id="axis-Test" height="300" width="0"></canvas>
</div>
Thanks in advance, have a nice day!
If i understand correct, you want to show only 5 labels in your x-axis (1, 2, 3 ,4, second). Try this one:
var options = {
scales: {
xAxes: [{
afterTickToLabelConversion: function(data){
var xLabels = data.ticks;
xLabels.forEach(function (labels, i) {
if (i % 1000 != 0){
xLabels[i] = '';
}
});
}
}]
}
}

Binding Highcharts Pie Chart to differently formatted data

I have a pie chart integration in Spotfire which works well when the data is in a simpler format in 'data' and 'columns'. The data binds to the chart properly (this is the kind of format i've seen in most demos).
However in other real-life usages in Spotfire, the JSON which is produced is differently formatted and ceases to draw a pie chart properly. I think it should be possible to adjust the script to bind to this data format, but i don't know how?
In my fiddle it is working with simpler data format, if commenting this out and uncommenting the other data the failed chart can be seen...
https://jsfiddle.net/paulsmithleadershipfactor/3k2gzuw0/
The full code is here also...
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9"/>
<title>JS Visualization Tester with Highcharts</title>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script>
var chart; // Global chart object used to determine whether Highcharts has been intialized
var color = null;
var pie = null;
var svg = null;
var path = null;
function renderCore(sfdata)
{
if (resizing) {
return;
}
// Extract the columns
var columns = sfdata.columns;
columns.shift();
// Extract the data array section
var chartdata = sfdata.data;
// count the marked rows in the data set, needed later for marking rendering logic
var markedRows = 0;
for (var i = 0; i < chartdata.length; i++)
{
if (chartdata[i].hints.marked)
{
markedRows = markedRows + 1;
}
}
var width = window.innerWidth;
var height = window.innerHeight;
var radius = Math.min(width, height) / 2;
if ( !chart )
{
$('#js_chart').highcharts({
chart: {
plotBackgroundColor: '#f1f2f2',
plotBorderWidth: null,
plotShadow: false,
type: 'pie'
},
title: {
text: 'Pie',
},
tooltip: {
formatter: function() {
var sliceIndex = this.point.index;
var sliceName = this.series.chart.axes[0].categories[sliceIndex];
return sliceName + ':' +
'<b>' + this.y + '</b>';
}
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
showInLegend: true,
depth: 35,
innerSize: 100,
dataLabels: {
enabled: true,
format: '{point.y:,.0f}'
}
}
},
legend: {
enabled: true,
labelFormatter: function() {
var legendIndex = this.index;
var legendName = this.series.chart.axes[0].categories[legendIndex];
return legendName;
}
},
xAxis: {
categories: columns
}
});
}
chart = $('#js_chart').highcharts();
for ( var nIndex = 0 ; nIndex < chartdata.length ; nIndex++ )
{
var row = chartdata[nIndex];
// Check for an existing chart data series with the current id
var series = chart.get ( row.items[0] );
var seriesData = [];
for (var c = 1; c < row.items.length; c++) {
seriesData.push(Number(row.items[c]));
}
if ( series != null )
{
// Update the existing series with the new data
series.update ( {
data: seriesData
}, false );
}
else
{
// Create a new series
chart.addSeries ( {
id: row.items[0],
name: row.items[0],
data: seriesData
}, false );
}
}
for ( nSeriesIndex = 0 ; nSeriesIndex < chart.series.length ; nSeriesIndex++ )
{
var series = chart.series[nSeriesIndex];
var found = false;
for ( nDataIndex = 0 ; nDataIndex < chartdata.length ; nDataIndex++ )
{
var row = chartdata[nDataIndex];
if ( series.name == row.items[0] )
{
found = true;
break;
}
}
if ( found != true )
{
series.remove ( false );
nSeriesIndex = 0;
}
}
chart.redraw ();
wait ( sfdata.wait, sfdata.static );
}
var resizing = false;
window.onresize = function (event) {
resizing = true;
if ($("#js_chart")) {
}
resizing = false;
}
</script>
</head>
<body>
<button style="position:absolute; z-index:99" type="button" onclick="call_renderCore()">Call renderCore</button>
<div id="js_chart"></div>
<script type="text/javascript">
function call_renderCore()
{
var sfdata =
{
"columns": ["Sales (Total)", "Marketing (Total)", "Development (Total)", "Customer Support (Total)", "IT (Total)", "Administration (Total)"],
/* comment out the 'columns' above and uncomment 'columns' below */
/* "columns": [
"count([lastcontact])",
"First([lastcontact])"
], */
/* uncomment above and comment below */
"data": [{"items": [93000, 58000, 102000, 66000, 43000, 24000], "hints": {"index": 0}}]
/* comment out the 'data' above and uncomment 'data' below */
/* "data": [
{
"items": [
131,
"3 – 6 months"
],
"hints": {
"index": 0
}
},
{
"items": [
78,
"6 months – 1 year"
],
"hints": {
"index": 1
}
},
{
"items": [
89,
"Can't remember"
],
"hints": {
"index": 2
}
},
{
"items": [
56,
"Over a year ago"
],
"hints": {
"index": 4
}
},
{
"items": [
442,
"Less than 3 months"
],
"hints": {
"index": 3
}
}
], */
}
renderCore ( sfdata );
display_data ( sfdata );
}
</script>
</body>
</html>

ExtJS 4.2 export grid data to downloadable CSV file

I want to create a download button in my EXT JS panel which when click download/exports EXTJS grid into downloadable CSV file.
PS: I think we can use store data or the JSON from which i am filling data in grid store to populate data into CSV file
I have tried Ext.ux.CSVExporter but i wasn't able to use it successfully.
My current code is :
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title id='title'>HTML Page setup Tutorial</title>
<link rel="stylesheet" type="text/css" href="ext-all.css" />
<script type="text/javascript" src="ext-all.js"></script>
<script type="text/javascript" src="FileSaver.js"></script>
<script type="text/javascript" src="Formatter.js"></script>
<script type="text/javascript" src="CSVFormatter/CSVFormatter.js"></script>
<script type="text/javascript" src="ExcelFormatter/Cell.js"></script>
<script type="text/javascript" src="ExcelFormatter/Style.js"></script>
<script type="text/javascript" src="ExcelFormatter/Workbook.js"></script>
<script type="text/javascript" src="ExcelFormatter/Worksheet.js"></script>
<script type="text/javascript" src="ExcelFormatter/ExcelFormatter.js"></script>
<script type="text/javascript" src="Exporter.js"></script>
<script type="text/javascript" src="ExporterButton.js"></script>
<script type="text/javascript">
Ext.define('Ext.ux.ProgressBarPager', {
requires: ['Ext.ProgressBar'],
/**
* #cfg {Number} width
* <p>The default progress bar width. Default is 225.</p>
*/
width : 225,
/**
* #cfg {String} defaultText
* <p>The text to display while the store is loading. Default is 'Loading...'</p>
*/
defaultText : 'Loading...',
/**
* #cfg {Object} defaultAnimCfg
* <p>A {#link Ext.fx.Anim Ext.fx.Anim} configuration object.</p>
*/
defaultAnimCfg : {
duration: 1000,
easing: 'bounceOut'
},
/**
* Creates new ProgressBarPager.
* #param {Object} config Configuration options
*/
constructor : function(config) {
if (config) {
Ext.apply(this, config);
}
},
//public
init : function (parent) {
var displayItem;
if (parent.displayInfo) {
this.parent = parent;
displayItem = parent.child("#displayItem");
if (displayItem) {
parent.remove(displayItem, true);
}
this.progressBar = Ext.create('Ext.ProgressBar', {
text : this.defaultText,
width : this.width,
animate : this.defaultAnimCfg,
style: {
cursor: 'pointer'
},
listeners: {
el: {
scope: this,
click: this.handleProgressBarClick
}
}
});
parent.displayItem = this.progressBar;
parent.add(parent.displayItem);
Ext.apply(parent, this.parentOverrides);
}
},
// private
// This method handles the click for the progress bar
handleProgressBarClick : function(e){
var parent = this.parent,
displayItem = parent.displayItem,
box = this.progressBar.getBox(),
xy = e.getXY(),
position = xy[0]- box.x,
pages = Math.ceil(parent.store.getTotalCount() / parent.pageSize),
newPage = Math.max(Math.ceil(position / (displayItem.width / pages)), 1);
parent.store.loadPage(newPage);
},
// private, overriddes
parentOverrides : {
// private
// This method updates the information via the progress bar.
updateInfo : function(){
if(this.displayItem){
var count = this.store.getCount(),
pageData = this.getPageData(),
message = count === 0 ?
this.emptyMsg :
Ext.String.format(
this.displayMsg,
pageData.fromRecord, pageData.toRecord, this.store.getTotalCount()
),
percentage = pageData.pageCount > 0 ? (pageData.currentPage / pageData.pageCount) : 0;
this.displayItem.updateProgress(percentage, message, this.animate || this.defaultAnimConfig);
}
}
}
});
Ext.onReady(function() {
var field = [];
var columnList = [];
var counter = {
"levels":
[{
"name": "class",
"samples": [{
"name": "1660SH_3",
"features": [{
"count": 8,
"name": "Bacteroidia"
}, {
"count": 9,
"name": "Bacteroidiaa"
},
{
"count": 10,
"name": "Bacteroidiab"
},
{
"count": 11,
"name": "Bacteroidiac"
}]
}, {
"name": "1660SH_4",
"features": [{
"count": 5,
"name": "Bacteroidia"
}, {
"count": 6,
"name": "Bacteroidiaa"
},
{
"count": 7,
"name": "Bacteroidiab"
},
{
"count": 8,
"name": "Bacteroidiac"
}]
}]
}, ]
};
columnList.push({
header: "Sample v/s Feature",
dataIndex: "Sample v/s Feature",
width: 0.1 * Ext.getBody().getViewSize().width,
columnLines: true,
locked: true
});
field.push("Sample v/s Feature");
for (var p = 0; p < Object.keys(counter.levels[0].samples).length; p++) {
columnList.push({
header: counter.levels[0].samples[p].name,
dataIndex: counter.levels[0].samples[p].name,
flex: 1,
columnLines: true
});
field.push(counter.levels[0].samples[p].name);
}
if (counter.levels[0].name == 'class') {
var mydata=[];
for (var p = 0; p < Object.keys(counter.levels[0].samples[0].features).length; p++)
{
var s = [];
s["Sample v/s Feature"] = '<b>' + counter.levels[0].samples[0].features[p].name + '</b>';
for (var j = 0; j < Object.keys(counter.levels[0].samples).length; j++)
{
s[counter.levels[0].samples[j].name] = counter.levels[0].samples[j].features[p].count;
}
mydata.push(s);
}
var store = Ext.create('Ext.data.ArrayStore', {
autoLoad: false,
pageSize : 2,
fields: field,
data: {
count:mydata.length,
data:mydata
},
proxy:{
type:"memory",
enablePaging: true,
data:mydata,
reader: {
type: 'json',
root: 'data',
}
}
});
store.load({
params: {
// specify params for the first page load if using paging
start: 0,
limit: 2,
}
});
var classTable = Ext.create('Ext.grid.Panel', {
style: 'border: solid Blue 1px',
id: 'family',
renderTo: Ext.getBody(),
store: store,
requires: [
'Ext.ux.exporter.Exporter'
],
columns: columnList,
columnLines: true,
width: Ext.getBody().getViewSize().width,
height: Ext.getBody().getViewSize().height,
bbar: {
xtype: 'pagingtoolbar',
pageSize: 2,
store: store,
displayInfo: true,
plugins: new Ext.ux.ProgressBarPager()
},
dockedItems:[
{
xtype: 'toolbar',
dock: 'top',
items: [
{
xtype: 'exporterbutton',
text: 'export data'
}
]
}
]
});
}
});
</script>
</head>
<body>
</body>
</html>
repository link use this project
here is example how to use it fiddle link
first of all copy repository files to you ext library's ux folder located in ext/src/ux under exporter folder. full path will be ext/src/ux/exporter/[repository_files]
and modify your grid
var classTable = Ext.create('Ext.grid.Panel', {
style: 'border: solid Blue 1px',
id: 'family',
renderTo: Ext.getBody(),
store: store,
requires: [
'Ext.ux.exporter.Exporter'
],
columns: columnList,
columnLines: true,
width: Ext.getBody().getViewSize().width,
height: Ext.getBody().getViewSize().height,
bbar: {
xtype: 'pagingtoolbar',
pageSize: 2,
store: store,
displayInfo: true,
plugins: new Ext.ux.ProgressBarPager()
},
dockedItems:[
{
xtype: 'toolbar',
dock: 'top',
items: [
{
xtype: 'exporterbutton',
text: 'exrpot data'
}
]
}
]
});

High Charts windrose from API data (JSON)

I'm quite new here (and to web development in general), so please forgive any misuses that I perpetuate... I'm trying to create a basic windrose plot with data returned (in JSON) from the MesoWest Mesonet API service. I'm using HighCharts (or attempting to), and cannot quite get it to work. Perhaps this is due to my methodology of obtaining the data from the API itself as I'm a complete amateur in this regard. The following is the Javascript code, followed by the HTML for the page. Could someone please take a look and let me know what I've done wrong? Nothing displays on the page when I attempt to load it. In addition, if you're curious as to the specifics of an API call for MesoWest, like the one I've employed here, please see http://mesowest.org/api/docs/
The .js script:
var windrose = {
divname: "windrosediv",
tkn: "eecfc0259e2946a68f41080021724419",
load:function()
{
console.log('loading')
if (!window.jQuery) {
var script = document.createElement("script");
script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js';
script.type = 'text/javascript';
document.getElementByTagName("head")[0].appendChild(script);
setTimeout(pollJQuery, 100)
return
}
this.div = $("#"+this.divname);
this.request('WBB');
},
pollJQuery:function()
{
if (!window.jQuery) {
setTimeout(pollJQuery,100);
} else {
load();
}
},
request:function(stn){
console.log("making a request")
$.getJSON(http://api.mesowest.net/v2/stations/nearesttime?callback=?',
{
stid:stn,
within:1440,
units:'english',
token:windrose.tkn
}, this.receive);
},
receive:function (data)
{
console.log(data,windrose);
stn = data.STATION[0]
dat = stn.OBSERVATIONS
spd += Math.round(dat.wind_speed_value_1.value)
dir += dat.wind_direction_value_1.value
windDataJSON = [];
for (i = 0; i < dir.length; i++) {
windDataJSON.push([ dir[i], spd[i]
]);
},
}
$(function () {
var categories = ['0', '45', '90', '135', '180', '225', '270', '315'];
$('#container').highcharts({
series: [{
data: windDataJSON
}],
chart: {
polar: true,
type: 'column'
},
title: {
text: 'Wind Rose'
},
pane: {
size: '85%'
},
legend: {
align: 'right',
verticalAlign: 'top',
y: 100,
layout: 'vertical'
},
xAxis: {
min: 0,
max: 360,
type: "",
tickInterval: 22.5,
tickmarkPlacement: 'on',
labels: {
formatter: function () {
return categories[this.value / 22.5] + '°';
}
}
},
yAxis: {
min: 0,
endOnTick: false,
showLastLabel: true,
title: {
text: 'Frequency (%)'
},
labels: {
formatter: function () {
return this.value + '%';
}
},
reversedStacks: false
},
tooltip: {
valueSuffix: '%'
},
plotOptions: {
series: {
stacking: 'normal',
shadow: false,
groupPadding: 0,
pointPlacement: 'on'
}
}
});
});
And the HTML:
<!DOCTYPE html>
<html>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/highcharts-more.js"></script>
<script src="https://code.highcharts.com/modules/data.js">`enter code </script>
<script src="https://code.highcharts.com/modules/exporting.js"> </script>
<div id="container" style="min-width: 420px; max-width: 600px; height: 400px; margin: 0 auto"></div>
<p class="ex">
<script type="text/javascript" src="http://home.chpc.utah.edu/~u0675379/apiDemos/windTest.js"></script>
</p>
</html>
I appreciate any guidance in this regard, thanks!!!
-Will
#W.Howard, I think the problem here is how you are treating and preparing the JSON response from the API. Consider the following JavaScript to retrieve and parse out the data:
/*
* Helper function
* scalarMultiply(array, scalar)
*/
function scalarMultiply(arr, scalar) {
for (var i = 0; i < arr.length; i++) {
arr[i] = arr[i] * scalar;
}
return arr;
}
/*
* getQuery(station, api_token)
*/
function getQuery(station, mins, api_token) {
$.getJSON('http://api.mesowest.net/v2/stations/timeseries?callback=?', {
/* Specify the request parameters here */
stid: station,
recent: mins, /* How many mins you want */
obtimezone: "local",
vars: "wind_speed,wind_direction,wind_gust",
jsonformat: 2, /* for diagnostics */
token: api_token
},
function(data) {
try {
windSpeed = data.STATION[0].OBSERVATIONS.wind_speed_set_1;
windDir = data.STATION[0].OBSERVATIONS.wind_direction_set_1;
windGust = data.STATION[0].OBSERVATIONS.wind_gust_set_1;
} catch (err) {
console.log("Data is invalid. Check your API query");
console.log(this.url);
exit();
}
/* Convert from knots to mph */
windSpeed = scalarMultiply(windSpeed, 1.15078);
//windGust = scalarMultiply(windGust, 1.15078);
/* Create and populate array for plotting */
windData = [];
for (i = 0; i < windSpeed.length; i++) {
windData.push([windDir[i], windSpeed[i]]);
}
/* Debug */
// console.log(windData);
console.log(this.url);
plotWindRose(windData, mins);
})
};
What we had now is an 2D array with wind direction and wind speed that we can pass to the plotting function. Below is the updated plotting function:
/*
* Plot the wind rose
* plotWindRose([direction, speed])
*/
function plotWindRose(windData, mins) {
/*
* Note:
* Because of the nature of the data we will accept the HighCharts Error #15.
* --> Highcharts Error #15 (Highcharts expects data to be sorted).
* This only results in a performance issue.
*/
var categories = ["0", "45", "90", "135", "180", "225", "270", "315"];
$('#wind-rose').highcharts({
series: [{
name: "Wind Speed",
color: '#cc3000',
data: windData
}],
chart: {
type: 'column',
polar: true
},
title: {
text: 'Wind Direction vs. Frequency (Last ' + mins/60. + ' hours)'
},
pane: {
size: '90%',
},
legend: {
align: 'right',
verticalAlign: 'top',
y: 100,
text: "Wind Direction"
},
xAxis: {
min: 0,
max: 360,
type: "",
tickInterval: 45,
tickmarkPlacement: 'on',
labels: {
formatter: function() {
return categories[this.value / 45] + '\u00B0';
}
}
},
yAxis: {
min: 0,
endOnTick: false,
showLastLabel: true,
title: {
text: 'Frequency (%)'
},
labels: {
formatter: function() {
return this.value + '%';
}
},
reversedStacks: false
},
tooltip: {
valueSuffix: '%'
},
plotOptions: {
series: {
stacking: 'normal',
shadow: false,
groupPadding: 20,
pointPlacement: 'on'
}
}
});
}
You can see it all here at https://gist.github.com/adamabernathy/eda63f14d79090ab1ea411a8df1e246e . Best of luck!

Categories

Resources