How to take chart target position as input from the user in an Excel VSTO Add-in through a textfield? - vsto

I want to create a Bar chart on Excel Add-in, but I want to get the target position of the chart from the user in a textfield, how can I use that value and assign it to the chart.setPosition ? Is it possible to add the parameter for the setPosition function as a variable that contains the value taken as input from the textfield?
Here is my code:
function createBarChart() {
Excel.run(function (context) {
const sheet = context.workbook.worksheets.getItem("Sheet1");
const salesTable = sheet.tables.getItem("Table1");
const dataRange = salesTable.getDataBodyRange();
let chart = sheet.charts.add("ColumnClustered", dataRange, "Auto");
chart.setPosition("A9", "F20");
chart.title.text = "Farm Sales Bar chart";
chart.legend.position = "Right";
chart.legend.format.fill.setSolidColor("white");
chart.dataLabels.format.font.size = 15;
chart.dataLabels.format.font.color = "black";
let points = chart.series.getItemAt(0).points;
points.getItemAt(0).format.fill.setSolidColor("pink");
points.getItemAt(1).format.fill.setSolidColor("indigo");
return context.sync();
})
.catch(function (error) {
console.log("Error: " + error);
if (error instanceof OfficeExtension.Error) {
console.log("Debug info: " + JSON.stringify(error.debugInfo));
}
});
}

You could use
<input type="text" id="leftTop"/>
<input type="text" id="bottomRight"/>
in the HTML for user to enter the param, and use
let value = $("#leftTop").val();
let lt = String(value);
value = $("#bottomRight").val();
let br = String(value);
chart.setPosition(lt, br);
to parse the textfield into chart.setPosition.
Here's a sample code, you could run it by import into ScriptLab.

Related

Global Variables only Called Once then Lost their Scope

