Back To Start Of Archive
Taken From The Forum: Help & Support for DHTML Menu Version 5+
Forum Topic: Click to view post
Last Updated: Saturday July 14 2012 - 06:07:26
Menu width increasing in multiples of 21
Poster: moholland
Dated: Thursday July 3 2003 - 2:59:39 BST
This is going to sound really crazy but I have a client that wants the menu widths to increase only in multiples of 21pixels. This would be ok if everything was static but unfortunately the menus are being built from a sql db. So, is there an easy way to tweak the menu system to increase widths only in multiples of 21pixels? If not, the fall back is to have a field in the db but there are hundreds of menu items and it will be a maintenance nightmare. Thanks for your help and your menu system is truly amazing.
Poster: zotsf
Dated: Thursday July 3 2003 - 6:15:56 BST
you could try setting the width to a function rather than an int. I've successfully set the menu parameters with javascript variables. If it were a function, you could loop and increase every time it's called.
Dynamically Setting Width
Poster: Hergio
Dated: Thursday July 3 2003 - 20:34:54 BST
Ok here goes, I did alittle research and should be able to help you out. I am guessing that since you are in the version 4 forum, you are asking how to do this in the new version. But just in case, I am going to cover both versions.
For version 3:
As far as I could see, there is no way to 'on-the-fly' pick a width for your menu or the items in it. But immediately after you create one of your menus (after you've added all the items to it), you can reset the width to whatever you like. And I am assuming that since you are creating this from a DB, you have some sort of loop that is looping through and writing each line of code for each menu item. As you are doing this, record the width of the string and determine from that if you've passed, for example 21px, and you should jump to 42px. Immediately after writing out all your menu items, lets say that during the looping you determined that the longest string would take up 35px (youll need 42)....so write
menu[3] = ceil(35/21)*21;
which should set the width property to 2*21 or 42 for you. menu[3] is the array spot for the menus final width. Because the menu hasn't fully rendered at this point, you can still go back and change its value. Once you start another menu, I dont see a way of getting back. I am sure theres a way, but I stopped here since its easy enough to do it from here.
For version 4 ( or 5RC1, ya know, the new one):
As stated above, you are looping through each row in the DB as you output the javascript lines, ie the aI(...) lines of code. As you are doing this, determine how many pixels long your string is going to be when you write it out. Let say it also ends up needing 35px. Using similar logic as above, you'll need to figure out you need a width of 42px to keep with your client's NEED to increase in 21px increments. Once you've determined you'll need 42px, in your aI statement, write:
aI("text=LinkText;url=http://wwwlinkUrl.com;itemwidth=42;");
Notice the itemwidth flag, you are allowed to do this on the fly in a menu item declaration. The final menu will assume the size of the largest width specified. So if you have 3 items in your menu, which have been determined to take up 10 20 and 35 px, your menu declarations should read 21, 21, and 42. The menu will then render at 42px wide.
I tried this out with a small dataset and as far as I can tell it worked fine. I didnt do the DB part of it. I did this all in an hour or so, so forgive me for any errors. Hopefully this will help!
Good luck!
Poster: moholland
Dated: Thursday July 3 2003 - 21:00:07 BST
Hergio, sounds great but how do I determine the width of the string as I'm looping through each row? Is there a way to calculate the width of non monospaced characters or am I'm totally missing something? For example, 'Tilling' & 'Whether' are both 7 characters but 'Whether' is significantly longer so I can not just calculate each character. Thanks for your help.
Poster: Hergio
Dated: Friday July 4 2003 - 4:50:25 BST
That is definetly the problem at hand. As I was writing that response, I was thinking the same thing. As far as I can tell, whether your in SQL or in the code on the page, you really can't 'measure' the pixels occupied by a string. If you REALLY want to get this thing perfect, you could through your characterset into photoshop or something and measure each character and then have a quick function that whips through a string and tells you an approximate pixel length.
Heres another thing you may try. If you are using version 3, you can go back and reset the menus width. But if you don't specify a width, and finish writing all the items, I wonder if the menu[3] field contains the width it may draw based on whats entered. I doubt it, but its worth a try.
For the v4, I can't seem to think of a way other than hand measuring. I will look into this farther (it wont be until after the july 4th weekend) but I will see if theres a way to pull up the menu's width after the fact. If you can, then I am sure theres a way to set it after the fact. So you could get it, check to see if its greater than 21, and if so, bump it up to 42.
We'll figure this one out; one way or another!!
Poster: moholland
Dated: Monday July 7 2003 - 15:02:56 BST
Hergio, sounds very promising... thanks for the help.
Poster: Hergio
Dated: Monday July 7 2003 - 17:04:39 BST
Alrighty, I think I've got it. Take a look at this code, edit it as you like. Place this code AFTER the line of code...
"for(_a=_mnucnt;_a<_m.length;_a++){_drawMenu(_a)}"
in the data.js file. I will explain the code below in detail afterwards. Also, do not specify ANYWHERE in your menu declarations an itemwidth. When the item strings are placed into each menu, they will push out the menu as far as required, I then read that value, figure out if its a multiple of 21, and if not, push it up to the next multiple of 21. Specifying a hardcoded itemwidth would screw it up.
for( i=1; i<_m.length; i++)
{
menuName = _m[i][1];
mn = getMenuByName(menuName);
menuobject=gmobj("menu"+mn);
defaultTableWidth = menuobject.firstChild.clientWidth; //width of items table
defaultPadding = parseInt( menuobject.style.padding ); //get rid of 'px'
newWidth = 21 * Math.ceil(defaultTableWidth/21);
newItemWidth = newWidth;
newMenuWidth = new Number(newWidth) + (2 * defaultPadding);
menuobject.style.width = newMenuWidth;
menuobject.firstChild.style.width = newItemWidth;
}
Explanation:
_m is an array which holds ALL menus in your page. Starting with 0 up through all menus including subs. If a menu has a sub, it will be _m[3] and its child will be _m[4], it goes in that order. The reason I start at 1 and NOT 0 is because _m[0] is your main top menu and I didnt think you'd want to edit that, but you can if you change it to start at 0.
_[m][i] is the name of the menu, using that I grab the menu object itself. Inside each menu there is a table that takes the width of the largest item in the menu, this is the defaultTableWidth which is found in the firstChild of the menu. I also grab the padding because you may have padding set in your page. ClientWidth is what the width of the table is; based on the text inside of it. I take that, find if its a multiple of 21 and if not, I up it to the next multiple of 21. I then set the item's width back to the multiple of 21 and the menu back to the multiple plus the padding. This leaves your menus slightly bigger due to padding, but you should be able to tweak this to your liking.
Hopefully this will help you out some. Best of luck!
Poster: moholland
Dated: Friday July 11 2003 - 2:28:36 BST
Hergio, Thanks for the help but I couldn't get it to work. I think I did everything you said to do but it didn't seem to make the width change. It appeared to just increase it as if there wasn't a specified width. I kind of gave up because I think our client is going to approve it without the multiple of 21 restraint. But thanks again for your help.