Updating an existing "save layers to file" PS script - photoshop

I just downloaded a couple scripts to save layers in batch in photoshop. They both work well but for 1 of my specific purposes (saving with an overlay group for t-shirt mock ups) only 1 works well. The problem is it just saves each file with incremental numbers. I would prefer it to behave like the other script, which uses the layer name.
Could someone help me make that change? I have attached both scripts. I am hoping it would be as easy as taking a portion of the code from the one and putting it in the other. I just do not know how to do that. Thanks!
(her is the code that needs the layer naming function)
// Name: Export Layers Inside Selected Group.jsx
// Description: Photoshop script that separately saves top level layers inside the selected group.
// https://gist.github.com/joonaspaakko/013a223e94ba0fb9a2a0
#target photoshop
try {
var doc = app.activeDocument;
var docName = doc.name.split('.')[0];
}
catch (e) {
alert( 'Open a document first...' );
}
function init() {
var savefiles;
dlg.g.saveAs.minimumSize.width = 463;
dlg.btns.minimumSize.height = 142;
dlg.btns.save.onClick = function(){
savefiles = true;
dlg.close();
return savefiles;
};
dlg.show();
if ( savefiles ){
var getDestination = Folder.selectDialog( 'Select destination folder...', doc.saved ? doc.path : '' );
var group = doc.activeLayer;
var groupLength = group.layers.length;
for( var i = 0 ; i < groupLength; i++ ){
group.layers[i].visible = false;
}
for( var i = 0 ; i < groupLength; i++ ){
var layer = group.layers[ i ];
var layerIndex = i+1;
layer.visible = true;
save.file( dlg, doc, getDestination, layerIndex );
layer.visible = false;
}
alert('Files Saved!');
}
}
var save = {
file: function( dlg, doc, getDestination, layerIndex ) {
var saveOptions = {};
var formats = ["psd", "pdf", "png", "jpg", "tiff"];
for ( var i=0; i < formats.length; i++ ) {
if ( dlg.g.saveAs[ formats[i] ].value ) {
var fileformat = formats[i];
var path = getDestination + "/" + fileformat;
makeFolder( path );
doc.saveAs( File( path + "/" + dlg.g.filename.filename.text + layerIndex ), save[fileformat](), true );
}
}
},
psd: function() {
var psd_saveOpts = new PhotoshopSaveOptions();
psd_saveOpts.layers = true;
psd_saveOpts.embedColorProfile = true;
psd_saveOpts.annotations = true;
psd_saveOpts.alphaChannels = true;
return psd_saveOpts;
},
pdf: function() {
var presetName = '[High Quality Print]';
var pdf_SaveOpts = new PDFSaveOptions();
pdf_SaveOpts.pDFPreset = presetName;
return pdf_SaveOpts;
},
jpg: function() {
var jpg_SaveOpts = new JPEGSaveOptions();
jpg_SaveOpts.matte = MatteType.WHITE;
jpg_SaveOpts.quality = 10;
jpg_SaveOpts.formatOptions.STANDARDBASELINE;
return jpg_SaveOpts;
},
png: function() {
var png_SaveOpts = new PNGSaveOptions();
png_SaveOpts.compression = 9;
png_SaveOpts.interlaced = false;
return png_SaveOpts;
},
tiff: function() {
var tiff_SaveOpts = new TiffSaveOptions();
tiff_SaveOpts.alphaChannels = true;
tiff_SaveOpts.annotations = true;
tiff_SaveOpts.imageCompression = TIFFEncoding.JPEG;
tiff_SaveOpts.interleaveChannels = true;
tiff_SaveOpts.jpegQuality = 10;
tiff_SaveOpts.layers = true;
tiff_SaveOpts.layerCompression = LayerCompression.ZIP;
tiff_SaveOpts.transparency = true;
return tiff_SaveOpts;
}
};
// Prepare dialog...
var dlg = new Window("dialog { \
text: 'Export layers inside the selected group', \
alignChildren:['left','center'], \
orientation: 'row', \
g: Group { \
orientation:'column', \
alignChildren: ['left','center'], \
filename: Panel { \
orientation:'column', \
alignChildren: ['left','top'], \
filename_text: StaticText { alignment:'left', text: 'Filename ( Incremental numbers added automatically ): '}, \
filename: EditText { alignment:'left', preferredSize: [430,20], text: '"+ docName +"', active: true }, \
}, \
saveAs: Panel { \
margins: 20, \
spacing: 20, \
orientation: 'row', \
alignChildren: ['left','top'], \
saveAs_txt: StaticText { text: 'Save as: '}, \
jpg: Checkbox { text: 'jpg', value: true }, \
psd: Checkbox { text: 'psd', value: false }, \
pdf: Checkbox { text: 'pdf', value: false }, \
png: Checkbox { text: 'png', value: false }, \
tiff: Checkbox { text: 'tiff', value: false } \
} \
}, \
btns: Panel { \
margins: 20, \
spacing: 20, \
orientation: 'column', \
alignment: ['right','top'], \
save: Button { text: 'Save', properties:{ name: 'ok' }, preferredSize:[88, 24] }, \
cancel: Button { text: 'Cancel', properties:{ name: 'cancel' }, preferredSize:[88, 24] }, \
} \
}");
function makeFolder( path ) {
var newFolder = Folder( path );
if( !newFolder.exists ) newFolder.create();
}
if ( app.documents.length > 0 ) {
if ( app.activeDocument.activeLayer.layers ) {
init();
}
else {
alert( "Error: \nSelect a parent group of the layers you want to export.")
}
}

