I have a Highcharts component where the user can add comments to a graph, and the comment shows up as a dataLabel in a scatter series. However, I noticed that by default the allowOverlap just removes the dataLabels that collides, and my question to this is: would it be possible to make the colliding dataLabels stack on top of each other? I'm thinking that since the allowOverlap: true can detect which ones that are colliding, there might be a way to take advantage of this?
This is how my dataLabels look now:
This is my goal:
Hope that someone can help me with a clever solution, I sure know I am out of ideas!
By the way, right now the dataLabels gets their xAxis position by dividing the xAxis :{ max: value } by 1,5. This is just to position it equally on all my graphs, which all have different min and max values. Might be worth mentioning.
It is possible to override the funciton that should be hiding the overlapping labels and adjust position of the overlapping labels like this:
$(function() {
(function(H) {
var each = H.each,
UNDEFINED;
H.Chart.prototype.hideOverlappingLabels = function(labels, rerun) {
if (rerun === UNDEFINED ||
rerun < 10) //infinity loop limit
{
var doTheRerun = false,
len = labels.length,
label, i, j, label1, label2,
isIntersecting, pos1, pos2, parent1, parent2,
padding,
intersectRect = function(x1, y1, w1, h1, x2, y2, w2, h2) {
return !(
x2 > x1 + w1 ||
x2 + w2 < x1 ||
y2 > y1 + h1 ||
y2 + h2 < y1
);
};
for (i = 0; i < len; i++) {
label = labels[i];
if (label) {
label.oldOpacity = label.opacity;
label.newOpacity = 1;
}
}
labels.sort(function(a, b) {
return (b.labelrank || 0) - (a.labelrank || 0);
});
for (i = 0; i < len; i++) {
label1 = labels[i];
for (j = i + 1; j < len; ++j) {
label2 = labels[j];
if (label1 && label2 && label1.placed && label2.placed && label1.newOpacity !== 0 && label2.newOpacity !== 0) {
pos1 = label1.alignAttr;
pos2 = label2.alignAttr;
parent1 = label1.parentGroup; // Different panes have different positions
parent2 = label2.parentGroup;
padding = 2 * (label1.box ? 0 : label1.padding); // Substract the padding if no background or border (#4333)
isIntersecting = intersectRect(
pos1.x + parent1.translateX,
pos1.y + parent1.translateY,
label1.width - padding,
label1.height - padding,
pos2.x + parent2.translateX,
pos2.y + parent2.translateY,
label2.width - padding,
label2.height - padding
);
if (isIntersecting) {
(label1.labelrank < label2.labelrank ? label1 : label2).addHeightOffset = true;
}
}
}
}
each(labels, function(label) {
var complete,
newOpacity;
if (label) {
if (label.addHeightOffset && label.placed) {
label.alignAttr.y -= label.height;
label.addHeightOffset = false;
doTheRerun = true;
}
label['attr'](label.alignAttr);
}
});
if (doTheRerun) {
rerun = (rerun || 0) + 1;
H.Chart.prototype.hideOverlappingLabels(labels, rerun);
}
}
};
}(Highcharts))
$('#container').highcharts({
series: [{
dataLabels: {
enabled: true,
format: 'The value that is important for this point is: {y}'
},
data: [1, 2, 1, 1, 2, 2, 2]
}]
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://code.highcharts.com/highcharts.js"></script>
<div id="container" style="height: 400px"></div>
Demo in JSFiddle: http://jsfiddle.net/ozLtvwke/1/
Related
When using insidetextorientation = 'radial', even in a very simple plotly sunburst chart, some of the labels are grossly displaced.
library(plotly)
my_labels <- c("A","B","C","AA","AB","AC","BA","BB","CA","CB","CC")
my_parents <- c("","","","A","A","A","B","B","C","C","C")
my_values <- c(15,23,7,3,5,7,6,17,1,2,4)
plot_ly(labels = my_labels,parents = my_parents,values = my_values,type = 'sunburst',
branchvalues = 'total',insidetextorientation = 'radial')
Notice the "B" and "BA" on the left are misplaced. Similar issues occur when zooming in on any of the parents and do not persist with insidetextorientation = 'auto'. Is there a way to fix this?
On the plotly community forum the same question was asked 2 years ago, but not answered.
This isn't a great answer. It works, but when you click out of a parent so that everything is showing again, the plot has to stop moving before the labels will change back to the radial angles.
I've tried a lot of different ways to improve it. I think that letting Plotly package authors know is important; short of changing the code, I don't know of a better way to make this happen. The main problem is that the SVG paths that change when you enter and leave a parent are deleted and re-calculated. Any event that's attached is deleted at that point. (I tried both Plotly events and straight JS events.)
So instead of an event, it's on an interval. Every 100 milliseconds it checks to see if the labels need to be fixed.
plot_ly(labels = my_labels, parents = my_parents,
values = my_values, type = 'sunburst',
branchvalues = 'total', insidetextorientation = 'horizontal') %>%
htmlwidgets::onRender("function() {
pc = ['B', 'A', 'C', 'BB', 'BA', 'AC', 'AB', 'AA', 'CC', 'CB', 'CA'];
rpl = [0, -64, 28, -68, 28, -32, -80, 68, 40, 16, 4];
rx = /.*rotate\\((.*)\\)/g;
function fixer(){
tx = document.querySelectorAll('g > text');
if(tx.length === 11) { /*not when clicking subgroups*/
for(i=0;i<tx.length;i++){
wh = tx[i].getAttribute('data-unformatted');
tr = tx[i].getAttribute('transform');
rot = /.*rotate\\((.*)\\)/g.exec(tr);
if(rot !== null){ /*if a text rotation is designated*/
if(rpl[pc.indexOf(wh)] !== Number(rot)) {
rot = rot[1];
if(Number(rot) !== rpl[i] && wh === pc[i]){ /*if angle does not match & label does*/
beg = /(.*)rotate/.exec(tr)[1]; /*capture translate string*/
xy = beg + 'rotate(' + rpl[i] + ')'; /*build new transform string*/
tx[i].setAttribute('transform', xy); /*replace transform string with new*/
}
}
}
if(rot === null && wh === pc[i]) { /*if no rotation is present and label matches*/
str = tr + 'rotate(' + rpl[i] + ')'; /* build new transform string */
tx[i].setAttribute('transform', str); /*replace transform string with new*/
}
}
}
}
setInterval(fixer, 100);}") # check regularly! (every 100 ms)
I basically started with onRender set to just spit out the transform attribute for every label, so that I could get the order in which the labels appear (see pc in the JS) and the angles that the labels are placed at (see rpl in the JS). This was done while insidetextorientation = 'radial'. (I actually looked at all the text options: tangential, horizontal, auto, and radial.)
From there I tried MANY things to trigger the JS function fixer. In the end the only thing that was consistent enough for me to even share my work was using setInterval.
Update; Firefox friendly!
I really did try to figure this out for my initial answer. Here is the code without static arrays for the labels or angles. Let me know if you run into issues.
plot_ly(labels = my_labels, parents = my_parents,
values = my_values, type = 'sunburst',
branchvalues = 'total', insidetextorientation = 'horizontal') %>%
htmlwidgets::onRender("function(el, x) {
/* calculates the angles for each slice */
function angler (arVal, deg){ /* array of values in order; degrees each value unit*/
results = []; /* for storing the results */
theta = 0; /* for cumulative angle */
for(k = 0; k < arVal.length; k++){
here = arVal[k] * deg; /* units times degrees */
mrot = theta + (.5 * here); /* initial text angle */
if(mrot >= 90 && mrot < 270) {
mrot = mrot - 180; /* don't put text upside down */
}
if(mrot >= 270 && mrot < 360){
mrot = mrot - 360; /* don't put text upside down */
}
results[k] = mrot;
theta = theta + here; /* for the next loop */
}
return(results);
}
par = x.data[0].parents; /* collect the necessary data*/
val = x.data[0].values;
lab = x.data[0].labels;
parI = par.reduce((a, e, i) => { /*which rows have parents?*/
if (e == '') { a.push(i); };
return a;
}, []); /*in array a, if element e at pos i equates to ''*/
parC = par.reduce((a, e, i) => { /*which rows do NOT have parents?*/
if (e != '') { a.push(i); };
return a;
}, []); /*in array a, if element e at pos i equates to ''*/
alp = lab.map((i, j) => {return [i, val[j], par[j]]}); /* combine data */
palv = alp.filter((e, i) => parI.some(j => i === j)); /*parent array*/
calv = alp.filter((e, i) => parC.some(j => i === j)); /*children array*/
pvalS = palv.sort(function(a, b) {
return((a[1] > b[1]) ? -1 : ((a[1] == b[1]) ? 0 : 1));
}) /*parents sorted by values*/
parS = pvalS.map(function(j) {return j[0];}); /*extract ordered parents*/
csort = []; /* for ordered kids array*/
for(i = 0; i < parS.length; i++){ /* sort children by parent and size*/
arr = calv.filter(j => parS[i].includes(j[2]));
arr1 = arr.map(function(w) {return w[1]}); /*get just values*/
arr2 = arr1.sort(function(a, b){ return b - a });
bld = [];
for(k = 0; k < arr2.length; k++) {
arr3 = arr.filter(j => arr2[k] == j[1]);
csort = csort.concat(arr3);
}
}
/* get the order--- in reverse*/
cvo = csort.map(function(j){return j[1]});
cvov = Object.values(cvo).reverse();
pvo = pvalS.map(function(j) {return j[1];}); /*extract ordered parents' values*/
pvov = Object.values(pvo).reverse();
ctots = cvov.reduce((a, b) => a + b, 0); /* 45 */
rotV = 360/ctots; /* 8 in this example */
kids = angler(cvov, rotV); /* collect kids angles */
parents = angler(pvov, rotV); /* collect parent angles */
kidS = csort.map(function(j) {return j[0];}); /* extract kid labels in order */
/*pc = ['B', 'A', 'C', 'BB', 'BA', 'AC', 'AB', 'AA', 'CC', 'CB', 'CA'];*/
pc = Object.values(parS).concat(Object.values(kidS));
/*rpl = [0, -64, 28, -68, 28, -32, -80, 68, 40, 16, 4];*/
rpl = parents.reverse().concat(kids.reverse());
rx = /.*rotate\\((.*)\\)/g;
function fixer(){
tx = document.querySelectorAll('g > text');
if(tx.length === 11) { /*not when clicking subgroups*/
for(i=0;i<tx.length;i++){
wh = tx[i].getAttribute('data-unformatted');
tr = tx[i].getAttribute('transform');
rot = /.*rotate\\((.*)\\)/g.exec(tr);
if(rot !== null){ /*if a text rotation is designated*/
if(rpl[pc.indexOf(wh)] !== Number(rot)) {
rot = rot[1];
if(Number(rot) !== rpl[i] && wh === pc[i]){ /*if angle does not match & label does*/
beg = /(.*)rotate/.exec(tr)[1]; /*capture translate string*/
xy = beg + 'rotate(' + rpl[i] + ')'; /*build new transform string*/
tx[i].setAttribute('transform', xy); /*replace transform string with new*/
}
}
}
if(rot === null && wh === pc[i]) { /*if no rotation is present and label matches*/
str = tr + 'rotate(' + rpl[i] + ')'; /* build new transform string */
tx[i].setAttribute('transform', str); /*replace transform string with new*/
}
}
}
}
setInterval(fixer, 100);}") # check regularly! (every 100 ms)
I am trying to add random segments along the path of a rectangle. Here is my jsfiddle http://jsfiddle.net/hhND7/1/
<canvas id='canvas' resize style='' style='padding:0; margin:0;'></canvas>
<script type="text/paperscript" canvas="canvas" >
var rect = new Path.Rectangle({x:200, y:100}, new Size(80, 100))
rect.strokeColor = 'gray'
rect.selected = true;
var pathCuts = rands(20, 0, 360).sort(function(a,b){return a - b});
var tArr = [];
for ( var i=0; i<pathCuts.length; i++){
var loc = rect.getLocationAt(pathCuts[i]);
tArr.push(loc.point);
var sE = new Path.Circle(loc.point, 2);
sE.strokeColor = 'red';
}
rect.insertSegments(1, tArr);
function rands(n, min, max) {
var range = max - min;
if (range < n)
throw new RangeError("Specified number range smaller than count requested");
function shuffle() {
var deck = [], p, t;
for (var i = 0; i < range; ++i)
deck[i] = i + min;
for (i = range - 1; i > 0; --i) {
p = Math.floor(Math.random() * i);
t = deck[i];
deck[i] = deck[p];
deck[p] = t;
}
return deck.slice(0, n);
}
function find() {
var used = {}, rv = [], r;
while (rv.length < n) {
r = Math.floor(Math.random() * range + min);
if (!used[r]) {
used[r] = true;
rv.push(r);
}
}
return rv;
}
return range < 3 * n ? shuffle() : find();
}
</script>
I think the problem is with the insertSegments function. But i can not find a solution.
If you want it to still look like the original polygon, you need to sort in the positions of the original segments. Since you can replace a path's segments with an array of curveLocation , you can just add the locations of these points to tArr, then sort by each element by it's offset:
var pathCuts = rands(20, 0, rect.length);
var tArr = [];
for ( var i=0; i<pathCuts.length; i++){
var loc = rect.getLocationAt(pathCuts[i]);
tArr.push(loc);
var sE = new Path.Circle(loc.point, 2);
sE.strokeColor = 'red';
}
for ( var i = 0, l = rect.segments.length; i < l; i++){
tArr.push(rect.segments[i].location);
}
tArr.sort(function(a,b){return a.offset - b.offset})
rect.segments = tArr;
Can i align a text in a div with a geometric shape, like this
https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcQ5z8OYxnypDr09mmfFMunJj31x_XtfG3MFj0vlAa_ceoCnts0OfQ
without hiding some of text?
Update:
I need something like this, above is a circle, but also i need something like this for parallelogram:
http://i39.tinypic.com/4r2ikm.jpg
Here's a js fiddle code
fiddle
Found it some where.
Here's the script
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var text = "'Twas the night before Christmas, when all through the house, Not a creature was stirring, not even a mouse. And so begins the story of the day of Christmas";
var font = "12pt verdana";
var textHeight = 15;
var lineHeight = textHeight + 5;
var lines = [];
var cx = 150;
var cy = 150;
var r = 100;
initLines();
wrapText();
ctx.beginPath();
ctx.arc(cx, cy, r, 0, Math.PI * 2, false);
ctx.closePath();
ctx.strokeStyle = "skyblue";
ctx.lineWidth = 2;
ctx.stroke();
// pre-calculate width of each horizontal chord of the circle
// This is the max width allowed for text
function initLines() {
for (var y = r * .90; y > -r; y -= lineHeight) {
var h = Math.abs(r - y);
if (y - lineHeight < 0) {
h += 20;
}
var length = 2 * Math.sqrt(h * (2 * r - h));
if (length && length > 10) {
lines.push({
y: y,
maxLength: length
});
}
}
}
// draw text on each line of the circle
function wrapText() {
var i = 0;
var words = text.split(" ");
while (i < lines.length && words.length > 0) {
line = lines[i++];
var lineData = calcAllowableWords(line.maxLength, words);
ctx.fillText(lineData.text, cx - lineData.width / 2, cy - line.y + textHeight);
words.splice(0, lineData.count);
};
}
// calculate how many words will fit on a line
function calcAllowableWords(maxWidth, words) {
var wordCount = 0;
var testLine = "";
var spacer = "";
var fittedWidth = 0;
var fittedText = "";
ctx.font = font;
for (var i = 0; i < words.length; i++) {
testLine += spacer + words[i];
spacer = " ";
var width = ctx.measureText(testLine).width;
if (width > maxWidth) {
return ({
count: i,
width: fittedWidth,
text: fittedText
});
}
fittedWidth = width;
fittedText = testLine;
}
}
yes this can be achieved through these links
link1 and link2.
and then set the div's by giving postioning :) cheers.
give border radius and get your shape. and use some margins to get it accurate. The link i have posted will help you.
I have 4 tables that need to scroll, they are set up as follows:
Table1(static)
Table2(Horizontal Scrolling)
Table3(Vertical Scrolling)
Table4(Horizontal and Vertical Scrolling)
Table1 Table2
Table3 Table4
The tricky part of this is that Table 3 and 4 need to keep in sync as this is a listing of data broken out into two tables. Table 2 and 4 are in the same situation.
Any ideas?
No Javascript please as we have a script that works, but it is far too slow to work.
Thanks.
EDIT:
var tables = new Array();
var headerRowDivs = new Array();
var headerColumnDivs = new Array();
var bodyDivs = new Array();
var widths = new Array();
var heights = new Array();
var borderHorizontals = new Array();
var borderVerticals = new Array();
var tableWidths = new Array();
var tableHeights = new Array();
var arrayCount = 0;
var paddingTop = 0;
var paddingBottom = 0;
var paddingLeft = 0;
var paddingRight = 0;
function ScrollTableAbsoluteSize(table, width, height)
{
ScrollTable(table, null, null, width, height);
}
function ScrollTableRelativeSize(table, borderHorizontal, borderVertical)
{
ScrollTable(table, borderHorizontal, borderVertical, null, null);
}
function ScrollTable(table, borderHorizontal, borderVertical, width, height)
{
var childElement = 0;
if (table.childNodes[0].tagName == null)
{
childElement = 1;
}
var cornerDiv = table.childNodes[childElement].childNodes[0].childNodes[childElement].childNodes[childElement];
var headerRowDiv = table.childNodes[childElement].childNodes[0].childNodes[(childElement + 1) * 2 - 1].childNodes[childElement];
var headerColumnDiv = table.childNodes[childElement].childNodes[childElement + 1].childNodes[childElement].childNodes[childElement];
var bodyDiv = table.childNodes[childElement].childNodes[childElement + 1].childNodes[(childElement + 1) * 2 - 1].childNodes[childElement];
tables[arrayCount] = table;
headerRowDivs[arrayCount] = headerRowDiv;
headerColumnDivs[arrayCount] = headerColumnDiv;
bodyDivs[arrayCount] = bodyDiv;
borderHorizontals[arrayCount] = borderHorizontal;
borderVerticals[arrayCount] = borderVertical;
tableWidths[arrayCount] = width;
tableHeights[arrayCount] = height;
ResizeCells(table, cornerDiv, headerRowDiv, headerColumnDiv, bodyDiv);
widths[arrayCount] = bodyDiv.offsetWidth;
heights[arrayCount] = bodyDiv.offsetHeight;
arrayCount++;
ResizeScrollArea();
bodyDiv.onscroll = SyncScroll;
if (borderHorizontal != null)
{
window.onresize = ResizeScrollArea;
}
}
function ResizeScrollArea()
{
var isIE = true;
var scrollbarWidth = 17;
if (!document.all)
{
isIE = false;
scrollbarWidth = 19;
}
for (i = 0; i < arrayCount; i++)
{
bodyDivs[i].style.overflow = "scroll";
bodyDivs[i].style.overflowX = "scroll";
bodyDivs[i].style.overflowY = "scroll";
var diffWidth = 0;
var diffHeight = 0;
var scrollX = true;
var scrollY = true;
var columnWidth = headerColumnDivs[i].offsetWidth;
if (borderHorizontals[i] != null)
{
var width = document.documentElement.clientWidth - borderHorizontals[i] - columnWidth;
}
else
{
var width = tableWidths[i];
}
if (width > widths[i])
{
width = widths[i];
bodyDivs[i].style.overflowX = "hidden";
scrollX = false;
}
var columnHeight = headerRowDivs[i].offsetHeight;
if (borderVerticals[i] != null)
{
var height = document.documentElement.clientHeight - borderVerticals[i] - columnHeight;
}
else
{
var height = tableHeights[i];
}
if (height > heights[i])
{
height = heights[i];
bodyDivs[i].style.overflowY = "hidden";
scrollY = false;
}
headerRowDivs[i].style.width = width + "px";
headerRowDivs[i].style.overflow = "hidden";
headerColumnDivs[i].style.height = height + "px";
headerColumnDivs[i].style.overflow = "hidden";
bodyDivs[i].style.width = width + scrollbarWidth + "px";
bodyDivs[i].style.height = height + scrollbarWidth + "px";
if (!scrollX && isIE)
{
bodyDivs[i].style.overflowX = "hidden";
bodyDivs[i].style.height = bodyDivs[i].offsetHeight - scrollbarWidth + "px";
}
if (!scrollY && isIE)
{
bodyDivs[i].style.overflowY = "hidden";
bodyDivs[i].style.width = bodyDivs[i].offsetWidth - scrollbarWidth + "px";
}
if (!scrollX && !scrollY && !isIE)
{
bodyDivs[i].style.overflow = "hidden";
}
}
}
function ResizeCells(table, cornerDiv, headerRowDiv, headerColumnDiv, bodyDiv)
{
var childElement = 0;
if (table.childNodes[0].tagName == null)
{
childElement = 1;
}
SetWidth(
cornerDiv.childNodes[childElement].childNodes[childElement].childNodes[0].childNodes[childElement],
headerColumnDiv.childNodes[childElement].childNodes[childElement].childNodes[0].childNodes[0]);
SetHeight(
cornerDiv.childNodes[childElement].childNodes[childElement].childNodes[0].childNodes[childElement],
headerRowDiv.childNodes[childElement].childNodes[childElement].childNodes[0].childNodes[childElement]);
var headerRowColumns = headerRowDiv.childNodes[childElement].childNodes[childElement].childNodes[0].childNodes;
var bodyColumns = bodyDiv.childNodes[childElement].childNodes[childElement].childNodes[0].childNodes;
for (i = 0; i < headerRowColumns.length; i++)
{
if (headerRowColumns[i].tagName == "TD" || headerRowColumns[i].tagName == "TH")
{
SetWidth(
headerRowColumns[i],
bodyColumns[i],
i == headerRowColumns.length - 1);
}
}
var headerColumnRows = headerColumnDiv.childNodes[childElement].childNodes[childElement].childNodes;
var bodyRows = bodyDiv.childNodes[childElement].childNodes[childElement].childNodes;
for (i = 0; i < headerColumnRows.length; i++)
{
if (headerColumnRows[i].tagName == "TR")
{
SetHeight(
headerColumnRows[i].childNodes[0],
bodyRows[i].childNodes[childElement],
i == headerColumnRows.length - 1);
}
}
}
function SetWidth(element1, element2, isLastColumn)
{
// alert(element2 + "\n\n" + element2.offsetWidth);
var diff = paddingLeft + paddingRight;
if (element1.offsetWidth < element2.offsetWidth)
{
element1.childNodes[0].style.width = element2.offsetWidth - diff + "px";
element2.childNodes[0].style.width = element2.offsetWidth - diff + "px";
}
else
{
element2.childNodes[0].style.width = element1.offsetWidth - diff + "px";
element1.childNodes[0].style.width = element1.offsetWidth - diff + "px";
}
}
function SetHeight(element1, element2, isLastRow)
{
var diff = paddingTop + paddingBottom;
if (element1.offsetHeight < element2.offsetHeight)
{
element1.childNodes[0].style.height = element2.offsetHeight - diff + "px";
element2.childNodes[0].style.height = element2.offsetHeight - diff + "px";
}
else
{
element2.childNodes[0].style.height = element1.offsetHeight - diff + "px";
element1.childNodes[0].style.height = element1.offsetHeight - diff + "px";
}
}
function SyncScroll()
{
for (i = 0; i < arrayCount; i++)
{
headerRowDivs[i].scrollLeft = bodyDivs[i].scrollLeft;
headerColumnDivs[i].scrollTop = bodyDivs[i].scrollTop;
}
}
We got the code from this link.
I hope this helps.
As it stands, the code is far too bulky to process the amount of data we need to. We have approximately 5000 rows of data per month that needs to be displayed on the page.
If by "need to keep in sync" you mean that when you scroll one of them, the other scrolls too, you can't do this with CSS, because you can't manipulate scroll position using CSS.
And one more thing, have in mind that scrollbar in IE goes inside the element and overlaps 20px of this element (there is a workaround for this), and in all other browsers scrollbar goes outside the element.
You can use CSS to set the height of an element and then set overflow:auto (this will give you scroll bars when needed).
Its very hard to get rows of a table to scroll properly. I've been trying with things such as wrapping a table row in a div (or vice versa) and setting a max-height and overflow of that div.
That's the best I can do with out seeing what you are trying to do.
function ResizeCells(table, cornerDiv, headerRowDiv, headerColumnDiv, bodyDiv)
{
var childElement = 0;
if (table.childNodes[0].tagName == null)
{
childElement = 1;
}
SetWidth(
cornerDiv.childNodes[childElement].childNodes[childElement].childNodes[0].childNodes[childElement],
headerColumnDiv.childNodes[childElement].childNodes[childElement].childNodes[0].childNodes[0]);
SetHeight(
cornerDiv.childNodes[childElement].childNodes[childElement].childNodes[0].childNodes[childElement],
headerRowDiv.childNodes[childElement].childNodes[childElement].childNodes[0].childNodes[childElement]);
var headerRowColumns = headerRowDiv.childNodes[childElement].childNodes[childElement].childNodes[0].childNodes;
var bodyColumns = bodyDiv.childNodes[childElement].childNodes[childElement].childNodes[0].childNodes;
for (i = 0; i < headerRowColumns.length; i++)
{
if (headerRowColumns[i].tagName == "TD" || headerRowColumns[i].tagName == "TH")
{
SetWidth(
headerRowColumns[i],
bodyColumns[i],
i == headerRowColumns.length - 1);
}
}
var headerColumnRows = headerColumnDiv.childNodes[childElement].childNodes[childElement].childNodes;
var bodyRows = bodyDiv.childNodes[childElement].childNodes[childElement].childNodes;
for (i = 0; i < headerColumnRows.length; i++)
{
if (headerColumnRows[i].tagName == "TR")
{
SetHeight(
headerColumnRows[i].childNodes[0],
bodyRows[i].childNodes[childElement],
i == headerColumnRows.length - 1);
}
}
}
function SetWidth(element1, element2, isLastColumn)
{
// alert(element2 + "\n\n" + element2.offsetWidth);
var diff = paddingLeft + paddingRight;
if (element1.offsetWidth < element2.offsetWidth)
{
element1.childNodes[0].style.width = element2.offsetWidth - diff + "px";
element2.childNodes[0].style.width = element2.offsetWidth - diff + "px";
}
else
{
element2.childNodes[0].style.width = element1.offsetWidth - diff + "px";
element1.childNodes[0].style.width = element1.offsetWidth - diff + "px";
}
}
function SetHeight(element1, element2, isLastRow)
{
var diff = paddingTop + paddingBottom;
if (element1.offsetHeight < element2.offsetHeight)
{
element1.childNodes[0].style.height = element2.offsetHeight - diff + "px";
element2.childNodes[0].style.height = element2.offsetHeight - diff + "px";
}
else
{
element2.childNodes[0].style.height = element1.offsetHeight - diff + "px";
element1.childNodes[0].style.height = element1.offsetHeight - diff + "px";
}
}
function SyncScroll()
{
for (i = 0; i < arrayCount; i++)
{
headerRowDivs[i].scrollLeft = bodyDivs[i].scrollLeft;
headerColumnDivs[i].scrollTop = bodyDivs[i].scrollTop;
}
}
I appoligize, this part will not format no matter what I do, sorry about the poor formatting.
In ZedGraph, how do I show text labels for each point and in the XAxis all together?
If I do
myPane.XAxis.Type = AxisType.Text;
myPane.XAxis.Scale.TextLabels = array_of_string;
I get labels on the XAxis like this
And if I do
for (int i = 0; i < myCurve.Points.Count; i++)
{
PointPair pt = myCurve.Points[i];
// Create a text label from the Y data value
TextObj text = new TextObj(
pt.Y.ToString("f0"), pt.X, pt.Y + 0.1,
CoordType.AxisXYScale, AlignH.Left, AlignV.Center);
text.ZOrder = ZOrder.A_InFront;
text.FontSpec.Angle = 0;
myPane.GraphObjList.Add(text);
}
I get labels on the curve, like this
But if I do both at the same time, labels on the curve disappear.
Is there a way to combine both kind of labels?
I've changed my answer after you clarified the question.
You just have to remember to position the labels correctly:
<%
System.Collections.Generic.List<ZedGraphWebPointPair> points = new System.Collections.Generic.List<ZedGraphWebPointPair>();
for (int i = 0; i < 15; i++)
{
// Let's have some fun with maths
points.Add(new ZedGraphWebPointPair
{
X = i,
Y = Math.Pow(i - 10, 2) * -1 + 120
});
}
System.Collections.Generic.List<string> XAxisLabels = new System.Collections.Generic.List<string>();
TestGraph.CurveList.Add(new ZedGraphWebLineItem { Color = System.Drawing.Color.Red });
TestGraph.XAxis.Scale.FontSpec.Size = 9;
int j = 1;
foreach (ZedGraphWebPointPair point in points)
{
// Add the points we calculated
TestGraph.CurveList[0].Points.Add(point);
// Add the labels for the points
TestGraph.GraphObjList.Add(new ZedGraphWebTextObj
{
Location =
{
CoordinateFrame = ZedGraph.CoordType.XChartFractionYScale,
// Make sure we position them according to the CoordinateFrame
X = Convert.ToSingle(j) / points.Count - 0.05f,
Y = Convert.ToSingle(point.Y) + 3f,
AlignV = ZedGraph.AlignV.Top
},
Text = point.Y.ToString(),
FontSpec = { Angle = 90, Size = 9, Border = { IsVisible = false } }
});
// Add the labels for the XAxis
XAxisLabels.Add(String.Format("P{0}", j));
j++;
}
TestGraph.RenderGraph += delegate(ZedGraphWeb zgw, System.Drawing.Graphics g, ZedGraph.MasterPane mp)
{
ZedGraph.GraphPane gp = mp[0];
gp.XAxis.Type = ZedGraph.AxisType.Text;
gp.XAxis.Scale.TextLabels = XAxisLabels.ToArray();
};
%>
That code will produce this graph:
If the axis type is text, the code below is easier to get x-coordinates of the points ;)
for (int tPoint = 0; tPoint < curve.Points.Count; tPoint++)
{
TextObj text = new TextObj(curve.Points[tPoint].Y.ToString(), curve.Points[tPoint].X, curve.Points[tPoint].Y + 10);
}