Posted By

jatkins on 06/21/12


Tagged

algorithm graphics sparsematrix


Versions (?)

Experimenting with a sparse matrix fill algorithm


 / Published in: JavaScript
 

it's got the beginnings of the gradient designer now

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>Pie Chart Generator</title>
  6. <script type="text/javascript">
  7. // <![CDATA[
  8. if(!Object.keys) Object.keys = function(o) { // from http://tokenposts.blogspot.com.au/2012/04/javascript-objectkeys-browser.html
  9. if(o!==Object(o))
  10. throw new TypeError('Object.keys called on a non-object');
  11. var k = [], p;
  12. for (p in o) {
  13. if(Object.prototype.hasOwnProperty.call(o,p))
  14. k.push(p);
  15. }
  16. return k;
  17. };
  18.  
  19. var misc = {
  20. math: {
  21. pythagoras: function(length1, length2) {
  22. return Math.sqrt(Math.pow(length1, 2)+Math.pow(length2, 2));
  23. },
  24. distanceBetweenTwoPoints: function(point1, point2) {
  25. return this.pythagoras(point2.x-point1.x, point2.y-point1.y);
  26. },
  27. justNumber: function(stringToParse) {
  28. return parseFloat(stringToParse.toString().replace(/[^0-9\.\-]+/, ''));
  29. },
  30. degToRad: function(angleInDegrees) {
  31. return angleInDegrees * Math.PI / 180;
  32. }
  33. },
  34.  
  35. js: {
  36. getRandomColor: function() {
  37. return 'rgb('+Math.round(Math.random()*254)+', '+Math.round(Math.random()*254)+', '+Math.round(Math.random()*254)+')';
  38. },
  39. getRealPosition: function (elmnt) { // based on http://www.quirksmode.org/js/findpos.html
  40. elmnt = typeof elmnt == 'object' ? elmnt : document.getElementById(elmnt);
  41. elmntLeft = elmnt.offsetLeft;
  42. elmntTop = elmnt.offsetTop;
  43. while(elmnt = elmnt.offsetParent) {
  44. elmntLeft += elmnt.offsetLeft;
  45. elmntTop += elmnt.offsetTop;
  46. }
  47. return {x: elmntLeft, y: elmntTop};
  48. },
  49. positionBelow: function(anchorElement, elementToPosition, xExtra, yExtra) {
  50. if(typeof elementToPosition=='string')
  51. elementToPosition = document.getElementById(elementToPosition);
  52.  
  53. var realAnchorPosition = this.getRealPosition(anchorElement);
  54.  
  55. var yExtra = yExtra || 0, xExtra = xExtra || 0;
  56.  
  57. elementToPosition.style.top = realAnchorPosition.y + anchorElement.offsetHeight + yExtra + 'px';
  58. elementToPosition.style.left = realAnchorPosition.x + xExtra + 'px';
  59. elementToPosition.style.position = 'absolute';
  60. }
  61. }
  62. }
  63.  
  64. var pieChart = function(pieName, radius, pieData) {
  65. var pieDiv = document.createElement('div'),
  66. radiusSquared = Math.pow(radius, 2);
  67.  
  68. pieDiv.id = pieName;
  69. pieDiv.className = 'chart';
  70. pieDiv.style.width = radius * 2 + 'px';
  71. pieDiv.style.height = radius * 2 + 'px';
  72. document.body.appendChild(pieDiv);
  73.  
  74. this.renderPoint = function(x, y, pointColor) {
  75. var newPoint = document.createElement('span');
  76. newPoint.style.left = x + radius + 'px';
  77. newPoint.style.top = y + radius + 'px';
  78. newPoint.style.backgroundColor = pointColor;
  79. pieDiv.appendChild(newPoint);
  80. return {x: x+radius, y: y+radius};
  81. };
  82.  
  83. this.renderCircle = function(sparseMatrix) {
  84. var x = -radius;
  85. while(x<radius) {
  86. x++;
  87. y = Math.sqrt(radiusSquared - Math.pow(x, 2));
  88. this.renderPoint(x, y); // for the bottom semicircle
  89. this.renderPoint(x, -y); // for the top semicircle
  90.  
  91. if(!sparseMatrix['x'+x])
  92. sparseMatrix['x'+x] = [];
  93. sparseMatrix['x'+x]['y'+y] = '#000000';
  94. sparseMatrix['x'+x]['y-'+y] = '#000000';
  95. }
  96.  
  97. return sparseMatrix;
  98. };
  99.  
  100. this.rotatePoint = function(origPoint, cosTheta, sinTheta) {
  101. return {x: origPoint.x*cosTheta - origPoint.y*sinTheta, y: origPoint.x*sinTheta + origPoint.y*cosTheta};
  102. };
  103.  
  104. this.renderLine = function(startPoint, endPoint, rotateBy, lineColor, sparseMatrix) { // render a straight line (y=mx+c)
  105. var rotateByInRadians = misc.math.degToRad(rotateBy), cosTheta, sinTheta;
  106. cosTheta = Math.cos(rotateByInRadians);
  107. sinTheta = Math.sin(rotateByInRadians);
  108.  
  109. startPoint = this.rotatePoint(startPoint, cosTheta, sinTheta);
  110. endPoint = this.rotatePoint(endPoint, cosTheta, sinTheta);
  111.  
  112. var tempPoint, width, height, gradient, yIntercept, i = 0, pointCount, switchPoint = false;
  113.  
  114. if(misc.math.distanceBetweenTwoPoints(startPoint, {x: 0, y: 0})>misc.math.distanceBetweenTwoPoints({x: 0, y: 0}, endPoint)) {
  115. tempPoint = startPoint;
  116. startPoint = endPoint;
  117. endPoint = tempPoint;
  118. }
  119.  
  120. width = Math.abs(endPoint.x - startPoint.x);
  121. height = Math.abs(endPoint.y - startPoint.y);
  122. gradient = (endPoint.y - startPoint.y) / (endPoint.x - startPoint.x);
  123.  
  124. yIntercept = endPoint.y - gradient * endPoint.x;
  125. distance = misc.math.distanceBetweenTwoPoints(startPoint, endPoint);
  126.  
  127. var calcXCoord = function(y) {
  128. var x = (y - yIntercept) / gradient;
  129. return ((gradient == Infinity) || (Math.abs(x) == Infinity)) ? startPoint.x : x;
  130. };
  131. var calcYCoord = function(x) {
  132. return Math.abs(gradient) == Infinity ? startPoint.y : gradient * x + yIntercept;
  133. };
  134. pointCount = width > height ? width : height;
  135.  
  136. if(width>height) {
  137. if(endPoint.x<startPoint.x)
  138. switchPoint = true;
  139. }
  140. else {
  141. if(endPoint.y<startPoint.y)
  142. switchPoint = true;
  143. }
  144.  
  145. var currentPoint;
  146. while(i<pointCount) {
  147. if(width>height)
  148. currentPoint = {x: parseInt((switchPoint?endPoint:startPoint).x)+i, y: calcYCoord(parseInt((switchPoint?endPoint:startPoint).x)+i)};
  149. else
  150. currentPoint = {x: calcXCoord(parseInt((switchPoint?endPoint:startPoint).y)+i), y: parseInt((switchPoint?endPoint:startPoint).y)+i};
  151. this.renderPoint(currentPoint.x, currentPoint.y, lineColor);
  152.  
  153. if(!sparseMatrix['x'+currentPoint.x])
  154. sparseMatrix['x'+currentPoint.x] = [];
  155. sparseMatrix['x'+currentPoint.x]['y'+currentPoint.y] = lineColor;
  156.  
  157. i++;
  158. }
  159.  
  160. return sparseMatrix;
  161. };
  162.  
  163. // draw sectors
  164. var lineColor = misc.js.getRandomColor(), currentAngle = 0, sectorAngles = [], dataSum = 0, sectorColors = [];
  165.  
  166. for(var i=0;i<pieData.length;i++)
  167. dataSum += pieData[i][1];
  168.  
  169. var cumulativeAngle = 0, pieSparseMatrix = [];
  170. for(var i=0;i<pieData.length;i++) {
  171. cumulativeAngle += pieData[i][1] / dataSum * 360;
  172. pieSparseMatrix = this.renderLine({x: 0, y: -radius}, {x: 0, y: 0}, cumulativeAngle, misc.js.getRandomColor(), pieSparseMatrix);
  173. }
  174. var pieLegend = document.createElement('ul');
  175. pieLegend.style.left = radius*2 + 'px';
  176. for(var i=0;i<pieData.length;i++) {
  177. var newLegendLI = document.createElement('li'), newLegendBlock = document.createElement('span');
  178. newLegendLI.style.color = sectorColors[i];
  179. newLegendLI.appendChild(document.createTextNode(pieData[i][0]));
  180. pieLegend.appendChild(newLegendLI);
  181. }
  182. pieDiv.appendChild(pieLegend);
  183.  
  184. var pieSparseMatrix = [];
  185. //pieSparseMatrix = this.renderCircle(pieSparseMatrix);
  186. this.renderCircle([]); // if we leave the circle out of the matrix, it won't be filled in
  187.  
  188. var pointSets = [
  189. [[200, 300], [400, 300], [300, 200], [200, 300]], // top triangle
  190. [[200, 250], [300, 350], [400, 250], [200, 250]], // bottom triangle
  191.  
  192. [[50, 0], [250, 0], [250, 100], [50, 100], [50, 0]], // outer rectangle
  193. [[0, 50], [200, 50], [200, 150], [0, 150], [0, 50]], // inner rectangle
  194. [[50, 0], [0, 50]], // connect at top-left
  195. [[250, 0], [200, 50]], // connect at top-right
  196. [[50, 100], [0, 150]], // connect at bottom-left
  197. [[250, 100], [200, 150]] // connect at bottom-right
  198. ];
  199.  
  200. for(var i=0;i<pointSets.length;i++) {
  201. for(var j=0;j<pointSets[i].length-1;j++)
  202. pieSparseMatrix = this.renderLine({x: pointSets[i][j][0], y: pointSets[i][j][1]}, {x: pointSets[i][j+1][0], y: pointSets[i][j+1][1]}, 0, '#000000', pieSparseMatrix);
  203. }
  204.  
  205. var numericalSort = function(a, b) {
  206. return parseFloat(a.replace(/[^0-9\-\.]/g, '')) - parseFloat(b.replace(/[^0-9\-\.]/g, ''));
  207. };
  208.  
  209. var currentColor;
  210.  
  211. this.fillWithGradient = function(startColor, endColor) {
  212. for(var i=0;i<3;i++) {
  213. startColor[i] = parseInt(startColor[i]);
  214. endColor[i] = parseInt(endColor[i]);
  215. }
  216.  
  217. var sMatColNames = Object.keys(pieSparseMatrix).sort(numericalSort), sMatRowNames = [], fillColor = startColor, fillIncrement = [];
  218. for(var i=0;i<3;i++)
  219. fillIncrement[i] = Math.round((endColor[i]-startColor[i])/sMatColNames.length*1000)/1000;
  220.  
  221. for(var j=0;j<sMatColNames.length;j++) {
  222. sMatRowNames = Object.keys(pieSparseMatrix[sMatColNames[j]]).sort(numericalSort);
  223. for(var k=0;k<sMatRowNames.length-1;k++) {
  224. if(pieSparseMatrix[sMatColNames[j]][sMatRowNames[k]]!=fillColor&&pieSparseMatrix[sMatColNames[j]][sMatRowNames[k+1]]!=fillColor) { // fill between these points
  225. for(var l=parseFloat(sMatRowNames[k].substring(1))+1;l<parseFloat(sMatRowNames[k+1].substring(1));l++)
  226. this.renderPoint(parseFloat(sMatColNames[j].substring(1)), l, 'rgb('+Math.round(fillColor[0])+', '+Math.round(fillColor[1])+', '+Math.round(fillColor[2])+')');
  227. k++;
  228. }
  229. }
  230.  
  231. fillColor[0] += fillIncrement[0];
  232. fillColor[1] += fillIncrement[1];
  233. fillColor[2] += fillIncrement[2];
  234. }
  235. };
  236. };
  237.  
  238. var widgets = {
  239. colorPicker: function() {
  240. var shadeIncrement, currentColorBox, currentShadePreview, shadeAdjustmentTimer, pickerDivChildren = {};
  241. this.setColorBox = function(newColorBox) {
  242. currentColorBox = newColorBox;
  243. }
  244. this.getColorBox = function() {
  245. return currentColorBox;
  246. };
  247. var pickerDiv = document.createElement('div');
  248. this.pickerDiv = pickerDiv;
  249. var adjustShade = function() {
  250. var shadeColor = currentShadePreview.parentNode.childNodes[1].style.backgroundColor.replace(/[^0-9\-\,]/g, '').split(','), colorToChange = currentShadePreview.parentNode.childNodes[1].id.indexOf('Red') == -1 ? (currentShadePreview.parentNode.childNodes[1].id.indexOf('Green') == -1 ? 2 : 1) : 0;
  251.  
  252. shadeColor[0] = 0;
  253. shadeColor[1] = 0;
  254. shadeColor[2] = 0;
  255. shadeColor[colorToChange] = misc.math.justNumber(currentShadePreview.parentNode.childNodes[1].value);
  256.  
  257. if((shadeIncrement==1&&shadeColor[colorToChange]<100)||(shadeIncrement==-1&&shadeColor[colorToChange]>0))
  258. shadeColor[colorToChange] += shadeIncrement;
  259.  
  260. currentShadePreview.parentNode.childNodes[1].style.backgroundColor = 'rgb('+shadeColor[0]+'%, '+shadeColor[1]+'%, '+shadeColor[2]+'%)';
  261. currentShadePreview.parentNode.childNodes[1].value = shadeColor[colorToChange] + '%';
  262.  
  263. if(currentColorBox.value=='')
  264. currentColorBox.style.backgroundColor = currentShadePreview.parentNode.childNodes[1].style.backgroundColor;
  265.  
  266. var currentRGBColor = Math.round(255-(misc.math.justNumber(txtRed.value)/100*255)) + ',' + Math.round(255-(misc.math.justNumber(txtGreen.value)/100*255)) + ',' + Math.round(255-(misc.math.justNumber(txtBlue.value)/100*255));
  267.  
  268. var currentRGBColor = [Math.round(misc.math.justNumber(txtRed.value)/100*255), Math.round(misc.math.justNumber(txtGreen.value)/100*255), Math.round(misc.math.justNumber(txtBlue.value)/100*255)];
  269.  
  270. currentColorBox.style.backgroundColor = 'rgb(' + txtRed.value + ',' + txtGreen.value + ',' + txtBlue.value + ')';
  271. currentColorBox.value = currentColorBox.style.backgroundColor;
  272. currentColorBox.style.color = 'rgb(' + (255-currentRGBColor[0]) + ',' + (255-currentRGBColor[1]) + ',' + (255-currentRGBColor[2]) + ')'; // set the text color to the inverse of the background color
  273.  
  274. updateSelectedColor(currentRGBColor.join(','));
  275.  
  276. if(shadeAdjustmentTimer)
  277. clearTimeout(shadeAdjustmentTimer);
  278. shadeAdjustmentTimer = setTimeout(adjustShade, navigator.appName=='Microsoft Internet Explorer'?50:1);
  279. },
  280. incShade = function() {
  281. currentShadePreview = this;
  282. shadeIncrement = 1;
  283. adjustShade();
  284. },
  285. decShade = function() {
  286. currentShadePreview = this;
  287. shadeIncrement = -1;
  288. adjustShade();
  289. },
  290. endShadeAdjustment = function() {
  291. clearTimeout(shadeAdjustmentTimer);
  292. };
  293.  
  294. var updateSelectedColor = function(rgbColorCode) {
  295. if(colorNames[rgbColorCode]) {
  296. document.getElementById('colorListDropDown').childNodes[0].childNodes[0].childNodes[2].data = colorNames[rgbColorCode];
  297. document.getElementById('colorListDropDown').childNodes[0].childNodes[0].childNodes[1].style.background = 'rgb(' + rgbColorCode + ')';
  298. }
  299. else {
  300. document.getElementById('colorListDropDown').childNodes[0].childNodes[0].childNodes[2].data = 'Custom';
  301. document.getElementById('colorListDropDown').childNodes[0].childNodes[0].childNodes[1].style.background = 'url(customColor.png) center center no-repeat';
  302. }
  303. };
  304. this.updateSelectedColor = updateSelectedColor;
  305.  
  306. var colorListSelect = function(selectedItem) {
  307. var selectedColor = selectedItem.childNodes[0].style.backgroundColor.replace(/[^0-9\-\,]/g, '').split(',');
  308. txtRed.value = Math.round(selectedColor[0] / 255 * 100) + '%';
  309. txtRed.style.backgroundColor = 'rgb('+selectedColor[0]+',0,0)';
  310. txtGreen.value = Math.round(selectedColor[1] / 255 * 100) + '%';
  311. txtGreen.style.backgroundColor = 'rgb(0,'+selectedColor[1]+',0)';
  312. txtBlue.value = Math.round(selectedColor[2] / 255 * 100) + '%';
  313. txtBlue.style.backgroundColor = 'rgb(0,0,'+selectedColor[0]+')';
  314.  
  315. currentColorBox.value = 'rgb('+selectedColor.join(', ')+')';
  316. currentColorBox.style.backgroundColor = currentColorBox.value;
  317. currentColorBox.style.color = 'rgb('+(255-selectedColor[0])+', '+(255-selectedColor[1])+', '+(255-selectedColor[2])+')';
  318. };
  319. var colorListDropDown = new widgets.visualDropDown('colorListDropDown', colorListSelect);
  320. var colorNames = [];
  321. colorNames['255,255,255'] = 'White';
  322. colorNames['192,192,192'] = 'Silver';
  323. colorNames['128,128,128'] = 'Gray';
  324. colorNames['0,0,0'] = 'Black';
  325. colorNames['255,0,0'] = 'Red';
  326. colorNames['128,0,0'] = 'Maroon';
  327. colorNames['255,255,0'] = 'Yellow';
  328. colorNames['128,128,0'] = 'Olive';
  329. colorNames['0,255,0'] = 'Lime';
  330. colorNames['0,128,0'] = 'Green';
  331. colorNames['0,255,255'] = 'Aqua';
  332. colorNames['0,128,128'] = 'Teal';
  333. colorNames['0,0,255'] = 'Blue';
  334. colorNames['0,0,128'] = 'Navy';
  335. colorNames['255,0,255'] = 'Fushsia';
  336. colorNames['128,0,128'] = 'Purple';
  337. for(colorName in colorNames)
  338. colorListDropDown.addItem(colorNames[colorName], colorName);
  339.  
  340. var pickerDivChildren = {
  341. redShadeContainer: document.createElement('span'),
  342. greenShadeContainer: document.createElement('span'),
  343. blueShadeContainer: document.createElement('span'),
  344. br1: document.createElement('br'),
  345. colorList: document.getElementById('colorListDropDown'),
  346. br2: document.createElement('br'),
  347. collapseLink: document.createElement('a')
  348. };
  349.  
  350. var lblRed = document.createElement('label'), txtRed = document.createElement('input');
  351.  
  352. lblRed.appendChild(document.createTextNode('Red'));
  353. lblRed.setAttribute('for', 'txtRed');
  354.  
  355. txtRed.id = 'txtRed';
  356. txtRed.type = 'text';
  357. txtRed.className = 'colorPreview';
  358. txtRed.value = '100%';
  359. txtRed.style.backgroundColor = 'rgb(255, 0, 0)';
  360.  
  361. var btnIncRed = document.createElement('button'), btnDecRed = document.createElement('button');
  362.  
  363. btnIncRed.onmousedown = incShade;
  364. btnIncRed.onmouseup = endShadeAdjustment;
  365. btnIncRed.appendChild(document.createTextNode('+'));
  366.  
  367. btnDecRed.onmousedown = decShade;
  368. btnDecRed.onmouseup = endShadeAdjustment;
  369. btnDecRed.appendChild(document.createTextNode('-'));
  370.  
  371. pickerDivChildren.redShadeContainer.className = 'shadeContainer';
  372. pickerDivChildren.redShadeContainer.appendChild(lblRed);
  373. pickerDivChildren.redShadeContainer.appendChild(txtRed);
  374. pickerDivChildren.redShadeContainer.appendChild(document.createElement('br'));
  375. pickerDivChildren.redShadeContainer.appendChild(btnIncRed);
  376. pickerDivChildren.redShadeContainer.appendChild(btnDecRed);
  377.  
  378. var lblGreen = document.createElement('label'), txtGreen = document.createElement('input');
  379.  
  380. lblGreen.appendChild(document.createTextNode('Green'));
  381. lblGreen.setAttribute('for', 'txtGreen');
  382.  
  383. txtGreen.id = 'txtGreen';
  384. txtGreen.type = 'text';
  385. txtGreen.className = 'colorPreview';
  386. txtGreen.value = '100%';
  387. txtGreen.style.backgroundColor = 'rgb(0, 255, 0)';
  388.  
  389. var btnIncGreen = document.createElement('button'), btnDecGreen = document.createElement('button');
  390.  
  391. btnIncGreen.onmousedown = incShade;
  392. btnIncGreen.onmouseup = endShadeAdjustment;
  393. btnIncGreen.appendChild(document.createTextNode('+'));
  394.  
  395. btnDecGreen.onmousedown = decShade;
  396. btnDecGreen.onmouseup = endShadeAdjustment;
  397. btnDecGreen.appendChild(document.createTextNode('-'));
  398.  
  399. pickerDivChildren.greenShadeContainer.className = 'shadeContainer';
  400. pickerDivChildren.greenShadeContainer.appendChild(lblGreen);
  401. pickerDivChildren.greenShadeContainer.appendChild(txtGreen);
  402. pickerDivChildren.greenShadeContainer.appendChild(document.createElement('br'));
  403. pickerDivChildren.greenShadeContainer.appendChild(btnIncGreen);
  404. pickerDivChildren.greenShadeContainer.appendChild(btnDecGreen);
  405.  
  406. var lblBlue = document.createElement('label'), txtBlue = document.createElement('input');
  407.  
  408. lblBlue.appendChild(document.createTextNode('Blue'));
  409. lblBlue.setAttribute('for', 'txtBlue');
  410.  
  411. txtBlue.id = 'txtBlue';
  412. txtBlue.type = 'text';
  413. txtBlue.className = 'colorPreview';
  414. txtBlue.value = '100%';
  415. txtBlue.style.backgroundColor = 'rgb(0, 0, 255)';
  416.  
  417. var btnIncBlue = document.createElement('button'), btnDecBlue = document.createElement('button');
  418.  
  419. btnIncBlue.onmousedown = incShade;
  420. btnIncBlue.onmouseup = endShadeAdjustment;
  421. btnIncBlue.appendChild(document.createTextNode('+'));
  422.  
  423. btnDecBlue.onmousedown = decShade;
  424. btnDecBlue.onmouseup = endShadeAdjustment;
  425. btnDecBlue.appendChild(document.createTextNode('-'));
  426.  
  427. pickerDivChildren.blueShadeContainer.className = 'shadeContainer';
  428. pickerDivChildren.blueShadeContainer.appendChild(lblBlue);
  429. pickerDivChildren.blueShadeContainer.appendChild(txtBlue);
  430. pickerDivChildren.blueShadeContainer.appendChild(document.createElement('br'));
  431. pickerDivChildren.blueShadeContainer.appendChild(btnIncBlue);
  432. pickerDivChildren.blueShadeContainer.appendChild(btnDecBlue);
  433.  
  434. var collapsePickerDiv = function() {
  435. pickerDiv.className = 'hidden';
  436. };
  437.  
  438. var collapseIMG = document.createElement('img');
  439. collapseIMG.src = 'collapse.png';
  440. collapseIMG.alt = '[Collapse]';
  441. collapseIMG.title = 'Collapse Color Picker';
  442. pickerDivChildren.collapseLink.appendChild(collapseIMG);
  443. pickerDivChildren.collapseLink.className = 'collapse';
  444. pickerDivChildren.collapseLink.href = '#';
  445. pickerDivChildren.collapseLink.onclick = collapsePickerDiv;
  446.  
  447. var pickerDivChildrenKeys = Object.keys(pickerDivChildren);
  448. for(var i=0;i<pickerDivChildrenKeys.length;i++)
  449. this.pickerDiv.appendChild(pickerDivChildren[pickerDivChildrenKeys[i]]);
  450.  
  451. this.pickerDiv.className = 'pickerDiv hidden';
  452. },
  453. gradientSelector: function() {
  454. this.show = function() {
  455. selectorDiv.className = 'gradientSelector';
  456. selectorDiv.childNodes[selectorDiv.childNodes.length-2].style.width/*(the gradient designer)*/ = misc.js.getRealPosition(selectorDiv.childNodes[selectorDiv.childNodes.length-3]).x/*(the '...' button)*/ + selectorDiv.childNodes[selectorDiv.childNodes.length-3].offsetWidth - misc.js.getRealPosition(selectorDiv.childNodes[selectorDiv.childNodes.length-5]).x/*(the label)*/ + 'px';
  457. };
  458. this.hide = function() {
  459. selectorDiv.className = 'gradientSelector hidden';
  460. };
  461. this.isVisible = function() {
  462. return selectorDiv.className.indexOf('hidden') == -1;
  463. };
  464.  
  465. var selectColorToEdit = function() {
  466. gsColorPicker.setColorBox(this.previousSibling);
  467. var currentColor = gsColorPicker.getColorBox().value.replace(/[^0-9\-\,]/g, '').split(',');
  468. if(currentColor=='')
  469. currentColor = [255, 255, 255];
  470. txtRed.value = Math.round(currentColor[0] / 255 * 100) + '%';
  471. txtRed.style.backgroundColor = 'rgb(' + currentColor[0] + ', 0, 0)';
  472. txtGreen.value = Math.round(currentColor[1] / 255 * 100) + '%';
  473. txtGreen.style.backgroundColor = 'rgb(0, ' + currentColor[1] + ', 0)';
  474. txtBlue.value = Math.round(currentColor[2] / 255 * 100) + '%';
  475. txtBlue.style.backgroundColor = 'rgb(0, 0, ' + currentColor[2] + ')';
  476.  
  477. gsColorPicker.updateSelectedColor(currentColor[0]+','+currentColor[1]+','+currentColor[2]);
  478.  
  479. selectorDivChildren.pickerDiv.className = 'pickerDiv';
  480. };
  481.  
  482. var gsColorPicker = new widgets.colorPicker(),
  483. selectorDiv = document.createElement('div'),
  484. selectorDivChildren = {
  485. /*lblStartColor: document.createElement('label'),
  486. txtStartColor: document.createElement('input'),
  487. btnSelectStartColor: document.createElement('button'),
  488. br1: document.createElement('br'),
  489. lblEndColor: document.createElement('label'),
  490. txtEndColor: document.createElement('input'),
  491. btnSelectEndColor: document.createElement('button'),*/
  492.  
  493. lblCurrentColor: document.createElement('label'),
  494. txtCurrentColor: document.createElement('input'),
  495. btnSelectCurrentColor: document.createElement('button'),
  496. gradientDesignDiv: document.createElement('div'),
  497.  
  498. pickerDiv: gsColorPicker.pickerDiv
  499. };
  500. selectorDiv.className = 'gradientSelector hidden'; // hidden by default
  501. this.selectorDiv = selectorDiv;
  502.  
  503. selectorDivChildren.gradientDesignDiv.className = 'gradientDesign';
  504. var hoverBar = document.createElement('span');
  505. hoverBar.className = 'hidden';
  506. selectorDivChildren.gradientDesignDiv.appendChild(hoverBar);
  507.  
  508. selectorDivChildren.gradientDesignDiv.onmousemove = function(e) {
  509. hoverBar.style.backgroundColor = selectorDivChildren.txtCurrentColor.value;
  510. if(hoverBar.className=='hidden')
  511. hoverBar.className = '';
  512. hoverBar.style.left = (e || window.event).clientX - misc.js.getRealPosition(selectorDivChildren.gradientDesignDiv).x - 4 + 'px';
  513. };
  514. selectorDivChildren.gradientDesignDiv.onclick = function(e) {
  515. var newVerticalBar = document.createElement('span');
  516. newVerticalBar.style.left = (e || window.event).clientX - misc.js.getRealPosition(selectorDivChildren.gradientDesignDiv).x - 4 + 'px';
  517. newVerticalBar.style.backgroundColor = selectorDivChildren.txtCurrentColor.value;
  518. this.appendChild(newVerticalBar);
  519.  
  520. hoverBar.className = 'hidden';
  521. };
  522. selectorDivChildren.gradientDesignDiv.onmouseout = function() {
  523. hoverBar.className = 'hidden';
  524. };
  525.  
  526. selectorDivChildren.lblCurrentColor.appendChild(document.createTextNode('Color:'));
  527. selectorDivChildren.lblCurrentColor.setAttribute('for', 'txtCurrentColor');
  528.  
  529. selectorDivChildren.txtCurrentColor.id = 'txtCurrentColor';
  530. selectorDivChildren.txtCurrentColor.type = 'text';
  531. selectorDivChildren.txtCurrentColor.value = 'rgb(255, 255, 255)';
  532.  
  533. selectorDivChildren.btnSelectCurrentColor.appendChild(document.createTextNode('...'));
  534. selectorDivChildren.btnSelectCurrentColor.title = 'Pick Current Color';
  535. selectorDivChildren.btnSelectCurrentColor.onclick = selectColorToEdit;
  536.  
  537. /*selectorDivChildren.lblStartColor.appendChild(document.createTextNode('Start Color:'));
  538. selectorDivChildren.lblStartColor.setAttribute('for', 'txtStartColor');
  539.  
  540. selectorDivChildren.txtStartColor.id = 'txtStartColor';
  541. selectorDivChildren.txtStartColor.type = 'text';
  542. selectorDivChildren.txtStartColor.value = 'rgb(255, 255, 255)';
  543.  
  544. selectorDivChildren.btnSelectStartColor.appendChild(document.createTextNode('...'));
  545. selectorDivChildren.btnSelectStartColor.title = 'Pick Start Color';
  546. selectorDivChildren.btnSelectStartColor.onclick = selectColorToEdit;
  547.  
  548. selectorDivChildren.lblEndColor.appendChild(document.createTextNode('End Color:'));
  549. selectorDivChildren.lblEndColor.setAttribute('for', 'txtEndColor');
  550.  
  551. selectorDivChildren.txtEndColor.id = 'txtEndColor';
  552. selectorDivChildren.txtEndColor.type = 'text';
  553. selectorDivChildren.txtEndColor.value = 'rgb(255, 255, 255)';
  554.  
  555. selectorDivChildren.btnSelectEndColor.appendChild(document.createTextNode('...'));
  556. selectorDivChildren.btnSelectEndColor.title = 'Pick End Color';
  557. selectorDivChildren.btnSelectEndColor.onclick = selectColorToEdit;*/
  558.  
  559. var selectorDivChildrenKeys = Object.keys(selectorDivChildren);
  560. for(var i=0;i<selectorDivChildrenKeys.length;i++)
  561. selectorDiv.appendChild(selectorDivChildren[selectorDivChildrenKeys[i]]);
  562.  
  563. document.body.appendChild(selectorDiv);
  564. },
  565.  
  566. visualDropDown: function(dropDownID, callBack) {
  567. var dropItems = [], dropDownUL = document.createElement('ul');
  568. dropDownUL.id = dropDownID;
  569. dropDownUL.className = 'visualDropDown';
  570. document.body.appendChild(dropDownUL);
  571.  
  572. var selectItem = function() {
  573. dropDownUL.childNodes[0].childNodes[0].childNodes[2].data = this.childNodes[1].data;
  574. dropDownUL.childNodes[0].childNodes[0].childNodes[1].style.backgroundColor = this.childNodes[0].style.backgroundColor;
  575.  
  576. if(callBack)
  577. callBack(this);
  578.  
  579. toggleDropDown(); // hide the dropdown;
  580. };
  581.  
  582. var toggleDropDown = function() {
  583. if(dropDownUL.className.indexOf('expanded')==-1) {
  584. dropDownUL.className = 'visualDropDown expanded';
  585. dropDownUL.childNodes[0].childNodes[0].childNodes[0].src = 'arrowUp.png';
  586. }
  587. else {
  588. dropDownUL.className = 'visualDropDown';
  589. dropDownUL.childNodes[0].childNodes[0].childNodes[0].src = 'arrowDown.png';
  590. }
  591.  
  592. var e = e || window.event;
  593.  
  594. if(e.preventDefault)
  595. e.preventDefault();
  596. else
  597. e.returnValue = false;
  598. };
  599.  
  600. var dropItem = function(itemText, iconColor) {
  601. this.iconColor = iconColor;
  602. this.itemText = itemText;
  603.  
  604. var itemLI = document.createElement('li'), itemLink = document.createElement('a'), iconSpan = document.createElement('span');
  605. itemLink.href = '#';
  606. itemLink.title = itemText;
  607. itemLink.onclick = selectItem;
  608. iconSpan.style.backgroundColor = 'rgb(' + iconColor + ')';
  609.  
  610. itemLink.appendChild(iconSpan);
  611. itemLink.appendChild(document.createTextNode(itemText));
  612. itemLI.appendChild(itemLink);
  613.  
  614. dropDownUL.appendChild(itemLI);
  615.  
  616. if(dropItems.length==0) {
  617. dropDownUL.appendChild(itemLI.cloneNode(true));
  618. var dropDownExpandIcon = document.createElement('img');
  619. dropDownExpandIcon.src = 'arrowDown.png';
  620. dropDownExpandIcon.alt = '[Expand]';
  621. dropDownExpandIcon.title = 'Show Options';
  622. dropDownUL.childNodes[0].childNodes[0].onclick = toggleDropDown;
  623. dropDownUL.childNodes[0].childNodes[0].insertBefore(dropDownExpandIcon, dropDownUL.childNodes[0].childNodes[0].childNodes[0]);
  624. dropDownUL.childNodes[1].childNodes[0].onclick = selectItem;
  625. }
  626. };
  627.  
  628. this.addItem = function(itemText, iconColor) {
  629. var newDropItem = new dropItem(itemText, iconColor);
  630. dropItems.push(newDropItem);
  631. return newDropItem;
  632. };
  633. }
  634. };
  635.  
  636. var pieApp = {};
  637. function initPie() {
  638. pieApp.myPieChart = new pieChart('myPieChart', 100, [['WinXP',500],['Win7',1200],['WinVista',500],['Win8',800],['Win95',900]]);
  639. pieApp.gsGradientSelector = new widgets.gradientSelector();
  640. }
  641. // ]]>
  642. </script>
  643. <style type="text/css">
  644. <!--
  645. img {
  646. border: 0;
  647. }
  648.  
  649. .hidden {
  650. display: none !important;
  651. }
  652.  
  653. div.gradientSelector {
  654. position: absolute;
  655. left: 0px;
  656. top: 0px;
  657. border: 1px solid #d3d3d3;
  658. background: #f5f5f5;
  659. font: 80% Tahoma, Arial, Helvetica, sans-serif;
  660. padding: 0.5em;
  661. }
  662.  
  663. div.gradientSelector label {
  664. width: 5.75em;
  665. display: inline-block;
  666. }
  667.  
  668. span.shadeContainer {
  669. display: inline-block;
  670. margin-right: 0.25em;
  671. text-align: center;
  672. }
  673.  
  674. div.gradientSelector button {
  675. border: 1px solid #a1a1a1;
  676. background: #d3d3d3;
  677. padding: 3px;
  678. margin-top: -2px;
  679. cursor: pointer;
  680. font: bold 80% Arial, Helvetica, sans-serif;
  681. }
  682.  
  683. span.shadeContainer button {
  684. width: 1.25em;
  685. height: 1.75em;
  686. padding: 1px;
  687. font-weight: 100;
  688. }
  689.  
  690. div.gradientSelector button:hover {
  691. border-color: gray;
  692. background: #a1a1a1;
  693. }
  694.  
  695. div.gradientSelector input {
  696. border: 0;
  697. padding: 2px;
  698. }
  699.  
  700. span.shadeContainer label {
  701. display: block;
  702. text-transform: uppercase;
  703. font-weight: bold;
  704. }
  705.  
  706. div.gradientSelector span.shadeContainer input {
  707. padding: 0px;
  708. }
  709.  
  710. div.pickerDiv {
  711. text-align: center;
  712. background: #fcfcfc;
  713. border-top: 1px solid #d3d3d3;
  714. margin: 0.5em -0.5em -0.5em;
  715. padding: 0.5em;
  716. }
  717.  
  718. div.pickerDiv br {
  719. clear: both;
  720. }
  721.  
  722. div.pickerDiv a.collapse {
  723. display: block;
  724. background: #f2f2f2;
  725. border-top: 1px solid #d3d3d3;
  726. padding: 0.25em;
  727. margin: 0.5em -0.5em -0.5em;
  728. }
  729.  
  730. input.colorPreview {
  731. width: 39px;
  732. height: 20px;
  733. border: 0;
  734. padding: 0;
  735. margin: 0;
  736. display: inline-block;
  737. color: #ffffff;
  738. text-align: center;
  739. }
  740.  
  741. div.chart {
  742. position: relative;
  743. border: 1px solid #d3d3d3;
  744. }
  745.  
  746. div.chart span {
  747. display: block;
  748. width: 1px;
  749. height: 1px;
  750. background: #000000;
  751. position: absolute;
  752. }
  753.  
  754. div.chart ul {
  755. list-style: square;
  756. position: absolute;
  757. top: 0px;
  758. }
  759.  
  760. div.chart ul li {
  761. list-style: square;
  762. }
  763.  
  764. ul.visualDropDown {
  765. display: inline-block;
  766. padding: 0;
  767. margin: 0.75em 0em 0em;
  768. }
  769.  
  770. ul.visualDropDown li {
  771. list-style: none;
  772. display: none;
  773. }
  774.  
  775. ul.visualDropDown li:first-child, ul.visualDropDown.expanded li {
  776. display: block;
  777. }
  778.  
  779. ul.visualDropDown li:first-child img {
  780. float: right;
  781. display: block;
  782. margin: -0.25em -0.25em -0.25em 0.5em;
  783. }
  784.  
  785. ul.visualDropDown li span {
  786. margin-right: 0.5em;
  787. width: 1em;
  788. height: 1em;
  789. display: inline-block;
  790. border: 1px solid black;
  791. vertical-align: sub;
  792. }
  793.  
  794. ul.visualDropDown li a {
  795. text-align: left;
  796. display: block;
  797. padding: 0.25em 0.5em;
  798. color: #000000;
  799. text-decoration: none;
  800. font-size: 120%;
  801. width: 7em;
  802. background: #ffffff;
  803. border: 1px solid #d3d3d3;
  804. margin-top: -1px;
  805. z-index: 1;
  806. position: relative;
  807. }
  808.  
  809. ul.visualDropDown li a:hover {
  810. background: #f8f8f8;
  811. border-color: #c3c3c3;
  812. z-index: 2;
  813. }
  814.  
  815. ul.visualDropDown li:first-child a, ul.visualDropDown li:first-child a:hover {
  816. background: #e3e3e3;
  817. }
  818.  
  819. div.gradientDesign {
  820. width: 100%;
  821. height: 2em;
  822. border: 1px solid #d3d3d3;
  823. position: relative;
  824. }
  825.  
  826. div.gradientDesign span { /* vertical bars */
  827. display: block;
  828. position: absolute;
  829. top: 0;
  830. width: 1px;
  831. height: 100%;
  832. background: #000000;
  833. }
  834. -->
  835. </style>
  836. <!--[if lt IE 9]><style type="text/css">
  837. img, span { vertical-align: baseline !important; }
  838. div.pickerDiv a.collapse { margin-bottom: 0em !important; }
  839. div.pickerDiv { padding-bottom: 0 !important; }
  840. span.shadeContainer button { margin-top: 0px !important; }
  841. </style><![endif]-->
  842. </head>
  843. <body onload="initPie();">
  844. <h1><button style="float: right;" onclick="var startColor = document.getElementById('txtStartColor').value.replace(/[^0-9\-\,]/g, '').split(','), endColor = document.getElementById('txtEndColor').value.replace(/[^0-9\-\,]/g, '').split(','); pieApp.myPieChart.fillWithGradient(startColor, endColor);">Render Gradient</button><button style="float: right;" onclick="if(pieApp.gsGradientSelector.isVisible()) pieApp.gsGradientSelector.hide(); else { pieApp.gsGradientSelector.show(); misc.js.positionBelow(this, pieApp.gsGradientSelector.selectorDiv, this.offsetWidth-pieApp.gsGradientSelector.selectorDiv.offsetWidth); }">Set Gradient Colors</button> Pie Chart Generator</h1>
  845. <h2 style="color: red;">To-Do: Make fill algorithm consider pen/brush width<br />To-Do: Make it possible to fill individual sections of a shape, so a fill button can be made<br />To-Do: Pattern fill, and make fills start and finish within each closed shape<br />Make it so you can't draw two pixels in the same place -- doing so should overwrite the existing pixel</h2>
  846. </body>
  847. </html>

Report this snippet  

You need to login to post a comment.