jquery.jgraduate.js 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175
  1. /*
  2. * jGraduate 0.4
  3. *
  4. * jQuery Plugin for a gradient picker
  5. *
  6. * Copyright (c) 2010 Jeff Schiller
  7. * http://blog.codedread.com/
  8. * Copyright (c) 2010 Alexis Deveria
  9. * http://a.deveria.com/
  10. *
  11. * Apache 2 License
  12. jGraduate( options, okCallback, cancelCallback )
  13. where options is an object literal:
  14. {
  15. window: { title: "Pick the start color and opacity for the gradient" },
  16. images: { clientPath: "images/" },
  17. paint: a Paint object,
  18. newstop: String of value "same", "inverse", "black" or "white"
  19. OR object with one or both values {color: #Hex color, opac: number 0-1}
  20. }
  21. - the Paint object is:
  22. Paint {
  23. type: String, // one of "none", "solidColor", "linearGradient", "radialGradient"
  24. alpha: Number representing opacity (0-100),
  25. solidColor: String representing #RRGGBB hex of color,
  26. linearGradient: object of interface SVGLinearGradientElement,
  27. radialGradient: object of interface SVGRadialGradientElement,
  28. }
  29. $.jGraduate.Paint() -> constructs a 'none' color
  30. $.jGraduate.Paint({copy: o}) -> creates a copy of the paint o
  31. $.jGraduate.Paint({hex: "#rrggbb"}) -> creates a solid color paint with hex = "#rrggbb"
  32. $.jGraduate.Paint({linearGradient: o, a: 50}) -> creates a linear gradient paint with opacity=0.5
  33. $.jGraduate.Paint({radialGradient: o, a: 7}) -> creates a radial gradient paint with opacity=0.07
  34. $.jGraduate.Paint({hex: "#rrggbb", linearGradient: o}) -> throws an exception?
  35. - picker accepts the following object as input:
  36. {
  37. okCallback: function to call when Ok is pressed
  38. cancelCallback: function to call when Cancel is pressed
  39. paint: object describing the paint to display initially, if not set, then default to opaque white
  40. }
  41. - okCallback receives a Paint object
  42. *
  43. */
  44. (function() {
  45. var ns = { svg: 'http://www.w3.org/2000/svg', xlink: 'http://www.w3.org/1999/xlink' };
  46. if(!window.console) {
  47. window.console = new function() {
  48. this.log = function(str) {};
  49. this.dir = function(str) {};
  50. };
  51. }
  52. $.jGraduate = {
  53. Paint:
  54. function(opt) {
  55. var options = opt || {};
  56. this.alpha = isNaN(options.alpha) ? 100 : options.alpha;
  57. // copy paint object
  58. if (options.copy) {
  59. this.type = options.copy.type;
  60. this.alpha = options.copy.alpha;
  61. this.solidColor = null;
  62. this.linearGradient = null;
  63. this.radialGradient = null;
  64. switch(this.type) {
  65. case "none":
  66. break;
  67. case "solidColor":
  68. this.solidColor = options.copy.solidColor;
  69. break;
  70. case "linearGradient":
  71. this.linearGradient = options.copy.linearGradient.cloneNode(true);
  72. break;
  73. case "radialGradient":
  74. this.radialGradient = options.copy.radialGradient.cloneNode(true);
  75. break;
  76. }
  77. }
  78. // create linear gradient paint
  79. else if (options.linearGradient) {
  80. this.type = "linearGradient";
  81. this.solidColor = null;
  82. this.radialGradient = null;
  83. this.linearGradient = options.linearGradient.cloneNode(true);
  84. }
  85. // create linear gradient paint
  86. else if (options.radialGradient) {
  87. this.type = "radialGradient";
  88. this.solidColor = null;
  89. this.linearGradient = null;
  90. this.radialGradient = options.radialGradient.cloneNode(true);
  91. }
  92. // create solid color paint
  93. else if (options.solidColor) {
  94. this.type = "solidColor";
  95. this.solidColor = options.solidColor;
  96. }
  97. // create empty paint
  98. else {
  99. this.type = "none";
  100. this.solidColor = null;
  101. this.linearGradient = null;
  102. this.radialGradient = null;
  103. }
  104. }
  105. };
  106. jQuery.fn.jGraduateDefaults = {
  107. paint: new $.jGraduate.Paint(),
  108. window: {
  109. pickerTitle: "Drag markers to pick a paint"
  110. },
  111. images: {
  112. clientPath: "images/"
  113. },
  114. newstop: 'inverse' // same, inverse, black, white
  115. };
  116. var isGecko = navigator.userAgent.indexOf('Gecko/') >= 0;
  117. function setAttrs(elem, attrs) {
  118. if(isGecko) {
  119. for (var aname in attrs) elem.setAttribute(aname, attrs[aname]);
  120. } else {
  121. for (var aname in attrs) {
  122. var val = attrs[aname], prop = elem[aname];
  123. if(prop && prop.constructor === 'SVGLength') {
  124. prop.baseVal.value = val;
  125. } else {
  126. elem.setAttribute(aname, val);
  127. }
  128. }
  129. }
  130. }
  131. function mkElem(name, attrs, newparent) {
  132. var elem = document.createElementNS(ns.svg, name);
  133. setAttrs(elem, attrs);
  134. if(newparent) newparent.appendChild(elem);
  135. return elem;
  136. }
  137. jQuery.fn.jGraduate =
  138. function(options) {
  139. var $arguments = arguments;
  140. return this.each( function() {
  141. var $this = $(this), $settings = $.extend(true, {}, jQuery.fn.jGraduateDefaults, options),
  142. id = $this.attr('id'),
  143. idref = '#'+$this.attr('id')+' ';
  144. if (!idref)
  145. {
  146. alert('Container element must have an id attribute to maintain unique id strings for sub-elements.');
  147. return;
  148. }
  149. var okClicked = function() {
  150. switch ( $this.paint.type ) {
  151. case "radialGradient":
  152. $this.paint.linearGradient = null;
  153. break;
  154. case "linearGradient":
  155. $this.paint.radialGradient = null;
  156. break;
  157. case "solidColor":
  158. $this.paint.radialGradient = $this.paint.linearGradient = null;
  159. break;
  160. }
  161. $.isFunction($this.okCallback) && $this.okCallback($this.paint);
  162. $this.hide();
  163. },
  164. cancelClicked = function() {
  165. $.isFunction($this.cancelCallback) && $this.cancelCallback();
  166. $this.hide();
  167. };
  168. $.extend(true, $this, // public properties, methods, and callbacks
  169. {
  170. // make a copy of the incoming paint
  171. paint: new $.jGraduate.Paint({copy: $settings.paint}),
  172. okCallback: $.isFunction($arguments[1]) && $arguments[1] || null,
  173. cancelCallback: $.isFunction($arguments[2]) && $arguments[2] || null
  174. });
  175. var pos = $this.position(),
  176. color = null;
  177. var $win = $(window);
  178. if ($this.paint.type == "none") {
  179. $this.paint = $.jGraduate.Paint({solidColor: 'ffffff'});
  180. }
  181. $this.addClass('jGraduate_Picker');
  182. $this.html('<ul class="jGraduate_tabs">' +
  183. '<li class="jGraduate_tab_color jGraduate_tab_current" data-type="col">Solid Color</li>' +
  184. '<li class="jGraduate_tab_lingrad" data-type="lg">Linear Gradient</li>' +
  185. '<li class="jGraduate_tab_radgrad" data-type="rg">Radial Gradient</li>' +
  186. '</ul>' +
  187. '<div class="jGraduate_colPick"></div>' +
  188. '<div class="jGraduate_gradPick"></div>' +
  189. '<div class="jGraduate_LightBox"></div>' +
  190. '<div id="' + id + '_jGraduate_stopPicker" class="jGraduate_stopPicker"></div>'
  191. );
  192. var colPicker = $(idref + '> .jGraduate_colPick');
  193. var gradPicker = $(idref + '> .jGraduate_gradPick');
  194. gradPicker.html(
  195. '<div id="' + id + '_jGraduate_Swatch" class="jGraduate_Swatch">' +
  196. '<h2 class="jGraduate_Title">' + $settings.window.pickerTitle + '</h2>' +
  197. '<div id="' + id + '_jGraduate_GradContainer" class="jGraduate_GradContainer"></div>' +
  198. '<div id="' + id + '_jGraduate_StopSlider" class="jGraduate_StopSlider"></div>' +
  199. '</div>' +
  200. '<div class="jGraduate_Form jGraduate_Points jGraduate_lg_field">' +
  201. '<div class="jGraduate_StopSection">' +
  202. '<label class="jGraduate_Form_Heading">Begin Point</label>' +
  203. '<div class="jGraduate_Form_Section">' +
  204. '<label>x:</label>' +
  205. '<input type="text" id="' + id + '_jGraduate_x1" size="3" title="Enter starting x value between 0.0 and 1.0"/>' +
  206. '<label>y:</label>' +
  207. '<input type="text" id="' + id + '_jGraduate_y1" size="3" title="Enter starting y value between 0.0 and 1.0"/>' +
  208. '</div>' +
  209. '</div>' +
  210. '<div class="jGraduate_StopSection">' +
  211. '<label class="jGraduate_Form_Heading">End Point</label>' +
  212. '<div class="jGraduate_Form_Section">' +
  213. '<label>x:</label>' +
  214. '<input type="text" id="' + id + '_jGraduate_x2" size="3" title="Enter ending x value between 0.0 and 1.0"/>' +
  215. '<label>y:</label>' +
  216. '<input type="text" id="' + id + '_jGraduate_y2" size="3" title="Enter ending y value between 0.0 and 1.0"/>' +
  217. '</div>' +
  218. '</div>' +
  219. '</div>' +
  220. '<div class="jGraduate_Form jGraduate_Points jGraduate_rg_field">' +
  221. '<div class="jGraduate_StopSection">' +
  222. '<label class="jGraduate_Form_Heading">Center Point</label>' +
  223. '<div class="jGraduate_Form_Section">' +
  224. '<label>x:</label>' +
  225. '<input type="text" id="' + id + '_jGraduate_cx" size="3" title="Enter x value between 0.0 and 1.0"/>' +
  226. '<label>y:</label>' +
  227. '<input type="text" id="' + id + '_jGraduate_cy" size="3" title="Enter y value between 0.0 and 1.0"/>' +
  228. '</div>' +
  229. '</div>' +
  230. '<div class="jGraduate_StopSection">' +
  231. '<label class="jGraduate_Form_Heading">Focal Point</label>' +
  232. '<div class="jGraduate_Form_Section">' +
  233. '<label>Match center: <input type="checkbox" checked="checked" id="' + id + '_jGraduate_match_ctr"/></label><br/>' +
  234. '<label>x:</label>' +
  235. '<input type="text" id="' + id + '_jGraduate_fx" size="3" title="Enter x value between 0.0 and 1.0"/>' +
  236. '<label>y:</label>' +
  237. '<input type="text" id="' + id + '_jGraduate_fy" size="3" title="Enter y value between 0.0 and 1.0"/>' +
  238. '</div>' +
  239. '</div>' +
  240. '</div>' +
  241. '<div class="jGraduate_StopSection jGraduate_SpreadMethod">' +
  242. '<label class="jGraduate_Form_Heading">Spread method</label>' +
  243. '<div class="jGraduate_Form_Section">' +
  244. '<select class="jGraduate_spreadMethod">' +
  245. '<option value=pad selected>Pad</option>' +
  246. '<option value=reflect>Reflect</option>' +
  247. '<option value=repeat>Repeat</option>' +
  248. '</select>' +
  249. '</div>' +
  250. '</div>' +
  251. '<div class="jGraduate_Form">' +
  252. '<div class="jGraduate_Slider jGraduate_RadiusField jGraduate_rg_field">' +
  253. '<label class="prelabel">Radius:</label>' +
  254. '<div id="' + id + '_jGraduate_Radius" class="jGraduate_SliderBar jGraduate_Radius" title="Click to set radius">' +
  255. '<img id="' + id + '_jGraduate_RadiusArrows" class="jGraduate_RadiusArrows" src="' + $settings.images.clientPath + 'rangearrows2.gif">' +
  256. '</div>' +
  257. '<label><input type="text" id="' + id + '_jGraduate_RadiusInput" size="3" value="100"/>%</label>' +
  258. '</div>' +
  259. '<div class="jGraduate_Slider jGraduate_EllipField jGraduate_rg_field">' +
  260. '<label class="prelabel">Ellip:</label>' +
  261. '<div id="' + id + '_jGraduate_Ellip" class="jGraduate_SliderBar jGraduate_Ellip" title="Click to set Ellip">' +
  262. '<img id="' + id + '_jGraduate_EllipArrows" class="jGraduate_EllipArrows" src="' + $settings.images.clientPath + 'rangearrows2.gif">' +
  263. '</div>' +
  264. '<label><input type="text" id="' + id + '_jGraduate_EllipInput" size="3" value="0"/>%</label>' +
  265. '</div>' +
  266. '<div class="jGraduate_Slider jGraduate_AngleField jGraduate_rg_field">' +
  267. '<label class="prelabel">Angle:</label>' +
  268. '<div id="' + id + '_jGraduate_Angle" class="jGraduate_SliderBar jGraduate_Angle" title="Click to set Angle">' +
  269. '<img id="' + id + '_jGraduate_AngleArrows" class="jGraduate_AngleArrows" src="' + $settings.images.clientPath + 'rangearrows2.gif">' +
  270. '</div>' +
  271. '<label><input type="text" id="' + id + '_jGraduate_AngleInput" size="3" value="0"/>deg</label>' +
  272. '</div>' +
  273. '<div class="jGraduate_Slider jGraduate_OpacField">' +
  274. '<label class="prelabel">Opac:</label>' +
  275. '<div id="' + id + '_jGraduate_Opac" class="jGraduate_SliderBar jGraduate_Opac" title="Click to set Opac">' +
  276. '<img id="' + id + '_jGraduate_OpacArrows" class="jGraduate_OpacArrows" src="' + $settings.images.clientPath + 'rangearrows2.gif">' +
  277. '</div>' +
  278. '<label><input type="text" id="' + id + '_jGraduate_OpacInput" size="3" value="100"/>%</label>' +
  279. '</div>' +
  280. '</div>' +
  281. '<div class="jGraduate_OkCancel">' +
  282. '<input type="button" id="' + id + '_jGraduate_Ok" class="jGraduate_Ok" value="OK"/>' +
  283. '<input type="button" id="' + id + '_jGraduate_Cancel" class="jGraduate_Cancel" value="Cancel"/>' +
  284. '</div>');
  285. // --------------
  286. // Set up all the SVG elements (the gradient, stops and rectangle)
  287. var MAX = 256, MARGINX = 0, MARGINY = 0, STOP_RADIUS = 15/2,
  288. SIZEX = MAX - 2*MARGINX, SIZEY = MAX - 2*MARGINY;
  289. var curType, curGradient, previewRect;
  290. var attr_input = {};
  291. var SLIDERW = 145;
  292. $('.jGraduate_SliderBar').width(SLIDERW);
  293. var container = $('#' + id+'_jGraduate_GradContainer')[0];
  294. var svg = mkElem('svg', {
  295. id: id + '_jgraduate_svg',
  296. width: MAX,
  297. height: MAX,
  298. xmlns: ns.svg
  299. }, container);
  300. // if we are sent a gradient, import it
  301. curType = curType || $this.paint.type;
  302. var grad = curGradient = $this.paint[curType];
  303. var gradalpha = $this.paint.alpha;
  304. var isSolid = curType === 'solidColor';
  305. // Make any missing gradients
  306. switch ( curType ) {
  307. case "solidColor":
  308. // fall through
  309. case "linearGradient":
  310. if(!isSolid) {
  311. curGradient.id = id+'_lg_jgraduate_grad';
  312. grad = curGradient = svg.appendChild(curGradient);//.cloneNode(true));
  313. }
  314. mkElem('radialGradient', {
  315. id: id + '_rg_jgraduate_grad'
  316. }, svg);
  317. if(curType === "linearGradient") break;
  318. case "radialGradient":
  319. if(!isSolid) {
  320. curGradient.id = id+'_rg_jgraduate_grad';
  321. grad = curGradient = svg.appendChild(curGradient);//.cloneNode(true));
  322. }
  323. mkElem('linearGradient', {
  324. id: id + '_lg_jgraduate_grad'
  325. }, svg);
  326. }
  327. if(isSolid) {
  328. grad = curGradient = $('#' + id + '_lg_jgraduate_grad')[0];
  329. var color = $this.paint[curType];
  330. mkStop(0, '#' + color, 1);
  331. var type = typeof $settings.newstop;
  332. if(type === 'string') {
  333. switch ( $settings.newstop ) {
  334. case 'same':
  335. mkStop(1, '#' + color, 1);
  336. break;
  337. case 'inverse':
  338. // Invert current color for second stop
  339. var inverted = '';
  340. for(var i = 0; i < 6; i += 2) {
  341. var ch = color.substr(i, 2);
  342. var inv = (255 - parseInt(color.substr(i, 2), 16)).toString(16);
  343. if(inv.length < 2) inv = 0 + inv;
  344. inverted += inv;
  345. }
  346. mkStop(1, '#' + inverted, 1);
  347. break;
  348. case 'white':
  349. mkStop(1, '#ffffff', 1);
  350. break;
  351. case 'black':
  352. mkStop(1, '#000000', 1);
  353. break;
  354. }
  355. } else if(type === 'object'){
  356. var opac = ('opac' in $settings.newstop) ? $settings.newstop.opac : 1;
  357. mkStop(1, ($settings.newstop.color || '#' + color), opac);
  358. }
  359. }
  360. var x1 = parseFloat(grad.getAttribute('x1')||0.0),
  361. y1 = parseFloat(grad.getAttribute('y1')||0.0),
  362. x2 = parseFloat(grad.getAttribute('x2')||1.0),
  363. y2 = parseFloat(grad.getAttribute('y2')||0.0);
  364. var cx = parseFloat(grad.getAttribute('cx')||0.5),
  365. cy = parseFloat(grad.getAttribute('cy')||0.5),
  366. fx = parseFloat(grad.getAttribute('fx')|| cx),
  367. fy = parseFloat(grad.getAttribute('fy')|| cy);
  368. var previewRect = mkElem('rect', {
  369. id: id + '_jgraduate_rect',
  370. x: MARGINX,
  371. y: MARGINY,
  372. width: SIZEX,
  373. height: SIZEY,
  374. fill: 'url(#'+id+'_jgraduate_grad)',
  375. 'fill-opacity': gradalpha/100
  376. }, svg);
  377. // stop visuals created here
  378. var beginCoord = $('<div/>').attr({
  379. 'class': 'grad_coord jGraduate_lg_field',
  380. title: 'Begin Stop'
  381. }).text(1).css({
  382. top: y1 * MAX,
  383. left: x1 * MAX
  384. }).data('coord', 'start').appendTo(container);
  385. var endCoord = beginCoord.clone().text(2).css({
  386. top: y2 * MAX,
  387. left: x2 * MAX
  388. }).attr('title', 'End stop').data('coord', 'end').appendTo(container);
  389. var centerCoord = $('<div/>').attr({
  390. 'class': 'grad_coord jGraduate_rg_field',
  391. title: 'Center stop'
  392. }).text('C').css({
  393. top: cy * MAX,
  394. left: cx * MAX
  395. }).data('coord', 'center').appendTo(container);
  396. var focusCoord = centerCoord.clone().text('F').css({
  397. top: fy * MAX,
  398. left: fx * MAX,
  399. display: 'none'
  400. }).attr('title', 'Focus point').data('coord', 'focus').appendTo(container);
  401. focusCoord[0].id = id + '_jGraduate_focusCoord';
  402. var coords = $(idref + ' .grad_coord');
  403. // $(container).hover(function() {
  404. // coords.animate({
  405. // opacity: 1
  406. // }, 500);
  407. // }, function() {
  408. // coords.animate({
  409. // opacity: .2
  410. // }, 500);
  411. // });
  412. $.each(['x1', 'y1', 'x2', 'y2', 'cx', 'cy', 'fx', 'fy'], function(i, attr) {
  413. var attrval = curGradient.getAttribute(attr);
  414. var isRadial = isNaN(attr[1]);
  415. if(!attrval) {
  416. // Set defaults
  417. if(isRadial) {
  418. // For radial points
  419. attrval = "0.5";
  420. } else {
  421. // Only x2 is 1
  422. attrval = attr === 'x2' ? "1.0" : "0.0";
  423. }
  424. }
  425. attr_input[attr] = $('#'+id+'_jGraduate_' + attr)
  426. .val(attrval)
  427. .change(function() {
  428. // TODO: Support values < 0 and > 1 (zoomable preview?)
  429. if (isNaN(parseFloat(this.value)) || this.value < 0) {
  430. this.value = 0.0;
  431. } else if(this.value > 1) {
  432. this.value = 1.0;
  433. }
  434. if(!(attr[0] === 'f' && !showFocus)) {
  435. if(isRadial && curType === 'radialGradient' || !isRadial && curType === 'linearGradient') {
  436. curGradient.setAttribute(attr, this.value);
  437. }
  438. }
  439. if(isRadial) {
  440. var $elem = attr[0] === "c" ? centerCoord : focusCoord;
  441. } else {
  442. var $elem = attr[1] === "1" ? beginCoord : endCoord;
  443. }
  444. var cssName = attr.indexOf('x') >= 0 ? 'left' : 'top';
  445. $elem.css(cssName, this.value * MAX);
  446. }).change();
  447. });
  448. function mkStop(n, color, opac, sel, stop_elem) {
  449. var stop = stop_elem || mkElem('stop',{'stop-color':color,'stop-opacity':opac,offset:n}, curGradient);
  450. if(stop_elem) {
  451. color = stop_elem.getAttribute('stop-color');
  452. opac = stop_elem.getAttribute('stop-opacity');
  453. n = stop_elem.getAttribute('offset');
  454. } else {
  455. curGradient.appendChild(stop);
  456. }
  457. if(opac === null) opac = 1;
  458. var picker_d = 'M-6.2,0.9c3.6-4,6.7-4.3,6.7-12.4c-0.2,7.9,3.1,8.8,6.5,12.4c3.5,3.8,2.9,9.6,0,12.3c-3.1,2.8-10.4,2.7-13.2,0C-9.6,9.9-9.4,4.4-6.2,0.9z';
  459. var pathbg = mkElem('path',{
  460. d: picker_d,
  461. fill: 'url(#jGraduate_trans)',
  462. transform: 'translate(' + (10 + n * MAX) + ', 26)'
  463. }, stopGroup);
  464. var path = mkElem('path',{
  465. d: picker_d,
  466. fill: color,
  467. 'fill-opacity': opac,
  468. transform: 'translate(' + (10 + n * MAX) + ', 26)',
  469. stroke: '#000',
  470. 'stroke-width': 1.5
  471. }, stopGroup);
  472. $(path).mousedown(function(e) {
  473. selectStop(this);
  474. drag = cur_stop;
  475. $win.mousemove(dragColor).mouseup(remDrags);
  476. stop_offset = stopMakerDiv.offset();
  477. e.preventDefault();
  478. return false;
  479. }).data('stop', stop).data('bg', pathbg).dblclick(function() {
  480. $('div.jGraduate_LightBox').show();
  481. var colorhandle = this;
  482. var stopOpacity = +stop.getAttribute('stop-opacity') || 1;
  483. var stopColor = stop.getAttribute('stop-color') || 1;
  484. var thisAlpha = (parseFloat(stopOpacity)*255).toString(16);
  485. while (thisAlpha.length < 2) { thisAlpha = "0" + thisAlpha; }
  486. color = stopColor.substr(1) + thisAlpha;
  487. $('#'+id+'_jGraduate_stopPicker').css({'left': 100, 'bottom': 15}).jPicker({
  488. window: { title: "Pick the start color and opacity for the gradient" },
  489. images: { clientPath: $settings.images.clientPath },
  490. color: { active: color, alphaSupport: true }
  491. }, function(color, arg2){
  492. stopColor = color.val('hex') ? ('#'+color.val('hex')) : "none";
  493. stopOpacity = color.val('a') !== null ? color.val('a')/256 : 1;
  494. colorhandle.setAttribute('fill', stopColor);
  495. colorhandle.setAttribute('fill-opacity', stopOpacity);
  496. stop.setAttribute('stop-color', stopColor);
  497. stop.setAttribute('stop-opacity', stopOpacity);
  498. $('div.jGraduate_LightBox').hide();
  499. $('#'+id+'_jGraduate_stopPicker').hide();
  500. }, null, function() {
  501. $('div.jGraduate_LightBox').hide();
  502. $('#'+id+'_jGraduate_stopPicker').hide();
  503. });
  504. });
  505. $(curGradient).find('stop').each(function() {
  506. var cur_s = $(this);
  507. if(+this.getAttribute('offset') > n) {
  508. if(!color) {
  509. var newcolor = this.getAttribute('stop-color');
  510. var newopac = this.getAttribute('stop-opacity');
  511. stop.setAttribute('stop-color', newcolor);
  512. path.setAttribute('fill', newcolor);
  513. stop.setAttribute('stop-opacity', newopac === null ? 1 : newopac);
  514. path.setAttribute('fill-opacity', newopac === null ? 1 : newopac);
  515. }
  516. cur_s.before(stop);
  517. return false;
  518. }
  519. });
  520. if(sel) selectStop(path);
  521. return stop;
  522. }
  523. function remStop() {
  524. delStop.setAttribute('display', 'none');
  525. var path = $(cur_stop);
  526. var stop = path.data('stop');
  527. var bg = path.data('bg');
  528. $([cur_stop, stop, bg]).remove();
  529. }
  530. var stops, stopGroup;
  531. var stopMakerDiv = $('#' + id + '_jGraduate_StopSlider');
  532. var cur_stop, stopGroup, stopMakerSVG, drag;
  533. var delStop = mkElem('path',{
  534. d:'m9.75,-6l-19.5,19.5m0,-19.5l19.5,19.5',
  535. fill:'none',
  536. stroke:'#D00',
  537. 'stroke-width':5,
  538. display:'none'
  539. }, stopMakerSVG);
  540. function selectStop(item) {
  541. if(cur_stop) cur_stop.setAttribute('stroke', '#000');
  542. item.setAttribute('stroke', 'blue');
  543. cur_stop = item;
  544. cur_stop.parentNode.appendChild(cur_stop);
  545. // stops = $('stop');
  546. // opac_select.val(cur_stop.attr('fill-opacity') || 1);
  547. // root.append(delStop);
  548. }
  549. var stop_offset;
  550. function remDrags() {
  551. $win.unbind('mousemove', dragColor);
  552. if(delStop.getAttribute('display') !== 'none') {
  553. remStop();
  554. }
  555. drag = null;
  556. }
  557. var scale_x = 1, scale_y = 1, angle = 0;
  558. var c_x = cx;
  559. var c_y = cy;
  560. function xform() {
  561. var rot = angle?'rotate(' + angle + ',' + c_x + ',' + c_y + ') ':'';
  562. if(scale_x === 1 && scale_y === 1) {
  563. curGradient.removeAttribute('gradientTransform');
  564. // $('#ang').addClass('dis');
  565. } else {
  566. var x = -c_x * (scale_x-1);
  567. var y = -c_y * (scale_y-1);
  568. curGradient.setAttribute('gradientTransform', rot + 'translate(' + x + ',' + y + ') scale(' + scale_x + ',' + scale_y + ')');
  569. // $('#ang').removeClass('dis');
  570. }
  571. }
  572. function dragColor(evt) {
  573. var x = evt.pageX - stop_offset.left;
  574. var y = evt.pageY - stop_offset.top;
  575. x = x < 10 ? 10 : x > MAX + 10 ? MAX + 10: x;
  576. var xf_str = 'translate(' + x + ', 26)';
  577. if(y < -60 || y > 130) {
  578. delStop.setAttribute('display', 'block');
  579. delStop.setAttribute('transform', xf_str);
  580. } else {
  581. delStop.setAttribute('display', 'none');
  582. }
  583. drag.setAttribute('transform', xf_str);
  584. $.data(drag, 'bg').setAttribute('transform', xf_str);
  585. var stop = $.data(drag, 'stop');
  586. var s_x = (x - 10) / MAX;
  587. stop.setAttribute('offset', s_x);
  588. var last = 0;
  589. $(curGradient).find('stop').each(function(i) {
  590. var cur = this.getAttribute('offset');
  591. var t = $(this);
  592. if(cur < last) {
  593. t.prev().before(t);
  594. stops = $(curGradient).find('stop');
  595. }
  596. last = cur;
  597. });
  598. }
  599. stopMakerSVG = mkElem('svg', {
  600. width: '100%',
  601. height: 45
  602. }, stopMakerDiv[0]);
  603. var trans_pattern = mkElem('pattern', {
  604. width: 16,
  605. height: 16,
  606. patternUnits: 'userSpaceOnUse',
  607. id: 'jGraduate_trans'
  608. }, stopMakerSVG);
  609. var trans_img = mkElem('image', {
  610. width: 16,
  611. height: 16
  612. }, trans_pattern);
  613. var bg_image = $settings.images.clientPath + 'map-opacity.png';
  614. trans_img.setAttributeNS(ns.xlink, 'xlink:href', bg_image);
  615. $(stopMakerSVG).click(function(evt) {
  616. stop_offset = stopMakerDiv.offset();
  617. var target = evt.target;
  618. if(target.tagName === 'path') return;
  619. var x = evt.pageX - stop_offset.left - 8;
  620. x = x < 10 ? 10 : x > MAX + 10 ? MAX + 10: x;
  621. mkStop(x / MAX, 0, 0, true);
  622. evt.stopPropagation();
  623. });
  624. $(stopMakerSVG).mouseover(function() {
  625. stopMakerSVG.appendChild(delStop);
  626. });
  627. stopGroup = mkElem('g', {}, stopMakerSVG);
  628. mkElem('line', {
  629. x1: 10,
  630. y1: 15,
  631. x2: MAX + 10,
  632. y2: 15,
  633. 'stroke-width': 2,
  634. stroke: '#000'
  635. }, stopMakerSVG);
  636. var spreadMethodOpt = gradPicker.find('.jGraduate_spreadMethod').change(function() {
  637. curGradient.setAttribute('spreadMethod', $(this).val());
  638. });
  639. // handle dragging the stop around the swatch
  640. var draggingCoord = null;
  641. var onCoordDrag = function(evt) {
  642. var x = evt.pageX - offset.left;
  643. var y = evt.pageY - offset.top;
  644. // clamp stop to the swatch
  645. x = x < 0 ? 0 : x > MAX ? MAX : x;
  646. y = y < 0 ? 0 : y > MAX ? MAX : y;
  647. draggingCoord.css('left', x).css('top', y);
  648. // calculate stop offset
  649. var fracx = x / SIZEX;
  650. var fracy = y / SIZEY;
  651. var type = draggingCoord.data('coord');
  652. var grad = curGradient;
  653. switch ( type ) {
  654. case 'start':
  655. attr_input.x1.val(fracx);
  656. attr_input.y1.val(fracy);
  657. grad.setAttribute('x1', fracx);
  658. grad.setAttribute('y1', fracy);
  659. break;
  660. case 'end':
  661. attr_input.x2.val(fracx);
  662. attr_input.y2.val(fracy);
  663. grad.setAttribute('x2', fracx);
  664. grad.setAttribute('y2', fracy);
  665. break;
  666. case 'center':
  667. attr_input.cx.val(fracx);
  668. attr_input.cy.val(fracy);
  669. grad.setAttribute('cx', fracx);
  670. grad.setAttribute('cy', fracy);
  671. c_x = fracx;
  672. c_y = fracy;
  673. xform();
  674. break;
  675. case 'focus':
  676. attr_input.fx.val(fracx);
  677. attr_input.fy.val(fracy);
  678. grad.setAttribute('fx', fracx);
  679. grad.setAttribute('fy', fracy);
  680. xform();
  681. }
  682. evt.preventDefault();
  683. }
  684. var onCoordUp = function() {
  685. draggingCoord = null;
  686. $win.unbind('mousemove', onCoordDrag).unbind('mouseup', onCoordUp);
  687. }
  688. // Linear gradient
  689. // (function() {
  690. stops = curGradient.getElementsByTagNameNS(ns.svg, 'stop');
  691. // if there are not at least two stops, then
  692. if (numstops < 2) {
  693. while (numstops < 2) {
  694. curGradient.appendChild( document.createElementNS(ns.svg, 'stop') );
  695. ++numstops;
  696. }
  697. stops = curGradient.getElementsByTagNameNS(ns.svg, 'stop');
  698. }
  699. var numstops = stops.length;
  700. for(var i = 0; i < numstops; i++) {
  701. mkStop(0, 0, 0, 0, stops[i]);
  702. }
  703. spreadMethodOpt.val(curGradient.getAttribute('spreadMethod') || 'pad');
  704. var offset;
  705. // No match, so show focus point
  706. var showFocus = false;
  707. previewRect.setAttribute('fill-opacity', gradalpha/100);
  708. $('#' + id + ' div.grad_coord').mousedown(function(evt) {
  709. evt.preventDefault();
  710. draggingCoord = $(this);
  711. var s_pos = draggingCoord.offset();
  712. offset = draggingCoord.parent().offset();
  713. $win.mousemove(onCoordDrag).mouseup(onCoordUp);
  714. });
  715. // bind GUI elements
  716. $('#'+id+'_jGraduate_Ok').bind('click', function() {
  717. $this.paint.type = curType;
  718. $this.paint[curType] = curGradient.cloneNode(true);;
  719. $this.paint.solidColor = null;
  720. okClicked();
  721. });
  722. $('#'+id+'_jGraduate_Cancel').bind('click', function(paint) {
  723. cancelClicked();
  724. });
  725. if(curType === 'radialGradient') {
  726. if(showFocus) {
  727. focusCoord.show();
  728. } else {
  729. focusCoord.hide();
  730. attr_input.fx.val("");
  731. attr_input.fy.val("");
  732. }
  733. }
  734. $("#" + id + "_jGraduate_match_ctr")[0].checked = !showFocus;
  735. var lastfx, lastfy;
  736. $("#" + id + "_jGraduate_match_ctr").change(function() {
  737. showFocus = !this.checked;
  738. focusCoord.toggle(showFocus);
  739. attr_input.fx.val('');
  740. attr_input.fy.val('');
  741. var grad = curGradient;
  742. if(!showFocus) {
  743. lastfx = grad.getAttribute('fx');
  744. lastfy = grad.getAttribute('fy');
  745. grad.removeAttribute('fx');
  746. grad.removeAttribute('fy');
  747. } else {
  748. var fx = lastfx || .5;
  749. var fy = lastfy || .5;
  750. grad.setAttribute('fx', fx);
  751. grad.setAttribute('fy', fy);
  752. attr_input.fx.val(fx);
  753. attr_input.fy.val(fy);
  754. }
  755. });
  756. var stops = curGradient.getElementsByTagNameNS(ns.svg, 'stop');
  757. var numstops = stops.length;
  758. // if there are not at least two stops, then
  759. if (numstops < 2) {
  760. while (numstops < 2) {
  761. curGradient.appendChild( document.createElementNS(ns.svg, 'stop') );
  762. ++numstops;
  763. }
  764. stops = curGradient.getElementsByTagNameNS(ns.svg, 'stop');
  765. }
  766. var slider;
  767. var setSlider = function(e) {
  768. var offset = slider.offset;
  769. var div = slider.parent;
  770. var x = (e.pageX - offset.left - parseInt(div.css('border-left-width')));
  771. if (x > SLIDERW) x = SLIDERW;
  772. if (x <= 0) x = 0;
  773. var posx = x - 5;
  774. x /= SLIDERW;
  775. switch ( slider.type ) {
  776. case 'radius':
  777. x = Math.pow(x * 2, 2.5);
  778. if(x > .98 && x < 1.02) x = 1;
  779. if (x <= .01) x = .01;
  780. curGradient.setAttribute('r', x);
  781. break;
  782. case 'opacity':
  783. $this.paint.alpha = parseInt(x*100);
  784. previewRect.setAttribute('fill-opacity', x);
  785. break;
  786. case 'ellip':
  787. scale_x = 1, scale_y = 1;
  788. if(x < .5) {
  789. x /= .5; // 0.001
  790. scale_x = x <= 0 ? .01 : x;
  791. } else if(x > .5) {
  792. x /= .5; // 2
  793. x = 2 - x;
  794. scale_y = x <= 0 ? .01 : x;
  795. }
  796. xform();
  797. x -= 1;
  798. if(scale_y === x + 1) {
  799. x = Math.abs(x);
  800. }
  801. break;
  802. case 'angle':
  803. x = x - .5;
  804. angle = x *= 180;
  805. xform();
  806. x /= 100;
  807. break;
  808. }
  809. slider.elem.css({'margin-left':posx});
  810. x = Math.round(x*100);
  811. slider.input.val(x);
  812. };
  813. var ellip_val = 0, angle_val = 0;
  814. if(curType === 'radialGradient') {
  815. var tlist = curGradient.gradientTransform.baseVal;
  816. if(tlist.numberOfItems === 2) {
  817. var t = tlist.getItem(0);
  818. var s = tlist.getItem(1);
  819. if(t.type === 2 && s.type === 3) {
  820. var m = s.matrix;
  821. if(m.a !== 1) {
  822. ellip_val = Math.round(-(1 - m.a) * 100);
  823. } else if(m.d !== 1) {
  824. ellip_val = Math.round((1 - m.d) * 100);
  825. }
  826. }
  827. } else if(tlist.numberOfItems === 3) {
  828. // Assume [R][T][S]
  829. var r = tlist.getItem(0);
  830. var t = tlist.getItem(1);
  831. var s = tlist.getItem(2);
  832. if(r.type === 4
  833. && t.type === 2
  834. && s.type === 3) {
  835. angle_val = Math.round(r.angle);
  836. var m = s.matrix;
  837. if(m.a !== 1) {
  838. ellip_val = Math.round(-(1 - m.a) * 100);
  839. } else if(m.d !== 1) {
  840. ellip_val = Math.round((1 - m.d) * 100);
  841. }
  842. }
  843. }
  844. }
  845. var sliders = {
  846. radius: {
  847. handle: '#' + id + '_jGraduate_RadiusArrows',
  848. input: '#' + id + '_jGraduate_RadiusInput',
  849. val: (curGradient.getAttribute('r') || .5) * 100
  850. },
  851. opacity: {
  852. handle: '#' + id + '_jGraduate_OpacArrows',
  853. input: '#' + id + '_jGraduate_OpacInput',
  854. val: $this.paint.alpha || 100
  855. },
  856. ellip: {
  857. handle: '#' + id + '_jGraduate_EllipArrows',
  858. input: '#' + id + '_jGraduate_EllipInput',
  859. val: ellip_val
  860. },
  861. angle: {
  862. handle: '#' + id + '_jGraduate_AngleArrows',
  863. input: '#' + id + '_jGraduate_AngleInput',
  864. val: angle_val
  865. }
  866. }
  867. $.each(sliders, function(type, data) {
  868. var handle = $(data.handle);
  869. handle.mousedown(function(evt) {
  870. var parent = handle.parent();
  871. slider = {
  872. type: type,
  873. elem: handle,
  874. input: $(data.input),
  875. parent: parent,
  876. offset: parent.offset()
  877. };
  878. $win.mousemove(dragSlider).mouseup(stopSlider);
  879. evt.preventDefault();
  880. });
  881. $(data.input).val(data.val).change(function() {
  882. var val = +this.value;
  883. var xpos = 0;
  884. var isRad = curType === 'radialGradient';
  885. switch ( type ) {
  886. case 'radius':
  887. if(isRad) curGradient.setAttribute('r', val / 100);
  888. xpos = (Math.pow(val / 100, 1 / 2.5) / 2) * SLIDERW;
  889. break;
  890. case 'opacity':
  891. $this.paint.alpha = val;
  892. previewRect.setAttribute('fill-opacity', val / 100);
  893. xpos = val * (SLIDERW / 100);
  894. break;
  895. case 'ellip':
  896. scale_x = scale_y = 1;
  897. if(val === 0) {
  898. xpos = SLIDERW * .5;
  899. break;
  900. }
  901. if(val > 99.5) val = 99.5;
  902. if(val > 0) {
  903. scale_y = 1 - (val / 100);
  904. } else {
  905. scale_x = - (val / 100) - 1;
  906. }
  907. xpos = SLIDERW * ((val + 100) / 2) / 100;
  908. if(isRad) xform();
  909. break;
  910. case 'angle':
  911. angle = val;
  912. xpos = angle / 180;
  913. xpos += .5;
  914. xpos *= SLIDERW;
  915. if(isRad) xform();
  916. }
  917. if(xpos > SLIDERW) {
  918. xpos = SLIDERW;
  919. } else if(xpos < 0) {
  920. xpos = 0;
  921. }
  922. handle.css({'margin-left': xpos - 5});
  923. }).change();
  924. });
  925. var dragSlider = function(evt) {
  926. setSlider(evt);
  927. evt.preventDefault();
  928. };
  929. var stopSlider = function(evt) {
  930. $win.unbind('mousemove', dragSlider).unbind('mouseup', stopSlider);
  931. slider = null;
  932. };
  933. // --------------
  934. var thisAlpha = ($this.paint.alpha*255/100).toString(16);
  935. while (thisAlpha.length < 2) { thisAlpha = "0" + thisAlpha; }
  936. thisAlpha = thisAlpha.split(".")[0];
  937. color = $this.paint.solidColor == "none" ? "" : $this.paint.solidColor + thisAlpha;
  938. if(!isSolid) {
  939. color = stops[0].getAttribute('stop-color');
  940. }
  941. // This should be done somewhere else, probably
  942. $.extend($.fn.jPicker.defaults.window, {
  943. alphaSupport: true, effects: {type: 'show',speed: 0}
  944. });
  945. colPicker.jPicker(
  946. {
  947. window: { title: $settings.window.pickerTitle },
  948. images: { clientPath: $settings.images.clientPath },
  949. color: { active: color, alphaSupport: true }
  950. },
  951. function(color) {
  952. $this.paint.type = "solidColor";
  953. $this.paint.alpha = color.val('ahex') ? Math.round((color.val('a') / 255) * 100) : 100;
  954. $this.paint.solidColor = color.val('hex') ? color.val('hex') : "none";
  955. $this.paint.radialGradient = null;
  956. okClicked();
  957. },
  958. null,
  959. function(){ cancelClicked(); }
  960. );
  961. var tabs = $(idref + ' .jGraduate_tabs li');
  962. tabs.click(function() {
  963. tabs.removeClass('jGraduate_tab_current');
  964. $(this).addClass('jGraduate_tab_current');
  965. $(idref + " > div").hide();
  966. var type = $(this).attr('data-type');
  967. var container = $(idref + ' .jGraduate_gradPick').show();
  968. if(type === 'rg' || type === 'lg') {
  969. // Show/hide appropriate fields
  970. $('.jGraduate_' + type + '_field').show();
  971. $('.jGraduate_' + (type === 'lg' ? 'rg' : 'lg') + '_field').hide();
  972. $('#' + id + '_jgraduate_rect')[0].setAttribute('fill', 'url(#' + id + '_' + type + '_jgraduate_grad)');
  973. // Copy stops
  974. curType = type === 'lg' ? 'linearGradient' : 'radialGradient';
  975. $('#' + id + '_jGraduate_OpacInput').val($this.paint.alpha).change();
  976. var newGrad = $('#' + id + '_' + type + '_jgraduate_grad')[0];
  977. if(curGradient !== newGrad) {
  978. var cur_stops = $(curGradient).find('stop');
  979. $(newGrad).empty().append(cur_stops);
  980. curGradient = newGrad;
  981. var sm = spreadMethodOpt.val();
  982. curGradient.setAttribute('spreadMethod', sm);
  983. }
  984. showFocus = type === 'rg' && curGradient.getAttribute('fx') != null && !(cx == fx && cy == fy);
  985. $('#' + id + '_jGraduate_focusCoord').toggle(showFocus);
  986. if(showFocus) {
  987. $('#' + id + '_jGraduate_match_ctr')[0].checked = false;
  988. }
  989. } else {
  990. $(idref + ' .jGraduate_gradPick').hide();
  991. $(idref + ' .jGraduate_colPick').show();
  992. }
  993. });
  994. $(idref + " > div").hide();
  995. tabs.removeClass('jGraduate_tab_current');
  996. var tab;
  997. switch ( $this.paint.type ) {
  998. case 'linearGradient':
  999. tab = $(idref + ' .jGraduate_tab_lingrad');
  1000. break;
  1001. case 'radialGradient':
  1002. tab = $(idref + ' .jGraduate_tab_radgrad');
  1003. break;
  1004. default:
  1005. tab = $(idref + ' .jGraduate_tab_color');
  1006. break;
  1007. }
  1008. $this.show();
  1009. // jPicker will try to show after a 0ms timeout, so need to fire this after that
  1010. setTimeout(function() {
  1011. tab.addClass('jGraduate_tab_current').click();
  1012. }, 10);
  1013. });
  1014. };
  1015. })();