AmChart move labelText to right a few pixels - amcharts

I'm trying to move label test to right few pixels because the way it's displayed now it looks like it is more to the left:
Label text is aligned to center for 2d bar charts but when you have 3d bars you have this slight offset effect to left that needs to be corrected.Label position values are: "bottom", "top", "right", "left", "inside", "middle".
I wasn't able to fine tune it.
Any ideas on this?

As mentioned in my comment, the labels are centered with respect to the angle setting for 3D charts. The API doesn't allow you to shift the label left or right, so you have to manipulate the graph SVG nodes directly through the drawn event. If you set addClassNames to true, you can retrieve the label elements using document.querySelectorAll through the generated DOM class names and then modifying the translate value in the transform attribute accordingly. You can use a technique from this SO answer to easily manipulate the transform attribute as an object:
// ...
"addClassNames": true,
"listeners": [{
"event": "drawn",
"method": function(e) {
Array.prototype.forEach.call(
document.querySelectorAll(".amcharts-graph-g4 .amcharts-graph-label"),
function(graphLabel) {
var transform = parseTransform(graphLabel.getAttribute('transform'));
transform.translate[0] = parseFloat(transform.translate[0]) + 5; //adjust X offset
graphLabel.setAttribute('transform', serializeTransform(transform));
});
}
}]
// ...
// from http://stackoverflow.com/questions/17824145/parse-svg-transform-attribute-with-javascript
function parseTransform(a) {
var b = {};
for (var i in a = a.match(/(\w+\((\-?\d+\.?\d*e?\-?\d*,?)+\))+/g)) {
var c = a[i].match(/[\w\.\-]+/g);
b[c.shift()] = c;
}
return b;
}
//serialize transform object back to an attribute string
function serializeTransform(transformObj) {
var transformStrings = [];
for (var attr in transformObj) {
transformStrings.push(attr + '(' + transformObj[attr].join(',') + ')');
}
return transformStrings.join(',');
}
Updated fiddle

Related

Disable brush resize (DC.js, D3.js)