You may try the Export As... function. In Layer Panel, select all layers/group you want to save, right click then choose Export As.... This will use layer's name to save every selected layers.
Edit: if you really want to do it by script, try editing these lines:
for( var i = 0 ; i < groupLength; i++ ){
var layer = group.layers[ i ];
var layerIndex = i+1; // <-- current using Index, skip it
var layerName = layer.name; // <-- get the Layer Name
layer.visible = true;
save.file( dlg, doc, getDestination, layerName ); // <-- change to layerName
layer.visible = false;
}

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.

Arguments passed to WorkerScript source

I need to load documents which filepath is provided by a FileDialog. The document are rather long to load so I want to display a BusyIndicator while loading the docs. In order to get the UI spinned while loading my doc I need to load my docs in a WorkerScript. Now I need to provide my filepath to the functions in the .js file pointed by WorkerScript::source. I could not find any way to do so.
Any idea?
Here is my source code:
WorkerScript
{
id: importScanWorkerScript
source: "script.js"
}
FileDialog
{
id: importScanDialog
visible: false
title: "Import a [scan] file"
folder: "/home/arennuit/Desktop/living_room_traj0n_scannedScene"
nameFilters: [ "STL files (*stl)" ]
selectedNameFilter: "STL files (*stl)"
onAccepted:
{
importScanDialog.visible = false;
busyIndicator.running = true;
uiController.onImportScanDevMenuClicked(importScanDialog.fileUrl);
busyIndicator.running = false;
}
}
BusyIndicator
{
id: busyIndicator
running: false
anchors.centerIn: parent
}
WorkerScript allows you to send custom object to a thread and also to get a custom object back, I guess the documentation is pretty clear. So the answer to your question is WorkerScript.sendMessage(). In the simple example below the WorkerScript receives random number of iterations from main.qml and so generates and sent back generated text, displayed by main.qml. The GUI doesn't freeze while waiting:
main.qml
import QtQuick 2.9
import QtQuick.Window 2.0
import QtQuick.Controls 2.2
Window {
id: window
width: 600
height: 400
visible: true
ScrollView {
id: view
anchors.fill: parent
clip: true
TextArea {
id: myText
text: ""
enabled: false
}
}
Component.onCompleted: {
var cnt = 1000 + Math.round(Math.random() * 1000);
myText.text = "Please wait, generating text (" + cnt + " characters) ...";
myWorker.sendMessage({count: cnt});
}
WorkerScript {
id: myWorker
source: "script.js"
onMessage: {
myText.text = messageObject.reply;
myText.enabled = true;
spinner.running = false;
}
}
BusyIndicator {
id: spinner
anchors.centerIn: parent
running: true
}
}
script.js
function pause(millis)
{
var date = new Date();
var curDate = null;
do {
curDate = new Date();
} while((curDate - date) < millis);
}
WorkerScript.onMessage = function(message) {
var txt = "";
var count = message.count;
for(var i = 0;i < count;i ++)
{
var ch = 97 + Math.round(Math.random() * 25);
txt += String.fromCharCode(ch);
var eol = Math.round(Math.random() * 30);
if(eol === 1)
txt += "\r\n";
else if(!(eol % 5))
txt += " ";
pause(10);
}
WorkerScript.sendMessage({ 'reply': txt })
}

PDF export from icCube reporting with custom widget