I Have a Problem with my Script and hope helping me, and thanks in advance, i still learning javascript and try to learn somthing new everyday, i have a script that draw modeless interface (palette) and have button including (option) that make another new palette (for options), i made the variables as globals for the option palette, but the problem is the global variables is only called once!, and the script lose the global variable scope!.
enter image description here
so my question is how to make the variables not losing its scope and retain in the memory? as long the script run, as an Example if the user move the slider and hit (Show alert due options) its only run once and then lose the scope, even the slider no longer interact with the user and update text box, please test the code to see the problem, and thank again for any help or advice.
Best
M.Hasanain
//Global Variables only Called Once then Lost their Scope!
#targetengine "session1";
var w = new Window("palette", {independent:true}); //Main Palette Windows
var findoptions = new Window("palette"); //Options Palette
function Main() {
// Check to see whether any InDesign documents are open.
// If no documents are open, display an error message.
if (app.documents.length > 0) {
var myDoc = app.activeDocument;
}else{
// No documents are open, so display an error message.
alert("No InDesign documents are open. Please open a document and try again.");
}
}
//---------------------------------------------------------
//Making Palettes Windows
//---------------------------------------------------------
#targetengine "session1";
var w = new Window("palette", {independent:true}); //Main Palette Windows
var findoptions = new Window("palette"); //Options Palette
//gqmanager is the (GREP Query Manager) outside the main Function
w.text = "Test the Connection Between Global Variables and Palettes";
w.preferredSize.width = 500;
w.alignChildren = ["center", "center"]; //"left";
w.orientation = "column"; //"row";
w.spacing = 10;
w.margins = 16;
//Parent - Input Panel Prepare
var InputPanel = w.add("panel", undefined, undefined, { name: "panel1" });
InputPanel.text = "Text Find : ";
InputPanel.preferredSize.width = 1000;
InputPanel.orientation = "row";
InputPanel.alignChildren = ["center", "center"];
InputPanel.spacing = 10;
InputPanel.margins = 16;
//Children - input Panel Inside Prepare
var myInputPanelInside = InputPanel.add("group", undefined, { name: "myInput" });
//--Adding Find What
myInputPanelInside.add("statictext", undefined, "Find What :");
//myInputPanelInside.alignment = "center";
var myGREPString = myInputPanelInside.add("edittext", undefined, "SAMPLE");
myGREPString.helpTip = "Enter Your Text"
myGREPString.characters = 20;
myGREPString.enabled = true;
myGREPString.preferredSize.width = 460;
var Button1 = myInputPanelInside.add("button", undefined, "Options");
//Parent - Radio Panel Prepare
var RadioPanel = w.add("panel", undefined, undefined, { name: "panel2" });
RadioPanel.text = "Select Desired Option : ";
RadioPanel.preferredSize.width = 1000;
RadioPanel.orientation = "row";
RadioPanel.alignChildren = ["center", "center"];
RadioPanel.spacing = 10;
RadioPanel.margins = 16;
//Children - input Panel Inside Prepare
var myRadioPanelInside = RadioPanel.add("group", undefined, { name: "myRadio" });
myRadioPanelInside.preferredSize.width = 500;
myRadioPanelInside.alignChildren = ["center", "center"];
//Adding Radio Buttons
var radio1 = myRadioPanelInside.add("radiobutton", undefined, "Option 1");
var radio2 = myRadioPanelInside.add("radiobutton", undefined, "Option 2");
var radio3 = myRadioPanelInside.add("radiobutton", undefined, "Option 3");
radio1.preferredSize.width = 200;
radio2.preferredSize.width = 200;
radio3.preferredSize.width = 200;
//Previous Default Condition
radio1.value = true;
var myButtonGroup = w.add("group");
myButtonGroup.alignment = "center";
var Button2 = myButtonGroup.add("button", undefined, "Show Alert Due Options");
var Button3 = myButtonGroup.add("button", undefined, "Exit");
Button1.onClick = function () {
CalltheFindOptions();
}
Button2.onClick = function () { Find(); };
function Find() {
doRadioButtonOpt();
}
Button3.onClick = function() {Canceled();};
function Canceled() {
ExitSure();
}
//After Drawing Interface
var a = w.show();
function ExitSure() {
var a = w.close();
exit(0);
}
//User Selection for Radio Buttons
function doRadioButtonOpt() {
myDoc = app.activeDocument;
if (radio1.value == true) {
TestVars();
}
}
function TestVars() {
#targetengine "session1";
var myDoc = app.activeDocument
var TimeMs = Number(SliderControlText.text); //Converting Text to Number
//Show Results Found as User Wish
if (DontShowResults.value == true) { //no Show only Apply
alert("you Select not to Show Results!");
}else{ //Direct Show and Apply
if (ShowResultsDirect.value == true) {
alert("you Select to Show Results in real time!");
}else{ //Show and Apply By WaitinhTime!
if (ShowResults.value == true) { //Show and Apply
alert("you Select to Show Results with Specific time!");
$.sleep(TimeMs); //Wait ms
}
}
}
alert("Do you need somthing else?, try again", "Finish Report");
}
var DontShowResults;
var ShowResultsDirect;
var ShowResults;
var SliderControlText;
var slider;
//--------------------------------------------Building the Find Options Palette-----------------------------------------//
//--------------------------------------------------------------------------------------------------------------------------------//
function CalltheFindOptions() {
#targetengine "session1";
//Find Options Window
findoptions.text = "Find Options";
//Parent - Input Panel Prepare
SelectPanel = findoptions.add("panel", undefined, undefined, { name: "panel1" });
SelectPanel.text = " Find Options : ";
SelectPanel.preferredSize.width = 1000;
SelectPanel.orientation = "row";
SelectPanel.alignChildren = ["center", "center"];
SelectPanel.spacing = 10;
SelectPanel.margins = 16;
//Children - input Panel Inside Prepare
mySelectPanelInside = SelectPanel.add("group", undefined, { name: "mySelOpt" });
DontShowResults = mySelectPanelInside.add("checkbox", undefined, "Don't Show Results");
DontShowResults.value = true; //by Default
DontShowResults.alignment = "left";
ShowResultsDirect = mySelectPanelInside.add("checkbox", undefined, "Show Results");
ShowResultsDirect.value = false; //by Default
ShowResults = mySelectPanelInside.add("checkbox", undefined, "Show Results Delayed in milliseconds(Ms) :");
ShowResults.value = false; //by Default
//Adding Slider to Control MS Time
SliderControlText = mySelectPanelInside.add ("edittext", undefined, 10, {readonly: false}); //read only prevent user Entering Nums
SliderControlText.characters = 3;
slider = mySelectPanelInside.add ("slider {minvalue: 1, maxvalue: 100, value: 10}");
//Slider Listener Plus SliderControl Text Listener
slider.onChanging = function () {SliderControlText.text = slider.value;} //Listen to Slider
var c = findoptions.show();
}
If I understand you correctly you need to use as global variables values rather than the objects. And you can change the values of global variables by onClick events.
Here is the bottom part of your code (the rest part of the code wasn't changed):
...
function TestVars() {
#targetengine "session1";
var myDoc = app.activeDocument
var TimeMs = Number(SliderControlText_text); //Converting Text to Number
//Show Results Found as User Wish
if (DontShowResults_value == true) { //no Show only Apply
alert("you Select not to Show Results!");
} else { //Direct Show and Apply
if (ShowResultsDirect_value == true) {
alert("you Select to Show Results in real time!");
} else { //Show and Apply By WaitinhTime!
if (ShowResults_value == true) { //Show and Apply
alert("you Select to Show Results with Specific time!");
$.sleep(TimeMs); //Wait ms
}
}
}
alert("Do you need somthing else?, try again", "Finish Report");
}
// values! not objects
var DontShowResults_value = true;
var ShowResultsDirect_value = false;
var ShowResults_value = false;
var SliderControlText_text = '10';
var slider_value = 10;
//--------------------------------------------Building the Find Options Palette-----------------------------------------//
//--------------------------------------------------------------------------------------------------------------------------------//
function CalltheFindOptions() {
#targetengine "session1";
//Find Options Window
findoptions.text = "Find Options";
//Parent - Input Panel Prepare
SelectPanel = findoptions.add("panel", undefined, undefined, {
name: "panel1"
});
SelectPanel.text = " Find Options : ";
SelectPanel.preferredSize.width = 1000;
SelectPanel.orientation = "row";
SelectPanel.alignChildren = ["center", "center"];
SelectPanel.spacing = 10;
SelectPanel.margins = 16;
//Children - input Panel Inside Prepare
var mySelectPanelInside = SelectPanel.add("group", undefined, {
name: "mySelOpt"
});
var DontShowResults = mySelectPanelInside.add("checkbox", undefined, "Don't Show Results");
DontShowResults.value = DontShowResults_value; //by Default
DontShowResults.alignment = "left";
// change the global variable by click
DontShowResults.onClick = function() { DontShowResults_value = DontShowResults.value }
var ShowResultsDirect = mySelectPanelInside.add("checkbox", undefined, "Show Results");
ShowResultsDirect.value = false; //by Default
// change the global variable by click
ShowResultsDirect.onClick = function() { ShowResultsDirect_value = ShowResultsDirect.value }
var ShowResults = mySelectPanelInside.add("checkbox", undefined, "Show Results Delayed in milliseconds(Ms) :");
ShowResults.value = ShowResults_value; //by Default
// change the global variable by click
ShowResults.onClick = function() { ShowResults_value = ShowResults.value }
//Adding Slider to Control MS Time
// SliderControlText = mySelectPanelInside.add("edittext", undefined, 10, {
var SliderControlText = mySelectPanelInside.add("edittext", undefined, SliderControlText_text, {
readonly: false
}); //read only prevent user Entering Nums
SliderControlText.characters = 3;
var slider = mySelectPanelInside.add("slider {minvalue: 1, maxvalue: 100, value: 10}");
// change slider every time as numbers is changes
SliderControlText.onChanging = function() {slider.value = SliderControlText.text};
//Slider Listener Plus SliderControl Text Listener
slider.onChanging = function () {
SliderControlText.text = slider.value;
// change the global variable by onChange
SliderControlText_text = SliderControlText.text;
} //Listen to Slider
findoptions.show();
}
It seems it works as intended.
As far as I can tell (I can be wrong), the cause of the problem was that the objects ShowResultsDirect, ShowResultsDirect, etc, disappears as soon as you close the palette. Because they are elements of the palette. They can't keep values if the palette is closed. That why they worked well only when you open the palette first time.

Hide/Show the corresponding data from the chart on legend click ngx-charts

I am working with angular 6 and ngx-chart and I need on clicking the legend item, the corresponding data from the chart should show/hide
The ng-chart library does have this functionality and my client requests it.
Edit01:
I have almost everything working but I have a problem when applying axisFormat. once I remove an item from the legend it reformats the x-axis and doesn't literally put how the data comes without applying the AxisFormat. Any solution?
onSelect (event) {
let temp = JSON.parse(JSON.stringify(this.multi));
this.sourceData = JSON.parse(JSON.stringify(this.multi2));
if (this.isDataShown(event)) {
//Hide it
temp.some(pie => {
const pie2 = pie.name[0] + ',' + pie.name[1];
// console.log('pie', pie[0], event, pie2);
if (pie2 === event) {
pie.series = [];
return true;
}
});
} else {
//Show it back
console.log('Entramos en el ELSE');
const pieToAdd = this.sourceData.filter(pie => {
const pie2 = pie.name[0] + ',' + pie.name[1];
return pie2 === event;
});
temp.some(pie => {
const pie2 = pie.name[0] + ',' + pie.name[1];
if (pie2 === event) {
pie.series = pieToAdd[0].series;
return true;
}
});
}
console.log('log temp: ' + JSON.stringify(temp));
this.multi = temp;
// this.axisFormat(this.multi);
}
isDataShown = (name) => {
const selectedPie = this.multi.filter(pie => {
const pie2 = pie.name[0] + ',' + pie.name[1];
return pie2 === name && pie.series[0] !== undefined;
});
return selectedPie && selectedPie.length > 0;
}
axisFormat(val) {
const options = { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' };
// Esto funciona pero al hacer timeline no pone horas val.toLocaleDateString("es-ES", options);
console.log('val:', val.toLocaleDateString('es-ES', options));
return val.toLocaleDateString('es-ES', options);
}
HTML
<ngx-charts-line-chart [view]="" [scheme]="colorScheme" [results]="multi" [gradient]="gradient" [xAxis]="showXAxis" [yAxis]="showYAxis" [legend]="showLegend" legendPosition="'below'" [showXAxisLabel]="showXAxisLabel" [showYAxisLabel]="showYAxisLabel"
[xAxisLabel]="xAxisLabel" [yAxisLabel]="yAxisLabel" [autoScale]="autoScale" [timeline]="timeline" [roundDomains]="true" [animations]="animations" (select)="onSelect($event)" [xAxisTickFormatting]="axisFormat">
<ng-template #seriesTooltipTemplate let-items="model">
<p>{{items[0].name | date:'medium'}}</p>
<ul>
<li *ngFor="let item of items">
{{item.series}}: {{item.value | number}}
</li>
</ul>
</ng-template>
</ngx-charts-line-chart>
EDIT
Hello,
I have already managed to solve the problem adding an example in case it can help other people.
https://stackblitz.com/edit/click-lengd-ngx-charts
I am kinda new to Stack Overflow, but i think you should specify your answer more and show us what you already tried. Nevertheless I will try to help you.
You should give your chart a (select)="onClickFunction ($event)" in HTML. In your TS you then call the onClickFunction(event). I always start with giving it a console.log(event) to see what i get from clicking on the legend.
After clicking on the legend, you get the label of the element you clicked on. You can then search for this label in your data and remove this data out of the array you use for filling the chart.
If you provide a stackblitz or plunker wtih your code, I will gladly show you how to do it.
This is how we can achieve it for ngx-pie-chart. With the help of select event, capture it, identify the item from the data and make it zero. Next, on the next click, add the value back from the source copy. See it working here ngx-pie-chart label-filter
onSelect (event) {
let temp = JSON.parse(JSON.stringify(this.single));
if (this.isDataShown(event)) {
//Hide it
temp.some(pie => {
if (pie.name === event) {
pie.value = 0;
return true;
}
});
} else {
//Show it back
const pieToAdd = this.sourceData.filter(pie => {
return pie.name === event;
});
temp.some(pie => {
if (pie.name === event) {
pie.value = pieToAdd[0].value;
return true;
}
});
}
this.single = temp;
}
isDataShown = (name) => {
const selectedPie = this.single.filter(pie => {
return pie.name === name && pie.value !== 0;
});
return selectedPie && selectedPie.length > 0;
}

How to Add and Display images in Identifier Popup

I have an identifier if I click on particular point it will display all the information of that point.Now the problem is to need to add image for each point if I click on that point it will display information as well as image.Currently I am using
map.on("load", mapReady);
var parcelsURL = "My Server";
//map.addLayer(new ArcGISDynamicMapServiceLayer(parcelsURL,
// { opacity: 20 }));
function mapReady() {
map.on("click", executeIdentifyTask);
//create identify tasks and setup parameters
identifyTask = new IdentifyTask(parcelsURL);
identifyParams = new IdentifyParameters();
identifyParams.tolerance = 3;
identifyParams.returnGeometry = true;
identifyParams.layerIds = [0];
identifyParams.layerOption = IdentifyParameters.LAYER_OPTION_ALL;
identifyParams.width = map.width;
identifyParams.height = map.height;
}
function executeIdentifyTask(event) {
identifyParams.geometry = event.mapPoint;
identifyParams.mapExtent = map.extent;
var deferred = identifyTask
.execute(identifyParams)
.addCallback(function (response) {
// response is an array of identify result objects
// Let's return an array of features.
return arrayUtils.map(response, function (result) {
var feature = result.feature;
var layerName = result.layerName;
feature.attributes.layerName = layerName;
if (layerName === 'GridPoint') {
var taxParcelTemplate = new InfoTemplate("",
"XX: ${XX} <br/> YY: ${YY} <br/> Sample Point Number: ${Sample Point Number} <br/> Point Collected: ${Point Collected} <br/> Major Rabi Crops: ${ Major Rabi Crops} <br/> Major Summer Crop: ${Major Summer Crop} <br/> Soil Type: ${Soil Type} <br/> Major Kharif Crops: ${Major Kharif Crops}");
feature.setInfoTemplate(taxParcelTemplate);
}
//else if (layerName === 'Grid') {
// console.log(feature.attributes.objectid);
// var buildingFootprintTemplate = new InfoTemplate("",
// "OBJECTID: ${OBJECTID}");
// feature.setInfoTemplate(buildingFootprintTemplate);
//}
return feature;
});
});
map.infoWindow.setFeatures([deferred]);
map.infoWindow.show(event.mapPoint);
}
can someone please help me to solve this problem.I am using http://developers.arcgis.com/javascript/sandbox/sandbox.html?sample=find_drilldown
Adding an image is really simple. Just add it to the infoTemplate. Here is an example of an image added to the guide you referenced above. The only thing that was added was line 101:
template += "<img src='http://webapps-cdn.esri.com/Apps/MegaMenu/img/logo.jpg' /><br>";
Where the src would obviously be to the image.
If you want help with your code in particular, create a fiddle so it will be easier to work with.

How to check if Form data have been modified?

I have a pretty complicated form and I don't want to make all the database queries, just because someone entered the update page.
How I would know if the content inside the form has been modified?
I don't use knockout.js and don't want to implement it.
You could use javascript. For example once the form is rendered you could calculate a checksum and before submitting it recalculate this checksum and compare the 2 values. Then you could set the value of a hidden field so that when the form is submitted to the server you would know whether something was modified:
String.prototype.hashCode = function() {
var hash = 0;
if (this.length == 0) return hash;
for (i = 0; i < this.length; i++) {
char = this.charCodeAt(i);
hash = ((hash<<5) - hash) + char;
hash = hash & hash;
}
return hash;
};
$(function() {
var $form = $('form');
$form.data('checksum', $form.serialize().hashCode())
$form.submit(function() {
var initialChecksum = $(this).data('checksum');
var currentChecksum = $(this).serialize();
var isDirty = initialChecksum != currentChecksum;
$('#isDirty').val(isDirty);
});
});
and your view model could have an IsDirty boolean property that you could query in the controller action that is processing the form submission.
maybe with some jQuery. assign some classes to field and fire the change event and put the name of the changed field in some hidden field, then you can have the field which have changed on server side.
<input type="hidden" id="changedNames" name ="changedNames" />
$(function () {
$('.observe').change(function (e) {
var thisName = $(this).attr('name');
$('#changedNames').val($('#changedNames').val() + thisName + " ");
});
});

Not updating list in the panel at the run time in sencha

i have two panel. when i'm click on the left panel items its calling web service and populating the right panel and same time its updating the number of items in the right panel to the left panel item which is clicked.
for first time its updating the left panel items but when i click on the other left panel item its not updating left panel items again.
its updating only first time.
my code is:
onInboxListTap:function (dataview, index, item, record) {
console.log('Inside onInboxListTap function');
var queuestore = dataview.getStore();
var rec = queuestore.getAt(index);
console.log(rec.data.workSetName);
var store = Ext.getStore('InboxWorkitemStore');
store.clearData(); //Function To clear WorkitemStore
//creating object of InboxQueueServices class
var inboxQueueServiceObject =
Ext.create('InfoImage.common.services.InboxQueueServices', {
config:{
scope:this
}
}, this.onQueueContentRetrievalSuccess, this.onQueueContentRetrievalFailure());
// calling loadQueueContent function to load queue contents
inboxQueueServiceObject.loadQueueContent(rec.data.workSetName);
},
//To call Function onQueueContentRetrievalSuccess after loadQueueContent successful
onQueueContentRetrievalSuccess:function () {
console.log('Inside onQueueContent Retrieval Success function');
var store = Ext.getStore('InboxWorkitemStore');
//Getting componenet queueDetails list
var inboxWorkitemList = Ext.getCmp('inboxWorkitemList');
var queueDetails = Ext.getCmp('queueDetails');
var queueList = Ext.getCmp('queuelist'); //Getting component list
var queueViewPanel = Ext.getCmp('queueViewPanel'); //Getting queueViewPanel
queueDetails.setStore(store);
store.sync();
var queueCount = store.getCount();
if (queueCount > 0) {
var queueItem = store.getAt(0);
var queueStore = queueList.getStore();
queueStore.each(function (record) {
if (record.get('workSetName') == queueItem.get('sourceWorkstep')) {
record.data.queueName = queueItem.get('sourceWorkstep') + '(' +
queueCount + ')';
}
});
queueList.setStore(queueStore);
queueStore.sync();
queueList.getStore().each(function (record) {
console.log('queueList:' + record.data.queueName);
});
console.log('store UPDATED');
}
queueList.refresh();
console.log('store count: ' + store.getCount());
console.log(queueDetails);
// navigates the panel
queueViewPanel.animateActiveItem(
inboxWorkitemList, {
type:'slide',
direction:'up',
duration:250
});
},
Please help me on this isssue.
i have to set record for that i resolve it.
queueStore.each(function (record) {
if (record.get('workSetName') == workitem.get('sourceWorkset')) {
record.data.queueName = workitem.get('sourceWorkset')
+ '(' + queueCount + ')';
// queueStore.updateRecord(record.data.queueName);
record.set(record.data.queueName);
}
});