Brush extent needs to be changed only from a dropdown as shown here: https://jsfiddle.net/dani2011/67jopfj8/3/
Need to disable brush extending by:
1) Extending an existing brush using the handles/resize-area of the brush
Gray circles are the handels:
2) Dragging a new brush by clicking on the brush background, where the
haircross cursor appears.
JavaScript file
Removed the handles of the brush:
timeSlider.on('preRedraw',function (chart)
{
var timesliderSVG = d3.select("#bitrate-timeSlider-chart").selectAll("g.brush").selectAll("g.resize").selectAll("*").data(data[0]).exit().remove();})
If using css instead:
#bitrate-timeSlider-chart g.resize {
display:none;
visibility:hidden;
Now it looks like this:
.
The rect and the path elements inside "resize e","resize w" were removed:
However,the "resize e", "resize w" for extanding the brush still exist:
g.resize.e and g.resize.w dimesions are 0*0:
Furthurmore,after deleting "resize e","resize w" in the "developer tools/elements" in chrome,they reappear after moving the brush.
Tried to remove the resize-area in brushstart,brush,brushend:
timeSlider.on('renderlet', function (chart) {
var brushg = d3.select("#bitrate-timeSlider-chart").selectAll("g.brush");
var resizeg = brushg.selectAll("g.resize").selectAll("*").data(data[0]);
var timesliderSVG4 =
brushg.on("brushstart", function () {resizeg.exit().remove()}).on("brush", function () { resizeg.exit().remove() }).on("brushend", function () {resizeg.exit().remove() })
dc.js file
Tried to change setHandlePaths,resizeHandlePath:
1)
Remarked the _chart.setHandlePaths(gBrush):
_chart.renderBrush = function (g) {....
// _chart.setHandlePaths(gBrush);
...}
2) Changed _chart.setHandlePaths = function (gBrush) for example by removing the gbrush.path:
// gBrush.selectAll('.resize path').exit().remove();
3) Remarked/changed _chart.resizeHandlePath = function (d) {...}.
d3.js file
1) Remarked/changed resize such as:
mode: "move" //mode: "resize" ,
var resize = g.selectAll(".resize").data(resizes[0], d3_identity);
Using resizes[0] disable the brush rendering on the background but still can re-extend the existing brush
2) Remarked/changed d3_svg_brushResizes
3) In d3.svg.brush = function():
a) Added .style("display","none"):
background.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("display", "none").style("cursor", "none");
b) background.exit().remove();
The cursor now is "pointer" instead of "haircross" extending the brush to a full width
c) d3_svg_brushCursor disabled makes the whole brush disappear
4) Changed the pointer-events as specified here: https://developer.mozilla.org/en/docs/Web/CSS/pointer-events
5) console.log in different places to track the different brush events:
function d3_event_dragSuppress(node) {
console.log("here2 ");
}
if (d3_event_dragSelect) {
console.log("here3 d3_event_dragSelect");
...
}
return function (suppressClick) {
console.log("suppressClick1");
...
var off = function () {
console.log("suppressClick2");
...
w.on(click, function () {
console.log("suppressClick3")
...
function d3_mousePoint(container, e) {
console.log("d3_mousePoint1")
...
if (svg.createSVGPoint) {
console.log("createSVGPoint");
...
if (window.scrollX || window.scrollY) {
console.log("createSVGPoint1");
svg = d3.select("body").append("svg").style({
...
function dragstart(id, position, subject, move, end) {
console.log("dragstart")
...
function moved() {
console.log("moved ");
console.log("transition1");
...
if (d3.event.changedTouches) {
console.log("brushstart1");
...
} else {
console.log("brushstart2");
..
if (dragging) {
console.log("dragging4");
....
if (d3.event.keyCode == 32) {
if (!dragging) {
console.log("notdragging1");
...
function brushmove() {
console.log("brushmove");
...
if (!dragging) {
console.log("brushmove!dragging");
if (d3.event.altKey) {
console.log("brushmove!dragging1");
...
if (resizingX && move1(point, x, 0)) {
console.log("resizeXMove1");
...
if (resizingY && move1(point, y, 1)) {
console.log("resizeYMove1");
...
if (moved) {
console.log("moved");
...
}
function move1(point, scale, i) {
if (dragging) {
console.log("dragging1");
...
if (dragging) {
console.log("dragging2");
...
} else {
console.log("dragging10");
...
if (extent[0] != min || extent[1] != max) {
console.log("dragging11");
if (i) console.log("dragging12"); yExtentDomain = null;
console.log("dragging13");
function brushend() {
console.log("brushend");
...
The two changes that seemed to get closest to the needed result are in d3.js:
1) Using resizes[0] disables the brush rendering on the background but still can re-extend the existing brush
var resize = g.selectAll(".resize").data(resizes[0], d3_identity);
2) Removing the brush's background changes the cursor to "pointer" instead of "haircross",extending the brush to a full width only when clicking on the graph
`background.exit().remove();`
Any help would be very appreciated!
This is from the accepted answer in Disable d3 brush resize, as suggested by #altocumulus. I didn't see a response from #Dani on this idea in particular, but thought I'd go ahead and try it, since I've seen other people try it in the past. (Probably on the dc.js users group.)
It looks a little twitchy, because d3.js will draw the brush at the new extent, and then a moment later we reset the extent to what we want, but functionally it seems to do what we want.
In dc.js the function that handles brush "rounding" is coordinateGridMixin.extendBrush:
_chart.extendBrush = function () {
var extent = _brush.extent();
if (_chart.round()) {
extent[0] = extent.map(_chart.round())[0];
extent[1] = extent.map(_chart.round())[1];
_g.select('.brush')
.call(_brush.extent(extent));
}
return extent;
};
Notice that it's following the same pattern as Lars' answer. Well, this is sort of like rounding, right? Let's override it.
First, let's store the current number of hours when it's set through the dropdown:
var graphSpan;
function addHours(amountHours) {
graphSpan = amountHours;
// ...
Next let's override coordinateGridMixin.extendBrush:
timeSlider.extendBrush = function() {
var extent = timeSlider.brush().extent();
if(graphSpan) {
extent[1] = moment(extent[0]).add(graphSpan, 'hours');
}
return extent;
}
We just replace the function. If we needed to reuse the old implementation in our function, we could use dc.override.
If graphSpan has been set, we add that amount to the beginning to get the end. If it's not set, we allow the user to specify the brush width - you'd need to default the graphSpan and the select widget if you wanted that part to work automatically.
Well, let's admit it: it's very twitchy, but it works:
EDIT: Got rid of the twitch! The problem was that dc.js was setting the brush extent asynchronously after a little while (in response to the filter event). If we also set it during extentBrush then it never shows the wrong extent:
timeSlider.extendBrush = function() {
var extent = timeSlider.brush().extent();
if(graphSpan) {
extent[1] = moment(extent[0]).add(graphSpan, 'hours');
timeSlider.brush().extent(extent);
}
return extent;
}
https://jsfiddle.net/gordonwoodhull/xdo05chk/1/
What worked for me:
in d3:
disable resize handles
d3.selectAll('.brush>.handle').remove();
disable crosshair
d3.selectAll('.brush>.overlay').remove();
or
in css:
disable resize handles -
.handle {
pointer-events: none;
}
disable crosshair -
.overlay {
pointer-events: none;
}

D3 datamaps changing border width on mouseover

I'm trying to make a combined map/chart visualization work. I want to be able to mouseover/select a country on the map, and have an effect applied not only to the country but also to the line on the chart representing the country's data (of whatever, let's say population growth over the last decade).
In the done section of the map initialization, I use a callback highlightMap and pass in the countryName. This in theory would also be called by the chart when I mouseover that.
Questions:
1) In highlightMap my attempt to get the country element and change it's border width doesn't work. What's the right way to grab a map subunit and apply an effect to it?
2) Is this the right way to do this in general?
var map;
function setupMap(mouseoverCallback, mouseoutCallback) {
var width = mapWidth;
var height = mapHeight;
map = new Datamap({
element: document.getElementById(mapContainerDiv),
projection: 'mercator',
// responsive: true,
width: width,
height: height,
fills: {
defaultFill: "#ffffff"
},
geographyConfig: {
borderColor: '#000000',
},
data: {},
done: function(datamap) {
datamap.svg.selectAll('.datamaps-subunit').on('mouseover', function(geography) {
var countryName = geography.properties.name;
highlightMap(countryName);
});
datamap.svg.selectAll('.datamaps-subunit').on('mouseout', function(geography) {
var countryName = geography.properties.name;
highlightMap(countryName);
});
}
});
}
function highlightMap(name, highlight) {
var code = country2Code[name];
if (highlight) {
var countryElement = map.svg.select("#datamaps-subunit "+code);
countryElement.attr('stroke-width', 10); // Change border of country to something nutty
// reset color
...
}
}
Sort out your selectors:
.datamaps-subunit is not the same as #datamaps-subunit
Moreover, each country geometry has an additional class (like "ESP" or "USA") with the country code
To later select the country you just use map.svg.selectAll(".datamaps-subunit.ESP") or map.svg.selectAll(".datamaps-subunit.USA")
Notice there is no space between class names, as they are applied to the same SVG element
Use select() or selectAll() depending on how many elements you expect to get (one or possibly many)
EDIT: A much easier option would be to simply add this rule to your CSS sheet:
.datamaps-subunit:hover {
stroke-width: 2px;
}

D3 Zoomable Treemap changing the children accessor

I am trying to use Mike Bostock's zoomable treemap http://bost.ocks.org/mike/treemap/ with one modification. Instead of using nested JSON data, I have have a simple mapping from parents to a list of children. I built a function, getChildren(root), that simply returns root's children, or null if root does not have any children.
I have tried replacing all instances of d.children() with getChildren(d) in the treemap javascript file, but it seems that it is not working properly.
The resulting page shows the orange bar as normal up top, but nothing else displays correctly (i.e. there are no rectangles underneath the orange bar, just empty gray space). All the text from the children is mashed up in the top left corner of the empty gray space, so it might be that coordinates are not being assigned correctly.
Any ideas??
Thanks!
It looks like there were a few issues here:
Your data structure doesn't seem to be referencing the child nodes:
var nMap = {};
nMap.papa = {};
nMap.papa["children"] = [];
nMap.papa["children"].push({
"name": "c1"
});
// snip
nMap.c1 = {
size: 5
};
Unless I'm missing something, your getChildren function gets the { name: "c1" } object but never looks up nMap.c1. I'm not exactly certain what your alternative data structure is trying to achieve, but it seems like the most obvious option is to use a flat map of nodes, with children referenced by id, like this:
var nMap = {};
nMap.c1 = {
name: "c1",
value: 5
};
nMap.c2 = {
name: "c2",
value: 5
};
nMap.c3 = {
name: "c3",
value: 5
};
nMap.papa = {
name: "papa",
children: ['c1', 'c2', 'c3']
};
With a structure like this, you can map to the real children in the getChildren function:
function getChildren(par){
var parName = par.name,
childNames = parName in nMap && nMap[parName].children;
if (childNames) {
// look up real nodes
return childNames.map(function(name) { return nMap[name]; });
}
}
Your children were using size instead of value to indicate weight, and the rest of the code expected value (so they all had weight 0).
Because you're using the "zoomable" treemap approach, which uses a specialized version of the treemap layout, you don't need to specify the .children accessor of the treemap layout. Instead, use your custom accessor in the the custom layout helper:
function layout(d) {
// get the children with your accessor
var children = getChildren(d);
if (children && children.length > 0) {
treemap.nodes({ children: children });
children.forEach(function(c) {
c.x = d.x + c.x * d.dx;
c.y = d.y + c.y * d.dy;
c.dx *= d.dx;
c.dy *= d.dy;
c.parent = d;
layout(c);
});
}
}
Working fiddle here: http://jsfiddle.net/nrabinowitz/WpQCy/

Raphael JS combined elements with separate control: Removing Event Part 2

This is a continuation of an earlier thread, that was answered by Neil- thanks Neil! I probably should have included this in the first question, but I wanted to simplify things...
Another feature that I need is to have a "dialogue box" that holds a title and some text that animates on and off next to the circle when it comes on. I achieved this in my earlier version prior to the help from Neil. I have spent some time trying to integrate it into the new and improved code and get some unexpected results. For example, if I rollover the first circle on the right, it works as it should, however, if I try to rollover the middle and right circles, they don't work. Oddly, if I refresh and start on the right circle, each will work when moving right to left, until I reach the left one, and then the middle and right don't work- but the left one continues to work. Additionally, if I click on the left circle, it works as it should, but then the others don't work. And conversely, if I click on the right one first, and then move to the middle, the middle works on click, but then the right one does not.
The behavior that I am looking for is that each circle, animate up with the rectangle next to the circle fading in with dynamic text on mouseover and animate down, with the rectangle with text fading out on mouseout. The rectangle with text should fade out on click and not fade up again if the user mousesover the clicked circle (need to remove the mouseover event as well I guess). One additional thing that needs to happen is that the rectangle needs to appear in a different place on the circle, depending where on the map it is- so that it doesn't fall off the map. I did this successfully in the earlier version, but have left that out on the previous post for better clarity. I will include it here so you get the gist of what I'm doing.
My guess is that I need to create a set() of the rectangle/text component and place it in an another set() along with the circle?
Any help on this is truly appreciated! Thanks
// JavaScript Document
var arr = [
[50, 50, "this", "Is text that is to be the abstract"],
[100, 50, "that", "Is text that I hope is here"],
[150, 50, "another thing", "Even more text"]
];
var currRect;
var currTitleTxt;
var currTeaseTxt;
var prevItem;
doMe();
function doMe() {
var paper = new Raphael(document.getElementById('canvas_container'), 696, 348);
for (var i = 0; i < arr.length; i++) {
paper.circle(arr[i][0], arr[i][1], 6).attr({
fill: '#fff',
'fill-opacity': 0.5
}).data("i", [arr[i][0], arr[i][1], arr[i][2], arr[i][3]]).click(function () {
this.unmouseout();
}).click(function () {
if (this.data('selected') != 'true') {
if (prevItem != null) {
prevItem.data('selected', '');
handleOutState(prevItem);
}
prevItem = this.data('selected', 'true');
currRect.animate({"fill-opacity":0, "stroke-opacity":0}, 150 );
currTitleTxt.animate({"fill-opacity":0}, 150 );
currTeaseTxt.animate({"fill-opacity":0}, 150 );
}
}).mouseover(function () {
handleOverState(this);
if(this.data("i")[0] <= 350){ //this is where I test for the position on the map
paper.setStart(); //create rectangle and text set
currRect =paper.rect(17, -20, 265,90).attr({fill:"#999","fill-opacity":0.5});
currTitleTxt = paper.text(25, -8, this.data("i")[2]).attr({"text-anchor":"start",fill:'#ffffff',"font-size": 14, "font-weight":"bold","fill-opacity":0});
currTeaseTxt = paper.text(25, 30).attr({"text-anchor":"start",fill:'#eeeeee',"font-size": 11, "font-weight":"bold","fill-opacity":0});
var maxWidth = 250;
var content = this.data("i")[3];
var words = content.split(" ");
var tempText = ""; //since Raphael doesn't have native word wrap, I break the line manually
for (var i=0; i<words.length; i++) {
currTeaseTxt.attr("text", tempText + " " + words[i]);
if (currTeaseTxt.getBBox().width > maxWidth) {
tempText += "\n" + words[i];
} else {
tempText += " " + words[i];
}
}
currTeaseTxt.attr("text", tempText.substring(1));
var st = paper.setFinish();
st.translate(this.data("i")[0]+10, this.data("i")[1]+0).animate({"fill-opacity":1}, 150 );
}else if(this.data("i")[0] >= 351){ //this is where I test for the position on the map
paper.setStart();
currRect = paper.rect(-280, -20, 250,50).attr({fill:"#999","fill-opacity":0.5});
currTitleTxt = paper.text(-270, -10, this.data("i")[2]).attr({"text-anchor":"start",fill:'#ffffff',"font-size": 14, "font-weight":"bold","fill-opacity":0});
currTeaseTxt =paper.text(-270, 5, this.data("i")[3]).attr({"text-anchor":"start",fill:'#cccccc',"font-size": 12, "font-weight":"bold","fill-opacity":0});
var st = paper.setFinish();
st.translate(this.data("i")[0]+10, this.data("i")[1]+0).animate({"fill-opacity":1}, 150 );
}
}).mouseout(function () {
currRect.animate({"fill-opacity":0, "stroke-opacity":0}, 150 );
currTitleTxt.animate({"fill-opacity":0}, 150 );
currTeaseTxt.animate({"fill-opacity":0}, 150 );
if (this.data('selected') != 'true') handleOutState(this);
});
}
function handleOverState(el) {
el.animate({
r: 8
}, 250).animate({
"fill-opacity": 1
}, 150);
}
function handleOutState(el) {
el.animate({
r: 6
}, 250).animate({
"fill-opacity": 0.5
}, 150);
}
}

One vertical scroll bar for whole Dijit BorderContainer

Here is the structure of my HTML body.
<body class="claro">
<div id="BorderContainerMain" data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="design:'headline'" style="width: 100%; border:0; padding:0; margin:0;">
<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'top'" style="border: 0;">
<div id="topBanner" data-dojo-type="core.widget.GeneralMainHeader" ></div>
</div>
<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'left'" style="border: 0;">
<div id="leftNav" data-dojo-type="core.widget.GeneralLeftNavigation"></div>
</div>
<div id="contentStackContainer" data-dojo-type="dijit.layout.StackContainer" data-dojo-props="region:'center', style: 'border: 0; padding: 0; margin: 0;'"></div>
</div>
Now, my desire is to make the whole screen auto grow in height depending on the content of the center region and let the viewport handle the vertical scrolling.
I am fairly new into dijit layout and I am using DOJO 1.6. I have already learned that I have to write code to achieve this. So, I am trying to get some experience guidance on this.
Thanks,
Rishi
So, I wrote up a custom resize for my purpose but it is not working. Is there any why it not working. Here is the code:
dojo.provide("core.widget.ClientBorderContainer");
dojo.require("dijit.layout.BorderContainer");
dojo.declare("core.widget.ClientBorderContainer", [dijit.layout.BorderContainer], {
totalHeight: 0,
_setupChild: function(/*dijit._Widget*/ child){
// Override BorderContainer._setupChild().
var region = child.region;
console.debug("region :: "+region);
if(region){
this.inherited(arguments);
dojo.addClass(child.domNode, this.baseClass+"Pane");
var ltr = this.isLeftToRight();
if(region == "leading"){ region = ltr ? "left" : "right"; }
if(region == "trailing"){ region = ltr ? "right" : "left"; }
// Create draggable splitter for resizing pane,
// or alternately if splitter=false but BorderContainer.gutters=true then
// insert dummy div just for spacing
if(region != "center" && (child.splitter || this.gutters) && !child._splitterWidget){
var _Splitter = dojo.getObject(child.splitter ? this._splitterClass : "dijit.layout._Gutter");
var splitter = new _Splitter({
id: child.id + "_splitter",
container: this,
child: child,
region: region,
live: this.liveSplitters
});
splitter.isSplitter = true;
child._splitterWidget = splitter;
dojo.place(splitter.domNode, child.domNode, "after");
// Splitters aren't added as Contained children, so we need to call startup explicitly
splitter.startup();
console.debug("Should not be printed as there is no splitter");
}
child.region = region; // TODO: technically wrong since it overwrites "trailing" with "left" etc.
}
},
resize: function(newSize, currentSize){
// Overrides BorderContainer.resize().
// resetting potential padding to 0px to provide support for 100% width/height + padding
// TODO: this hack doesn't respect the box model and is a temporary fix
if(!this.cs || !this.pe){
var node = this.domNode;
this.cs = dojo.getComputedStyle(node);
this.pe = dojo._getPadExtents(node, this.cs);
this.pe.r = dojo._toPixelValue(node, this.cs.paddingRight);
this.pe.b = dojo._toPixelValue(node, this.cs.paddingBottom);
dojo.style(node, "padding", "0px");
}
//Following section calculates the desired height of the BorderContainer
console.debug(this.id+" contentBox height ::: "+dojo.contentBox(this.domNode).h);
this.totalHeight = 0;
dojo.forEach(this.getChildren(), this.calculateHeight, this);
console.debug("this.totalHeight ::: "+this.totalHeight);
console.debug("newSize "+newSize);
console.debug("currentSize "+currentSize);
////////////////////////////////////////////////
// summary:
// Call this to resize a widget, or after its size has changed.
// description:
// Change size mode:
// When changeSize is specified, changes the marginBox of this widget
// and forces it to relayout its contents accordingly.
// changeSize may specify height, width, or both.
//
// If resultSize is specified it indicates the size the widget will
// become after changeSize has been applied.
//
// Notification mode:
// When changeSize is null, indicates that the caller has already changed
// the size of the widget, or perhaps it changed because the browser
// window was resized. Tells widget to relayout its contents accordingly.
//
// If resultSize is also specified it indicates the size the widget has
// become.
//
// In either mode, this method also:
// 1. Sets this._borderBox and this._contentBox to the new size of
// the widget. Queries the current domNode size if necessary.
// 2. Calls layout() to resize contents (and maybe adjust child widgets).
//
// changeSize: Object?
// Sets the widget to this margin-box size and position.
// May include any/all of the following properties:
// | {w: int, h: int, l: int, t: int}
//
// resultSize: Object?
// The margin-box size of this widget after applying changeSize (if
// changeSize is specified). If caller knows this size and
// passes it in, we don't need to query the browser to get the size.
// | {w: int, h: int}
var node = this.domNode;
// set margin box size, unless it wasn't specified, in which case use current size
if(newSize){
dojo.marginBox(node, newSize);
// set offset of the node
if(newSize.t){ node.style.top = newSize.t + "px"; }
if(newSize.l){ node.style.left = newSize.l + "px"; }
}
// If either height or width wasn't specified by the user, then query node for it.
// But note that setting the margin box and then immediately querying dimensions may return
// inaccurate results, so try not to depend on it.
var mb = currentSize || {};
dojo.mixin(mb, {h: this.totalHeight}); // calculated height overrides currentSize
if( !("h" in mb) || !("w" in mb) ){
mb = dojo.mixin(dojo.marginBox(node), mb); // just use dojo.marginBox() to fill in missing values
}
// Compute and save the size of my border box and content box
// (w/out calling dojo.contentBox() since that may fail if size was recently set)
var cs = dojo.getComputedStyle(node);
var me = dojo._getMarginExtents(node, cs);
var be = dojo._getBorderExtents(node, cs);
console.debug("mb.w "+mb.w);
console.debug("mb.h "+mb.h);
var bb = (this._borderBox = {
w: mb.w - (me.w + be.w),
h: mb.h - (me.h + be.h)
});
var pe = dojo._getPadExtents(node, cs);
console.debug("bb.w "+bb.w);
console.debug("bb.h "+bb.h);
this._contentBox = {
l: dojo._toPixelValue(node, cs.paddingLeft),
t: dojo._toPixelValue(node, cs.paddingTop),
w: bb.w - pe.w,
h: bb.h - pe.h
};
// Callback for widget to adjust size of its children
this.layout();
///////////////////////////////////////////////
console.debug(this.id+" contentBox height ::: "+dojo.contentBox(this.domNode).h);
},
calculateHeight: function(/*dijit._Widget*/ child){
var region = child.region;
console.debug("region :: "+region);
if(region && (region == "top" || region == "center" || region == "bottom")){
var childHeight = 0;
if(child instanceof dijit.layout.StackContainer){
console.debug("selectedChildWidget "+child.selectedChildWidget);
if(child.selectedChildWidget)
childHeight = dojo.contentBox(child.selectedChildWidget.domNode).h;
else
childHeight = dojo.contentBox(child.domNode).h;
}else{
childHeight = dojo.contentBox(child.domNode).h;
}
this.totalHeight = this.totalHeight+childHeight;
console.debug("childHeight = "+childHeight+" child.declaredClass"+child.declaredClass);
}
},
_layoutChildren: function(/*String?*/ changedChildId, /*Number?*/ changedChildSize){
// summary:
// This is the main routine for setting size/position of each child.
// description:
// With no arguments, measures the height of top/bottom panes, the width
// of left/right panes, and then sizes all panes accordingly.
//
// With changedRegion specified (as "left", "top", "bottom", or "right"),
// it changes that region's width/height to changedRegionSize and
// then resizes other regions that were affected.
// changedChildId:
// Id of the child which should be resized because splitter was dragged.
// changedChildSize:
// The new width/height (in pixels) to make specified child
if(!this._borderBox || !this._borderBox.h){
// We are currently hidden, or we haven't been sized by our parent yet.
// Abort. Someone will resize us later.
return;
}
console.debug("custom lay out children called");
// Generate list of wrappers of my children in the order that I want layoutChildren()
// to process them (i.e. from the outside to the inside)
var wrappers = dojo.map(this.getChildren(), function(child, idx){
return {
pane: child,
weight: [
child.region == "center" ? Infinity : 0,
child.layoutPriority,
(this.design == "sidebar" ? 1 : -1) * (/top|bottom/.test(child.region) ? 1 : -1),
idx
]
};
}, this);
wrappers.sort(function(a, b){
var aw = a.weight, bw = b.weight;
for(var i=0; i<aw.length; i++){
if(aw[i] != bw[i]){
return aw[i] - bw[i];
}
}
return 0;
});
// Make new list, combining the externally specified children with splitters and gutters
var childrenAndSplitters = [];
dojo.forEach(wrappers, function(wrapper){
var pane = wrapper.pane;
childrenAndSplitters.push(pane);
if(pane._splitterWidget){
childrenAndSplitters.push(pane._splitterWidget);
}
});
// Compute the box in which to lay out my children
console.debug("this._borderBox.h :: "+this._borderBox.h);
var dim = {
l: this.pe.l,
t: this.pe.t,
w: this._borderBox.w - this.pe.w,
h: this._borderBox.h - this.pe.h
};
// Layout the children, possibly changing size due to a splitter drag
dijit.layout.layoutChildren(this.domNode, dim, childrenAndSplitters,
changedChildId, changedChildSize);
}
});
BorderContainer was written to take a sized box and calculate the center based on what's left over, sort of the opposite of what you're trying to do. AFAIK it won't support this.

Resources