PDF export for custom widget doesn't work from icCube reporting. Server engine version is 5.0.3 and reporting 5.0.3 (6:2163).
We didn't see any error message within the logs, the process remains stuck into the Monitoring -> Active Requests tab.
The report included is based on icCube demo Sales schema.
Widget code:
FishboneChart.js:
test = {
module : {}
}
test.module.FishboneChart = (function (_super) {
__extends(FishboneChart, _super);
function FishboneChart(container, options) {
_super.call(this, container, options);
this.options = options;
this.container = container;
var chartContainer = $("<div class='ic3w-fishbone-chart'></div>");
var contentContainer = $("<div class='ic3w-fishbone-chart-content'></div>");
var ct = $(this.container);
ct.append(chartContainer);
chartContainer.append(contentContainer);
};
$.extend(FishboneChart.prototype, {
buildInHtml : function (gviTable) {
var chartData = buildChartDataJson(gviTable);
renderFishboneChart(chartData);
}
});
return FishboneChart;
})(viz.GviChartBase);
test.module.FishboneChartAdapterFactory = (function (_super) {
__extends(FishboneChartAdapterFactory, _super);
function FishboneChartAdapterFactory() {
_super.call(this, "test.module.FishboneChartAdapter");
}
FishboneChartAdapterFactory.prototype.getId = function () {
return 'testFishboneChart';
};
FishboneChartAdapterFactory.prototype.getMenuGroupName = function () {
return "testMenu"
};
FishboneChartAdapterFactory.prototype.getTag = function () {
return "testFishboneChart"
};
return FishboneChartAdapterFactory;
})(ic3.WidgetAdapterFactory);
test.module.FishboneChartAdapter = (function (_super) {
__extends(FishboneChartAdapter, _super);
function FishboneChartAdapter(context) {
_super.call(this, context);
this.classID = "test.module.FishboneChartAdapter";
}
FishboneChartAdapter.prototype.reportTypeName = function () {
return 'Test fishbone-chart';
};
FishboneChartAdapter.prototype.getWidgetGroupName = function() {
return 'chart';
};
FishboneChartAdapter.prototype.getNameForCssClass = function() {
return 'test-chart';
};
FishboneChartAdapter.prototype.gutsMeta = function () {
return [
{
name: 'title',
type: 'text'
}
]
};
FishboneChartAdapter.prototype.createWidget = function (options, container) {
return new test.module.FishboneChart(container, options);
};
return FishboneChartAdapter;
})(ic3.ChartAdapter);
var initializeFishbone = function(d3){
"use strict";
d3.fishbone = function(){
var _margin = 50,
_marginRoot = 20,
_marginTail = 100,
_marginTop = 30,
_nodes,
_links,
_node,
_link,
_root,
_arrowId = function(d){ return "arrow"; },
_children = function(d){ return d.children; },
_label = function(d){ return d.name; },
_perNodeTick = function(d){},
_linkScale = d3.scale.log()
.domain([1, 5])
.range([20, 10]),
_chartSize = getChartSize(),
_force = d3.layout.force()
.gravity(0)
.size([
_chartSize.width,
_chartSize.height
])
.linkDistance(_linkDistance)
.chargeDistance([10])
.on("tick", _tick);
var fb1 = function($){
_links = [];
_nodes = [];
_build_nodes($.datum());
_force
.nodes(_nodes)
.links(_links);
_link = $.selectAll(".link")
.data(_links);
_link.enter().append("line");
_link
.attr({
"class": function(d){ return "link link-" + d.depth; },
"marker-end": function(d){
return d.arrow ? "url(#" + _arrowId(d) + ")" : null;
}
});
_link.exit().remove();
_node = $.selectAll(".node").data(_nodes);
_node.enter().append("g")
.attr({
"class": function(d){ return "node" + (d.root ? " root" : ""); }
})
.append("text");
_node.select("text")
.attr({
"class": function(d){ return "label-" + d.depth; },
"text-anchor": function(d){
return !d.depth ? "start" : d.horizontal ? "end" : "middle";
},
dy: function(d){
return d.horizontal ? ".35em" : d.region === 1 ? "1em" : "-.2em";
}
})
.text(_label);
_node.exit().remove();
_node
.call(_force.drag)
.on("mousedown", function(){ d3.event.stopPropagation(); });
_root = $.select(".root").node();
};
function _arrow($){
var defs = $.selectAll("defs").data([1]);
defs.enter().append("defs");
defs.selectAll("marker#" + _arrowId())
.data([1])
.enter().append("marker")
.attr({
id: _arrowId(),
viewBox: "0 -5 10 10",
refX: 10,
refY: 0,
markerWidth: 10,
markerHeight: 10,
orient: "auto"
})
.append("path")
.attr({d: "M0,-5L10,0L0,5"});
}
function _build_nodes(node){
_nodes.push(node);
var cx = 0;
var between = [node, node.connector],
nodeLinks = [{
source: node,
target: node.connector,
arrow: true,
depth: node.depth || 0
}],
prev,
childLinkCount;
if(!node.parent){
_nodes.push(prev = {tail: true});
between = [prev, node];
nodeLinks[0].source = prev;
nodeLinks[0].target = node;
node.horizontal = true;
node.vertical = false;
node.depth = 0;
node.root = true;
node.totalLinks = []
}else{
node.connector.maxChildIdx = 0;
node.connector.totalLinks = [];
}
node.linkCount = 1;
(_children(node) || []).forEach(function(child, idx){
child.parent = node;
child.depth = (node.depth || 0) + 1;
child.childIdx = idx;
child.region = node.region ? node.region : (idx & 1 ? 1 : -1);
child.horizontal = !node.horizontal;
child.vertical = !node.vertical;
if(node.root && prev && !prev.tail){
_nodes.push(child.connector = {
between: between,
childIdx: prev.childIdx
})
prev = null;
}else{
_nodes.push(prev = child.connector = {between: between, childIdx: cx++});
}
nodeLinks.push({
source: child,
target: child.connector,
depth: child.depth
});
childLinkCount = _build_nodes(child);
node.linkCount += childLinkCount;
between[1].totalLinks.push(childLinkCount);
});
between[1].maxChildIdx = cx;
Array.prototype.unshift.apply(_links, nodeLinks);
return node.linkCount;
}
function _linePosition($){
$.attr({
x1: function(d){ return d.source.x; },
y1: function(d){ return d.source.y; },
x2: function(d){ return d.target.x; },
y2: function(d){ return d.target.y; }
})
}
function _nodePosition($){
$.attr("transform", function(d){
return "translate(" + d.x + "," + d.y + ")";
})
}
function _linkDistance(d){
return (d.target.maxChildIdx + 1) * _linkScale(d.depth === 0 ? 1 : d.depth);
}
function _tick(e){
var k = 6 * e.alpha,
size = _force.size(),
width = size[0],
height = size[1],
a,
b;
_nodes.forEach(function(d){
if(d.root){ d.x = width - (_marginRoot + _root.getBBox().width); }
if(d.tail){ d.x = _marginTail; d.y = height / 2; }
if(d.depth === 1){
d.y = d.region === -1 ? _marginTop : (height - _marginTop);
d.x -= 10 * k;
}
if(d.vertical){ d.y += k * d.region; }
if(d.depth){ d.x -= k; }
if(d.between){
a = d.between[0];
b = d.between[1];
d.x = b.x - (1 + d.childIdx) * (b.x - a.x) / (b.maxChildIdx + 1);
d.y = b.y - (1 + d.childIdx) * (b.y - a.y) / (b.maxChildIdx + 1);
}
_perNodeTick(d);
});
_node.call(_nodePosition);
_link.call(_linePosition);
}
fb1.links = function(){ return _links; };
fb1.nodes = function(){ return _nodes; };
fb1.force = function(){ return _force; };
fb1.defaultArrow = _arrow;
fb1.margin = function(_){
if(!arguments.length){ return _margin; }
_margin = _;
return my;
};
fb1.children = function(_){
if(!arguments.length){ return _children; }
_children = _;
return my;
};
fb1.label = function(_){
if(!arguments.length){ return _label; }
_label = _;
return my;
};
fb1.perNodeTick = function(_){
if(!arguments.length){ return _perNodeTick; }
_perNodeTick = _;
return my;
};
return fb1;
};
};
var getChartSize = function() {
var chart = $('.ic3w-fishbone-chart');
return {
width : chart.width() || 0,
height : chart.height() || 0
};
};
var renderFishboneChart = function(chartData) {
if (!d3.fishbone) {
initializeFishbone(d3);
}
d3.selectAll('.ic3w-fishbone-chart-content svg').remove();
var fishbone = d3.fishbone();
d3.select('.ic3w-fishbone-chart-content')
.append("svg")
.attr(getChartSize())
.datum(chartData)
.call(fishbone.defaultArrow)
.call(fishbone);
fishbone.force().start();
};
var buildChartDataJson = function(gviTable) {
var rowCount = gviTable.getRowCount();
var colCount = gviTable.getColumnCount();
var currentLevel, levelDepthStr;
var currentBranch = [];
for (var i = 0; i < colCount; i++) {
levelDepthStr = gviTable.getPropertyForColumnHeader(i, 0, "a_ld");
currentLevel = parseInt(levelDepthStr);
if (!isNaN(currentLevel)) {
var currentEl = {
name: gviTable.getColumnLabel(i),
children: []
};
if (currentLevel <= currentBranch.length - 1) {
removeElements(currentBranch, currentLevel);
}
currentBranch[currentLevel] = currentEl;
if (currentLevel != 0) {
var parent = currentBranch[currentLevel - 1];
parent.children.push(currentEl);
}
}
}
return currentBranch.length > 0 ? currentBranch[0] : {};
};
var removeElements = function(array, targetLength) {
if (array) {
while (array.length > targetLength) {
array.pop();
}
}
};
FishBonePlugin.js:
ic3globals.plugins.push(
{
name: "Fishbone Chart",
loadCSS: function (options) {
var root = options.rootLocal + "plugins/";
ic3css(root + 'Fishbone.css');
},
loadJS: function (options) {
var root = options.rootLocal + "plugins/";
var deps = ['FishboneChart'];
$script(root + 'FishboneChart.js', deps[0]);
$script.ready(deps, function () { /* asynchronous callback */
options.callback && options.callback();
});
},
registerWidgetFactories: function (manager) {
manager.addWidgetFactory(new test.module.FishboneChartAdapterFactory());
},
registerBabylonTags: function (babylon) {
}
});
Fishbone.css:
.ic3w-fishbone-chart {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.ic3w-fishbone-chart-content *{
font-family: "Gill Sans", "Gill Sans MT";
}
.ic3w-fishbone-chart-content .label-0 {
font-size: 2em;
}
.ic3w-fishbone-chart-content .label-1 {
font-size: 1.5em;
fill: #111;
}
.ic3w-fishbone-chart-content .label-2 {
font-size: 1em;
fill: #444;
}
.ic3w-fishbone-chart-content .label-3 {
font-size: .9em;
fill: #888;
}
.ic3w-fishbone-chart-content .label-4 {
font-size: .8em;
fill: #aaa;
}
.ic3w-fishbone-chart-content .link-0 {
stroke: #000;
stroke-width: 2px;
}
.ic3w-fishbone-chart-content .link-1 {
stroke: #333;
stroke-width: 1px;
}
.ic3w-fishbone-chart-content .link-2, .ic3w-fishbone-chart-content .link-3, .ic3w-fishbone-chart-content .link-4 {
stroke: #666;
stroke-width: .5px;
}
Report code:
{"classID":"ic3.ReportGuts","guts_":{"ic3Version":13,"schemaName":"Sales","cubeName":"Sales","layout":{"classID":"ic3.FixedLayout","guts_":{"ic3Version":13,"grid":10,"boxes":[{"classID":"ic3.FixedLayoutBox","guts_":{"ic3Version":13,"header":"widget-0 ( widgetGroup.testMenu/testFishboneChart )","behaviour":"Fixed Box","noPrint":false,"position":{"top":0,"left":170,"width":1380,"height":820},"widgetAdapterUid":"w1","zIndex":2001,"ic3_uid":"ic3-164"}}]}},"widgetMgr":{"classID":"ic3.WidgetAdapterContainerMgr","guts_":{"ic3Version":13,"items":[{"classID":"test.module.FishboneChartAdapter","guts_":{"ic3Version":13,"navigationGuts":{"classID":"ic3.NavigationStrategy","guts_":{"ic3Version":13,"menuVisibility":{"back":true,"axisXChange":"All","axisYChange":"All","filter":"All","reset":true,"widget":true,"others":"All"},"maxAxisMemberCount":25}},"ic3_name":"widget-0","ic3_uid":"w1","ic3_eventMapper":{"classID":"ic3.EventWidgetMapper","guts_":{"__ic3_widgetEventsDescription":{}}},"ic3_mdxBuilderUid":"m1","__ic3_widgetTypeName":"widgetGroup.testMenu/testFishboneChart"}}]}},"constantMgr":{"classID":"ic3.ConstantsMgr","guts_":{"ic3Version":13}},"cssMgr":{"classID":"ic3.CssMgr","guts_":{}},"javascriptMgr":{"classID":"ic3.ReportJavascriptMgr","guts_":{"ic3Version":13,"js":"/** \n * A function called each time an event is generated. \n * \n * #param context the same object is passed between consumeEvent calls. \n * Can be used to store information. \n * { \n * $report : jQuery context of the report container \n * fireEvent : a function( name, value ) triggering an event \n * } \n * \n * #param event the event information \n * \n { \n * name : as specified in the 'Events' tab \n * value : (optional) actual event value \n * type : (optional) e.g., ic3selection \n * } \n * \n * Check the 'Report Event Names' menu for the list of available events. \n */ \n \nfunction consumeEvent( context, event ) { \n if (event.name == 'ic3-report-init') { \n \n ic3globals.plugins.push(\n {\n name: \"Fishbone Chart\",\n\n loadCSS: function (options) {\n },\n\n loadJS: function (options) {\n },\n\n registerWidgetFactories: function (manager) {\n console.log('korte1');\n manager.addWidgetFactory(new test.module.FishboneChartAdapterFactory());\n },\n\n registerBabylonTags: function (babylon) {\n }\n });\n } \n}"}},"calcMeasureMgr":{"classID":"ic3.CalcMeasureMgr","guts_":{"measures":[]}},"mdxQueriesMgr":{"classID":"ic3.MdxQueriesContainerMgr","guts_":{"mdxQueries":{"classID":"ic3.BaseContainerMgr","guts_":{"ic3Version":13,"items":[{"classID":"ic3.QueryBuilderWidget","guts_":{"mdxWizard":{"classID":"ic3.QueryBuilderWizardForm","guts_":{"rows":[],"cols":[{"classID":"ic3.QueryBuilderHierarchyForm","guts_":{"hierarchy":{"name":"Geography","uniqueName":"[Customers].[Geography]"},"type":"membersOf","membersOf":"all members"}}],"filters":[],"nonEmptyOnRows":false,"nonEmptyOnColumns":false}},"mdxFlat":{"classID":"ic3.QueryBuilderFlatMdxForm","guts_":{"useMdxStatement":false}},"ic3_name":"mdx Query-0","ic3_uid":"m1"}}]}},"mdxFilter":{"classID":"ic3.BaseContainerMgr","guts_":{"ic3Version":13,"items":[]}},"actionBuilders":{"classID":"ic3.BaseContainerMgr","guts_":{"ic3Version":13,"items":[]}}}}}}
Thanks,
Balint Ruzsa
Widget adapter code needs two extra functions(workaround for internal bug):
FishboneChartAdapter.prototype.hasNavigation = function()
{
return false;
};
FishboneChartAdapter.prototype.getNavigationMenuItems = function()
{
return [];
};
isRendered method should be modified, because layout for chart computed dynamicaly. I suggest to use simple setTimeout to with heuristic timeout, but you may implement custom check.
FishboneChart:
test.module.FishboneChart = (function (_super) {
__extends(FishboneChart, _super);
function FishboneChart(container, options) {
_super.call(this, container, options);
this.options = options;
this.container = container;
this.rendered = false;
var chartContainer = $("<div class='ic3w-fishbone-chart'></div>");
var contentContainer = $("<div class='ic3w-fishbone-chart-content'></div>");
var ct = $(this.container);
ct.append(chartContainer);
chartContainer.append(contentContainer);
};
$.extend(FishboneChart.prototype, {
buildInHtml: function (gviTable) {
var chartData = buildChartDataJson(gviTable);
renderFishboneChart(chartData);
var self = this;
// wait until layout is stabilized
setTimeout(function(){self.rendered = true;}, 10000);
},
isRendered: function () {
return this.rendered;
}
});
return FishboneChart;
})(viz.GviChartBase);

Highcharts - Lazy loading combined with SQL queries

Based on the Lazy Loading Example I wanted to create the similar function for my Highcharts.StockChart. But with the aid of Ajax.
Some words about the database structure:
Tables contains the values of 1 month
Column 'tijd' contains a timestamp
Values are posted every minute to the database, resolution = 1 minute
Please focus on why the zoom function isn't updating the chart. This drives me #!#
For the first time generation of the chart I use this code, which works fine
JAVASCRIPT:
function generateChart(param, options)
{
// EERST DE GESELECTEERDE GEGEVENS GAAN OPVRAGEN
data = param.join();
console.log(data);
t_min = new Date(2015, 0, 1, 0, 0, 0, 0);
t_max = Date.now();
console.log(t_min, t_max);
console.log((t_max - t_min) / 1000);
$.ajax({
url: url,
data: { "data": data, "db": klantnummer, "t_min": t_min, "t_max": t_max },
type: "POST",
async: false,
cache: false,
success:
function (gegevens)
{
// GEGEVENS OPSLAAN IN DE OPTIE.SERIES
console.log('Gegevens:');
console.log(gegevens); //werkt!
options.series = gegevens;
}
});
//EFFECTIEF AANMAKEN VAN DE GRAFIEK
chart = new Highcharts.StockChart(options);
}
PHP:
// READ THE COLUMN NAMES
$data_in = $_POST['data'];
// DATA_IN to array
$name = explode(",", $data_in);
// count the amount of columns
$c_name = count($name);
$name_sql = implode(", ", $name);
//Connection with database
$klantnummer = $_POST['db'];
require 'connectie.php';
//ZOOM: min and max values are converterd to PHP UNIX EPOCH time
$t_min = ($_POST['t_min'])/1000;
$t_max = ($_POST['t_max'])/1000;
$range = $t_max - $t_min;
//Doesn't work, don't need it to load the chart
//$startTime = $t_min->format('m-d-Y H:i:s');
//$stopTime = $t_max->format('m-d-Y H:i:s');
//we only ask a query if there are enough columns
if ($c_name > 0) {
//Ask the names of the tables from the database
$sql = "SELECT TABLE_NAME FROM information_schema.tables WHERE TABLE_NAME LIKE 'T%' ORDER BY TABLE_NAME DESC";
$tableName = sqlsrv_query($conn, $sql);
if ( $tableName === false ) {
die(print_r(sqlsrv_errors(), true));
};
$t = array();
while ($row = sqlsrv_fetch_array($tableName)) {
array_push($t, $row['TABLE_NAME']);
};
// So we know the range, which filter should we apply?
if ($range < 14 * 24 *3600) { //2 weeks
$tijdspanne = 2; // load 2 tables
$filter = 1; // show every minute
} elseif ($range < 28 * 24 *3600) { //4 weeks
$tijdspanne = 2; // load 2 tables
$filter = 5; // show every 5 minutes
} elseif ($range < 3 * 28 * 24 *3600) { //3 months
$tijdspanne = 4; // load 4 months
$filter = 15; // show every 15 minutes
} else {
$tijdspanne = count($t); // load every table
$filter = 60; // show every 60 minutes
}
//Namen zijn gekend, nu in query steken om daarna op te vragen
$sql = "select tijd,".$name_sql." FROM ".$t[0]." where datepart(mi,tijd) % ".$filter." = 0";// AND tijd BETWEEN ".$startTime." AND ".$stopTime;
for ($x = 1; $x < count($t) and $x < $tijdspanne ; ++$x ) {
$sql .= " union all select tijd,".$name_sql." FROM ".$t[$x]." where datepart(mi,tijd) % ".$filter." = 0";// AND tijd BETWEEN ".$startTime." AND ".$stopTime;
};
$sql .= " ORDER BY tijd";
//DATA from MS SQL server, save to arrays
$stmt = sqlsrv_query($conn, $sql);
if ( $stmt === false ) {
die(print_r(sqlsrv_errors(), true));
}
while ($row = sqlsrv_fetch_array($stmt)) {
$tijd_U = $row["0"]->format("U");
$tijd = ($tijd_U) * 1000; //date format to javascript
for ($i = 0; $i < $c_name; ++$i) {
$j = $i +1;
$data[$i][]= array($tijd, $row[$j]);
}
}
// prepare JSON format
$data_output = array();
for ($i = 0; $i < $c_name; ++$i) {
$data_output[$i] = array('name' => $name[$i], 'data' => $data[$i]);
}
}
// admit we use JSON
header('Content-Type: application/json');
// send the data to the user
echo json_encode($data_output, JSON_NUMERIC_CHECK);
So this code works, but when the user zooms in. The graph doens't update.
JAVASCRIPT:
function afterSetExtremes(e)
{
console.log(Math.round(e.min));
chart.showLoading('Loading data from server...');
$.ajax({
url: url,
data: { "data": data, "db": klantnummer, "t_min": Math.round(e.min), "t_max": Math.round(e.max) },
type: "POST",
async: false,
cache: false,
success:
function (gegevens)
{
// GEGEVENS OPSLAAN IN DE OPTIE.SERIES
console.log('Gegevens:');
console.log(gegevens); //werkt!
options.series = gegevens;
}
});
chart.hideLoading();
}
With this set of options:
function generateChartOptions(div, ymax, ymin)
{
var options = {
navigator: {
adaptToUpdatedData: false,
series: {
includeInCSVExport: false
}
},
chart: {
renderTo: div,
type: 'line',
zoomType: 'x'
},
rangeSelector: {
buttons: [{
type: 'day',
count: 1,
text: '1d'
}, {
type: 'week',
count: 1,
text: '1w'
}, {
type: 'week',
count: 2,
text: '2w'
}, {
type: 'all',
text: 'All'
}],
selected: 4,
inputBoxWidth: 150,
inputDateFormat: '%d-%m-%Y %H:%M',
inputEditDateFormat: '%d-%m-%Y %H:%M'
},
legend: {
enabled: true
},
xAxis: {
type: 'datetime',
events: {
afterSetExtremes: afterSetExtremes,
setExtremes: function (e)
{
$('#testveld').html('<b>Set extremes:</b> e.min: ' + Highcharts.dateFormat(null, e.min) +
' | e.max: ' + Highcharts.dateFormat(null, e.max) + ' | e.trigger: ' + e.trigger);
}
},
minRange: 60 * 1000 //1 minuut
},
yAxis: {
opposite: false,
max: ymax,
min: ymin
},
plotOptions: {
line: {
tooltip: {
valueDecimals: 1
}
}
},
scrollbar: {
liveRedraw: false
},
series: [{}]
};
return options;
}

KineticJs-how to update x and y position of the multiple images after resizing the stage layer

As I am new to KineticJs so, I have tried implementing the functionality using Kinectic js for drawing the multiple image on different- different x and y. Now I wanted to resize the stage layer or canvas. I have done that by using the code given below
window.onresize = function (event) {
stage.setWidth(($('#tab' + tabId).innerWidth() / 100) * 80);
var _images = layer.getChildren();
for (var i = 0; i < _images.length; i++) {
if (typeof _images[i].getId() != 'undefined') {
//alert(stage.getScale().x);
_images[i].setX(_images[i].getX() * stage.getScale().x);
layer.draw();
}
}
}
but now the problem is the are being defined and now if browser resize than stage is resized but the images on the prev x and y are fixed . I would like to keep them fixed on the position on resizing of stage layer or canvas.Here are the link of the image before resize and after resizing.beforeresize and afterResize .
Here is my entire code given below:-
$("#tabs li").each(function () {
$(this).live("click", function () {
clearInterval(_timer);
var tabname = $(this).find("a").attr('name');
tabname = $.trim(tabname.replace("#tab", ""));
var tabId = $(this).find("a").attr('href');
tabId = $.trim(tabId.replace("#", ""));
$.ajax({
url: "/Home/GetTabsDetail",
dataType: 'json',
type: 'GET',
data: { tabId: tabId },
cache: false,
success: function (data) {
var bayStatus = [];
var i = 0;
var image_array = [];
var BayExist = false;
var BayCondition;
var imgSrc;
var CanvasBacgroundImage;
var _X;
var _bayNumber;
var _Y;
var _ZoneName;
$(data).each(function (i, val) {
i = i + 1;
if (!BayExist) {
bayStatus = val.BayStatus;
CanvasBacgroundImage = val.TabImageLocation;
BayExist = true;
}
$.each(val, function (k, v) {
if (k == "BayNumber") {
BayCondition = bayStatus[v];
_bayNumber = v;
if (BayCondition == "O")
imgSrc = "../../images/Parking/OccupiedCar.gif"
else if (BayCondition == "N")
imgSrc = "../../images/Parking/OpenCar.gif";
}
if (k == "BayX")
_X = v;
if (k == "BayY")
_Y = v;
if (k == "ZoneName")
_ZoneName = v;
});
image_array.push({ img: imgSrc, xAxis: _X, yAxis: _Y, toolTip: _bayNumber, ZoneName: _ZoneName });
});
var imageUrl = CanvasBacgroundImage;
if ($('#tab' + tabId).length) {
// $('#tab' + tabId).css('background-image', 'url("../../images/Parking/' + imageUrl + '")');
var stage = new Kinetic.Stage({
container: 'tab' + tabId,
width: ($('#tab' + tabId).innerWidth() / 100) * 80, // 80% width of the window.
height: 308
});
window.onresize = function (event) {
stage.setWidth(($('#tab' + tabId).innerWidth() / 100) * 80);
}
$('#tab' + tabId).find('.kineticjs-content').css({ 'background-image': 'url("../../images/Parking/' + imageUrl + '")', 'background-repeat': ' no-repeat', 'background-size': '100% 100%' });
var layer = new Kinetic.Layer();
var planetOverlay;
function writeMessage(message, _x, _y) {
text.setX(_x + 20);
text.setY(_y + 1);
text.setText(message);
layer.draw();
}
var text = new Kinetic.Text({
fontFamily: 'Arial',
fontSize: 14,
text: '',
fill: '#000',
width: 200,
height: 60,
align: 'center'
});
var opentooltip = new Opentip(
"div#tab" + tabId, //target element
"dummy", // will be replaced
"", // title
{
showOn: null // I'll manually manage the showOn effect
});
Opentip.styles.win = {
borderColor: "black",
shadow: false,
background: "#EAEAEA"
};
Opentip.defaultStyle = "win";
// _timer = setInterval(function () {
for (i = 0; i < image_array.length; i++) {
img = new Image();
img.src = image_array[i].img;
planetOverlay = new Kinetic.Image({
x: image_array[i].xAxis,
y: image_array[i].yAxis,
image: img,
height: 18,
width: 18,
id: image_array[i].toolTip,
name: image_array[i].ZoneName
});
planetOverlay.on('mouseover', function () {
opentooltip.setContent("<span style='color:#87898C;'><b>Bay:</b></span> <span style='color:#25A0D3;'>" + this.getId() + "</span><br> <span style='color:#87898C;'><b>Zone:</b></span><span style='color:#25A0D3;'>" + this.getName() + "</span>");
//writeMessage("Bay: " + this.getId() + " , Zone: " + this.getName(), this.getX(), this.getY());//other way of showing tooltip
opentooltip.show();
$("#opentip-1").offset({ left: this.getX(), top: this.getY() });
});
planetOverlay.on('mouseout', function () {
opentooltip.hide();
// writeMessage('');
});
planetOverlay.createImageHitRegion(function () {
layer.draw();
});
layer.add(planetOverlay);
layer.add(text);
stage.add(layer);
}
// clearInterval(_timer);
//$("#tab3 .kineticjs-content").find("canvas").css('background-image', 'url("' + imageUrl + '")');
// },
// 500)
}
}
,
error: function (result) {
alert('error');
}
});
});
});
I want to keep the icons on the position where they were before resizing. I have tried but could not get the right solution to get this done.
How can How can I update x,y position for the images . Any suggestions would be appreciated.
Thanks is advance.
In window.resize, you're changing the stage width by a scaling factor.
Save that scaling factor.
Then multiply the 'x' coordinate of your images by that scaling factor.
You can reset the 'x' position of your image like this:
yourImage.setX( yourImage.getX() * scalingFactor );
layer.draw();
In the above mentioned code for window.onresize. The code has been modified which as follow:-
window.onresize = function (event) {
_orignalWidth = stage.getWidth();
var _orignalHeight = stage.getHeight();
// alert(_orignalWidth);
// alert($('#tab' + tabId).outerHeight());
stage.setWidth(($('#tab' + tabId).innerWidth() / 100) * 80);
//stage.setHeight(($('#tab' + tabId).outerHeight() / 100) * 80);
_resizedWidth = stage.getWidth();
_resizedHeight = stage.getHeight();
// alert(_resizedWidth);
_scaleFactorX = _resizedWidth / _orignalWidth;
var _scaleFactorY = _resizedHeight / _orignalHeight;
//alert(_scaleFactor);
var _images = layer.getChildren();
for (var i = 0; i < _images.length; i++) {
if (typeof _images[i].getId() != 'undefined') {
//alert(stage.getScale().x);
_images[i].setX(_images[i].getX() * _scaleFactorX);
//_images[i].setY(_images[i].getY() * _scaleFactorY);
layer.draw();
}
}
}