Add unobtrusive javascript support for charts

@return  void
325848
public static function chart($type='core')
	{
		if (isset(self::$loaded[__METHOD__][$type]))
		{
			return;
		}

		if ($type != 'core')
		{
			self::chart();
		}

		if ($type == 'core')
		{
			Asset::script('assets/flot/jquery.flot.min.js', true, true);
			Asset::script('assets/flot/jquery.flot.canvas.min.js', true, true);
			Asset::script('assets/flot/jquery.flot.time.min.js', true, true);
			Asset::script('assets/flot/jquery.flot.tooltip.min.js', true, true);
		}
		else
		{
			Asset::script('assets/flot/jquery.flot.' . $type . '.min.js', true, true);
		}

		self::$loaded[__METHOD__][$type] = true;

		return;
	}
118889
public function run() {
        $configs = Json::encode($this->configs);

        
        $this->getView()->registerJs('
            var configChart = $.parseJSON(\'' . $configs . '\');
                console.log(configChart);
            $(function () {
                // Set up the chart
                var chart = new Highcharts.Chart(configChart);
                    
                // Activate the sliders
                $("#R0").on("change", function(){
                    chart.options.chart.options3d.alpha = this.value;
                    showValues();
                    chart.redraw(false);
                });
                $("#R1").on("change", function(){
                    chart.options.chart.options3d.beta = this.value;
                    showValues();
                    chart.redraw(false);
                });

                function showValues() {
                    $("#R0-value").html(chart.options.chart.options3d.alpha);
                    $("#R1-value").html(chart.options.chart.options3d.beta);
                }
                showValues();
            });
        ');
        echo '
            <div id="container"></div><div id="sliders">
	<table>
		<tr><td>Alpha Angle</td><td><input id="R0" type="range" min="0" max="45" value="15"/> <span id="R0-value" class="value"></span></td></tr>
	    <tr><td>Beta Angle</td><td><input id="R1" type="range" min="0" max="45" value="15"/> <span id="R1-value" class="value"></span></td></tr>
	</table>
        </div>';
    }
441998
public function init(){

		if ($this->shouldEnableExtendedSummary())
			$this->prepareDisplayingExtendedSummary();

		if ($this->shouldEnableChart() && $this->hasData())
			$this->enableChart();

		if ($this->shouldEnableBulkActions())
			$this->enableBulkActions();

		$this->fillSelectionChangedProperty();

		parent::init();
	}
226791
function () {
		var chart = this,
			axes = chart.axes,
			renderer = chart.renderer,
			options = chart.options;

		var labels = options.labels,
			credits = options.credits,
			creditsHref;

		// Title
		chart.setTitle();


		// Legend
		chart.legend = new Legend(chart, options.legend);

		chart.getStacks(); // render stacks

		// Get margins by pre-rendering axes
		// set axes scales
		each(axes, function (axis) {
			axis.setScale();
		});

		chart.getMargins();

		chart.maxTicks = null; // reset for second pass
		each(axes, function (axis) {
			axis.setTickPositions(true); // update to reflect the new margins
			axis.setMaxTicks();
		});
		chart.adjustTickAmounts();
		chart.getMargins(); // second pass to check for new labels


		// Draw the borders and backgrounds
		chart.drawChartBox();		


		// Axes
		if (chart.hasCartesianSeries) {
			each(axes, function (axis) {
				axis.render();
			});
		}

		// The series
		if (!chart.seriesGroup) {
			chart.seriesGroup = renderer.g('series-group')
				.attr({ zIndex: 3 })
				.add();
		}
		each(chart.series, function (serie) {
			serie.translate();
			serie.setTooltipPoints();
			serie.render();
		});

		// Labels
		if (labels.items) {
			each(labels.items, function (label) {
				var style = extend(labels.style, label.style),
					x = pInt(style.left) + chart.plotLeft,
					y = pInt(style.top) + chart.plotTop + 12;

				// delete to prevent rewriting in IE
				delete style.left;
				delete style.top;

				renderer.text(
					label.html,
					x,
					y
				)
				.attr({ zIndex: 2 })
				.css(style)
				.add();

			});
		}

		// Credits
		if (credits.enabled && !chart.credits) {
			creditsHref = credits.href;
			chart.credits = renderer.text(
				credits.text,
				0,
				0
			)
			.on('click', function () {
				if (creditsHref) {
					location.href = creditsHref;
				}
			})
			.attr({
				align: credits.position.align,
				zIndex: 8
			})
			.css(credits.style)
			.add()
			.align(credits.position);
		}

		// Set flag
		chart.hasRendered = true;

	}
978243
public function addDefaultIncludes()
    {
        $this->addInclude('start-atk4');

        /* $config['js']['jqueryui']='https://code.jquery.com/ui/1.11.4/jquery-ui.min.js'; // to use CDN */
        if ($v = $this->app->getConfig('js/versions/jqueryui', null)) {
            $v = 'jquery-ui-'.$v;
        } else {
            $v = $this->app->getConfig('js/jqueryui', 'jquery-ui-1.11.4.min');  // bundled jQueryUI version
        }

        $this->addInclude($v);

        $this->addInclude('ui.atk4_loader');
        $this->addInclude('ui.atk4_notify');
        $this->addInclude('atk4_univ_basic');
        $this->addInclude('atk4_univ_jui');
    }
846358
def OnInsertChartDialog(self, event):
        """"""

        key = self.grid.actions.cursor

        cell_code = self.grid.code_array(key)

        if cell_code is None:
            cell_code = u""

        chart_dialog = ChartDialog(self.grid.main_window, key, cell_code)

        if chart_dialog.ShowModal() == wx.ID_OK:
            code = chart_dialog.get_code()
            key = self.grid.actions.cursor
            self.grid.actions.set_code(key, code)
137529
public function onBeforeInit()
    {
        $canEdit        = FrontendEditing::ShowAdmin();
        $editingEnabled = FrontendEditing::editingEnabled();
        $minExt         = (Director::isDev()) ? "" : ".min";

        if ($canEdit) {
            // Enable front-end fly-out menu
            // 
            //Flexslider imports easing, which breaks?
            Requirements::block('flexslider/javascript/jquery.easing.1.3.js');

            Requirements::javascript(FRAMEWORK_DIR.'/thirdparty/jquery/jquery.js');
            Requirements::javascript(FRAMEWORK_DIR.'/thirdparty/jquery-ui/jquery-ui.js');
            Requirements::javascript(FRAMEWORK_ADMIN_DIR.'/javascript/ssui.core.js');
            Requirements::javascript(THIRDPARTY_DIR.'/jquery-entwine/dist/jquery.entwine-dist.js');
            Requirements::javascriptTemplate(FRONTEND_ADMIN_DIR.'/javascript/dist/FrontEndAdminTemplate'.$minExt.'.js', $this->getConfig($this->owner->data()));
            Requirements::css(FRAMEWORK_DIR.'/thirdparty/jquery-ui-themes/smoothness/jquery-ui.css');
            Requirements::javascript(FRONTEND_ADMIN_DIR.'/javascript/dist/FrontEndAdmin'.$minExt.'.js');
            Requirements::css(FRONTEND_ADMIN_DIR.'/css/frontend-admin'.$minExt.'.css');

            $this->owner->getResponse()->addHeader("X-DynamicCache-OptOut", true);
        }
        if ($canEdit && $editingEnabled) {
            // Disable mode pagespeed while editing
            $this->owner->getResponse()->addHeader("PageSpeed", "off");
            // Disable HTTP cache while editing
            HTTP::set_cache_age(0);
            // Enable TinyMCE when editing has been enabled
            Requirements::javascript(FRONTEND_ADMIN_DIR.'/bower_components/tinymce/jquery.tinymce.min.js');
            Requirements::javascript(FRONTEND_ADMIN_DIR.'/javascript/dist/FrontEndEditor'.$minExt.'.js');
            Requirements::css(FRONTEND_ADMIN_DIR.'/css/frontend-editor'.$minExt.'.css');
        }
    }
518251
protected function attachScripts()
    {
        $scripts   = $this->container->make('config')->get('antares/html::form.scripts.client-side');
        $container = $this->container->make('antares.asset')->container($scripts['position']);
        foreach ($scripts['resources'] as $name => $path) {
            $container->add($name, $path);
        }
        return;
    }
522087
protected function minifyJs()
    {
        $minifier = new Minify\JS();

        // Components
        $this->addJsToMinifier($minifier, 'dropdowns', 'dropdown');

        // Components w/ JavaScript
        $this->addJsToMinifier($minifier, 'modals', 'modal');
        $this->addJsToMinifier($minifier, 'tooltip');
        $this->addJsToMinifier($minifier, 'popovers', 'popover');
        $this->addJsToMinifier($minifier, 'carousel');

        // Pure JavaScript components
        $this->addJsToMinifier($minifier, 'affix');
        $this->addJsToMinifier($minifier, 'alert');
        $this->addJsToMinifier($minifier, 'button');
        $this->addJsToMinifier($minifier, 'collapse');
        $this->addJsToMinifier($minifier, 'scrollspy');
        $this->addJsToMinifier($minifier, 'tab');
        $this->addJsToMinifier($minifier, 'transition');

        return $minifier->minify();
    }
284040
protected function markdownEditorJs()
	{

		if (isset($this->htmlOptions['width']))
		{
			$width = $this->htmlOptions['width'];
			unset($this->htmlOptions['width']);
		}
		if (isset($this->htmlOptions['height']))
		{
			$height = $this->htmlOptions['height'];
			unset($this->htmlOptions['height']);
		}
		echo $this->getLabel();
		echo '<div class="controls">';
		echo '<div class="wmd-panel">';
		echo '<div id="wmd-button-bar" class="btn-toolbar"></div>';
		$this->widget('bootstrap.widgets.CiiMarkdownEditorJs', array(
			'model' => $this->model,
			'attribute' => $this->attribute,
			'width' => isset($width) ? $width : '100%',
			'height' => isset($height) ? $height : '400px',
			'htmlOptions' => $this->htmlOptions
		));
		echo $this->getError() . $this->getHint();
		echo '<div id="wmd-preview" class="wmd-panel wmd-preview" style="width:' . (isset($width) ? $width : '100%') . '"></div>';
		echo '</div>'; // wmd-panel
		echo '</div>'; // controls
	}
558598
public function allData()
    {
        call_user_func($this->callback, new ChartWidget($this->name, $this->label, $this->authSystem, $this->requiredPermissions, $this->chart));
    }
153204
public static function addToHTML()
    {
        if (!self::isViewingHTMLPage()) {
            return;
        }

        // js
        $paths = self::getAssetFilePaths('js');
        echo sprintf(
            '<script>%s</script>',
            self::getCombinedContents($paths)
        );

        // css
        $paths = self::getAssetFilePaths('css');
        echo sprintf(
            '<style>%s</style>',
            self::getCombinedContents($paths)
        );
    }
1029365
protected function onRender()
    {

        $columns = $this->getColumnSettings();

        //Update options
        $options = $this->options;
        if ($this->title) {
            $options["title"] = $this->title;
        }
        if ($this->colorScheme) {
            $options["colors"] = $this->colorScheme;
        }

        $this->template(
            'Timeline',
            array(
                "options" => $options,
                "columns" => $columns,
                "loader"=>array(
                    "package"=>$this->package,
                    "stability"=>$this->stability,
                    "mapsApiKey"=>$this->mapsApiKey
                )
            )
        );
    }
175832
protected function redactorJs()
	{
		if (isset($this->htmlOptions['options']))
		{
			$options = $this->htmlOptions['options'];
			unset($this->htmlOptions['options']);
		}
		if (isset($this->htmlOptions['width']))
		{
			$width = $this->htmlOptions['width'];
			unset($this->htmlOptions['width']);
		}
		if (isset($this->htmlOptions['height']))
		{
			$height = $this->htmlOptions['height'];
			unset($this->htmlOptions['height']);
		}
		echo $this->getLabel();
		$this->widget('bootstrap.widgets.CiiRedactorJs', array(
			'model' => $this->model,
			'attribute' => $this->attribute,
			'editorOptions' => isset($options) ? $options : array(),
			'width' => isset($width) ? $width : '100%',
			'height' => isset($height) ? $height : '400px',
			'htmlOptions' => $this->htmlOptions
		));
		echo $this->getError() . $this->getHint();
	}
936555
function () {
		var chart = this;

		// reset stacks for each yAxis
		each(chart.yAxis, function (axis) {
			if (axis.stacks && axis.hasVisibleSeries) {
				axis.oldStacks = axis.stacks;
			}
		});

		each(chart.series, function (series) {
			if (series.options.stacking && (series.visible === true || chart.options.chart.ignoreHiddenSeries === false)) {
				series.stackKey = series.type + pick(series.options.stack, '');
			}
		});
	}
960356
function () {

            var chart = this.chart,
              maxTicks = chart.maxTicks || {},
              tickPositions = this.tickPositions,
              key = this._maxTicksKey = [this.coll, this.pos, this.len].join('-');

            if (!this.isLinked && !this.isDatetimeAxis && tickPositions && tickPositions.length > (maxTicks[key] || 0) && this.options.alignTicks !== false) {
                maxTicks[key] = tickPositions.length;
            }
            chart.maxTicks = maxTicks;
        }
695125
function () {

		var options = chart.options.legend;

		if (!options.enabled) {
			return;
		}

		var horizontal = options.layout === 'horizontal',
			symbolWidth = options.symbolWidth,
			symbolPadding = options.symbolPadding,
			allItems,
			style = options.style,
			itemStyle = options.itemStyle,
			itemHoverStyle = options.itemHoverStyle,
			itemHiddenStyle = options.itemHiddenStyle,
			padding = pInt(style.padding),
			y = 18,
			initialItemX = 4 + padding + symbolWidth + symbolPadding,
			itemX,
			itemY,
			lastItemY,
			itemHeight = 0,
			box,
			legendBorderWidth = options.borderWidth,
			legendBackgroundColor = options.backgroundColor,
			legendGroup,
			offsetWidth,
			widthOption = options.width,
			series = chart.series,
			reversedLegend = options.reversed;

		// PATCH by Simon Fishel
        //
        // read in hooks from the options object
        //
        // + var hooks = options.hooks || {};
        
        var hooks = options.hooks || {};

		/**
		 * Set the colors for the legend item
		 * @param {Object} item A Series or Point instance
		 * @param {Object} visible Dimmed or colored
		 */
		function colorizeItem(item, visible) {
			var legendItem = item.legendItem,
				legendLine = item.legendLine,
				legendSymbol = item.legendSymbol,
				hiddenColor = itemHiddenStyle.color,
				textColor = visible ? options.itemStyle.color : hiddenColor,
				lineColor = visible ? item.color : hiddenColor,
				symbolAttr = visible ? item.pointAttr[NORMAL_STATE] : {
					stroke: hiddenColor,
					fill: hiddenColor
				};

			if (legendItem) {
				legendItem.css({ fill: textColor });
			}
			if (legendLine) {
				legendLine.attr({ stroke: lineColor });
			}
			if (legendSymbol) {
				legendSymbol.attr(symbolAttr);
			}

		}

		/**
		 * Position the legend item
		 * @param {Object} item A Series or Point instance
		 * @param {Object} visible Dimmed or colored
		 */
		function positionItem(item, itemX, itemY) {
			var legendItem = item.legendItem,
				legendLine = item.legendLine,
				legendSymbol = item.legendSymbol,
				checkbox = item.checkbox;
			if (legendItem) {
				legendItem.attr({
					x: itemX,
					y: itemY
				});
			}
			if (legendLine) {
				legendLine.translate(itemX, itemY - 4);
			}
			if (legendSymbol) {
				legendSymbol.attr({
					x: itemX + legendSymbol.xOff,
					y: itemY + legendSymbol.yOff
				});
			}
			if (checkbox) {
				checkbox.x = itemX;
				checkbox.y = itemY;
			}
		}

		/**
		 * Destroy a single legend item
		 * @param {Object} item The series or point
		 */
		function destroyItem(item) {
			var checkbox = item.checkbox;

			// pull out from the array
			//erase(allItems, item);

			// destroy SVG elements
			each(['legendItem', 'legendLine', 'legendSymbol'], function (key) {
				if (item[key]) {
					item[key].destroy();
				}
			});

			if (checkbox) {
				discardElement(item.checkbox);
			}


		}

		/**
		 * Destroys the legend.
		 */
		function destroy() {
			if (box) {
				box = box.destroy();
			}

			if (legendGroup) {
				legendGroup = legendGroup.destroy();
			}
		}

		/**
		 * Position the checkboxes after the width is determined
		 */
		function positionCheckboxes() {
			each(allItems, function (item) {
				var checkbox = item.checkbox,
					alignAttr = legendGroup.alignAttr;
				if (checkbox) {
					css(checkbox, {
						left: (alignAttr.translateX + item.legendItemWidth + checkbox.x - 40) + PX,
						top: (alignAttr.translateY + checkbox.y - 11) + PX
					});
				}
			});
		}

		/**
		 * Render a single specific legend item
		 * @param {Object} item A series or point
		 */
		function renderItem(item) {
			var bBox,
				itemWidth,
				legendSymbol,
				symbolX,
				symbolY,
				simpleSymbol,
				li = item.legendItem,
				series = item.series || item,
				itemOptions = series.options,
				strokeWidth = (itemOptions && itemOptions.borderWidth) || 0;

			if (!li) { // generate it once, later move it

				// let these series types use a simple symbol
				simpleSymbol = /^(bar|pie|area|column)$/.test(series.type);

				// generate the list item text
				item.legendItem = li = renderer.text(
						options.labelFormatter.call(item),
						0,
						0
					)
					.css(item.visible ? itemStyle : itemHiddenStyle)
					.on('mouseover', function () {
						item.setState(HOVER_STATE);
						li.css(itemHoverStyle);
					})
					.on('mouseout', function () {
						li.css(item.visible ? itemStyle : itemHiddenStyle);
						item.setState();
					})
					
					// PATCH by Simon Fishel
					// 
					// see below
					// 
					// - .on('click', function () {
					// + .on('click', function (event) {
					
					.on('click', function (event) {
						var strLegendItemClick = 'legendItemClick',
							fnLegendItemClick = function () {
								item.setVisible();
							};
						
						// PATCH by Simon Fishel
						//
						// passing any control/command key modifiers to the event handler
						//
						// + var eventArgs = {
                        // +     ctrlKey: event.ctrlKey,
                        // +     metaKey: event.metaKey
                        // + };
						//
						//   // click the name or symbol
	                    //   if (item.firePointEvent) { // point
						// -     item.firePointEvent(strLegendItemClick, null, fnLegendItemClick);
	                    // +     item.firePointEvent(strLegendItemClick, eventArgs, fnLegendItemClick);
	                    //   } else {
						// -     fireEvent(item, strLegendItemClick, null, fnLegendItemClick);
	                    // +     fireEvent(item, strLegendItemClick, eventArgs, fnLegendItemClick);
	                    //   }
							
						var eventArgs = {
						    ctrlKey: event.ctrlKey,
						    metaKey: event.metaKey
						};

						// click the name or symbol
						if (item.firePointEvent) { // point
							item.firePointEvent(strLegendItemClick, eventArgs, fnLegendItemClick);
						} else {
							fireEvent(item, strLegendItemClick, eventArgs, fnLegendItemClick);
						}
					})
					.attr({ zIndex: 2 })
					.add(legendGroup);

				// draw the line
				if (!simpleSymbol && itemOptions && itemOptions.lineWidth) {
					var attrs = {
							'stroke-width': itemOptions.lineWidth,
							zIndex: 2
						};
					if (itemOptions.dashStyle) {
						attrs.dashstyle = itemOptions.dashStyle;
					}
					item.legendLine = renderer.path([
						M,
						-symbolWidth - symbolPadding,
						0,
						L,
						-symbolPadding,
						0
					])
					.attr(attrs)
					.add(legendGroup);
				}

				// draw a simple symbol
				if (simpleSymbol) { // bar|pie|area|column

					legendSymbol = renderer.rect(
						(symbolX = -symbolWidth - symbolPadding),
						(symbolY = -11),
						symbolWidth,
						12,
						2
					).attr({
						//'stroke-width': 0,
						zIndex: 3
					}).add(legendGroup);

				// draw the marker
				} else if (itemOptions && itemOptions.marker && itemOptions.marker.enabled) {
					legendSymbol = renderer.symbol(
						item.symbol,
						(symbolX = -symbolWidth / 2 - symbolPadding),
						(symbolY = -4),
						itemOptions.marker.radius
					)
					//.attr(item.pointAttr[NORMAL_STATE])
					.attr({ zIndex: 3 })
					.add(legendGroup);

				}
				if (legendSymbol) {
					legendSymbol.xOff = symbolX + (strokeWidth % 2 / 2);
					legendSymbol.yOff = symbolY + (strokeWidth % 2 / 2);
				}

				item.legendSymbol = legendSymbol;

				// colorize the items
				colorizeItem(item, item.visible);


				// add the HTML checkbox on top
				if (itemOptions && itemOptions.showCheckbox) {
					item.checkbox = createElement('input', {
						type: 'checkbox',
						checked: item.selected,
						defaultChecked: item.selected // required by IE7
					}, options.itemCheckboxStyle, container);

					addEvent(item.checkbox, 'click', function (event) {
						var target = event.target;
						fireEvent(item, 'checkboxClick', {
								checked: target.checked
							},
							function () {
								item.select();
							}
						);
					});
				}
			}


			// calculate the positions for the next line
			bBox = li.getBBox();

			itemWidth = item.legendItemWidth =
				options.itemWidth || symbolWidth + symbolPadding + bBox.width + padding;
			itemHeight = bBox.height;

			// if the item exceeds the width, start a new line
			if (horizontal && itemX - initialItemX + itemWidth >
					(widthOption || (chartWidth - 2 * padding - initialItemX))) {
				itemX = initialItemX;
				itemY += itemHeight;
			}
			lastItemY = itemY;

			// position the newly generated or reordered items
			positionItem(item, itemX, itemY);

			// advance
			if (horizontal) {
				itemX += itemWidth;
			} else {
				itemY += itemHeight;
			}

			// the width of the widest item
			offsetWidth = widthOption || mathMax(
				horizontal ? itemX - initialItemX : itemWidth,
				offsetWidth
			);



			// add it all to an array to use below
			//allItems.push(item);
		}

		/**
		 * Render the legend. This method can be called both before and after
		 * chart.render. If called after, it will only rearrange items instead
		 * of creating new ones.
		 */
		function renderLegend() {
			itemX = initialItemX;
			itemY = y;
			offsetWidth = 0;
			lastItemY = 0;

			if (!legendGroup) {
				legendGroup = renderer.g('legend')
					.attr({ zIndex: 7 })
					.add();
			}


			// add each series or point
			allItems = [];
			each(series, function (serie) {
				var seriesOptions = serie.options;

				if (!seriesOptions.showInLegend) {
					return;
				}

				// use points or series for the legend item depending on legendType
				allItems = allItems.concat(seriesOptions.legendType === 'point' ?
					serie.data :
					serie
				);

			});

			// sort by legendIndex
			stableSort(allItems, function (a, b) {
				return (a.options.legendIndex || 0) - (b.options.legendIndex || 0);
			});

			// reversed legend
			if (reversedLegend) {
				allItems.reverse();
			}

			// render the items
			
			// PATCH by Simon Fishel
            //
            // call label render hook before rendering the legend items
            //
            // + if(hooks.labelRenderHook) {
            // +    hooks.labelRenderHook(allItems, options, itemStyle, spacingBox, renderer);
            // + }
            
            if(hooks.labelRenderHook) {
                hooks.labelRenderHook(allItems, options, itemStyle, spacingBox, renderer);
            }
			
			each(allItems, renderItem);



			// Draw the border
			legendWidth = widthOption || offsetWidth;
			legendHeight = lastItemY - y + itemHeight;

			if (legendBorderWidth || legendBackgroundColor) {
				legendWidth += 2 * padding;
				legendHeight += 2 * padding;

				if (!box) {
					box = renderer.rect(
						0,
						0,
						legendWidth,
						legendHeight,
						options.borderRadius,
						legendBorderWidth || 0
					).attr({
						stroke: options.borderColor,
						'stroke-width': legendBorderWidth || 0,
						fill: legendBackgroundColor || NONE
					})
					.add(legendGroup)
					.shadow(options.shadow);
					box.isNew = true;

				} else if (legendWidth > 0 && legendHeight > 0) {
					box[box.isNew ? 'attr' : 'animate'](
						box.crisp(null, null, null, legendWidth, legendHeight)
					);
					box.isNew = false;
				}

				// hide the border if no items
				box[allItems.length ? 'show' : 'hide']();
			}

			// 1.x compatibility: positioning based on style
			var props = ['left', 'right', 'top', 'bottom'],
				prop,
				i = 4;
			while (i--) {
				prop = props[i];
				if (style[prop] && style[prop] !== 'auto') {
					options[i < 2 ? 'align' : 'verticalAlign'] = prop;
					options[i < 2 ? 'x' : 'y'] = pInt(style[prop]) * (i % 2 ? -1 : 1);
				}
			}
			
			// PATCH by Simon Fishel
            // 
            // call placement hook before aligning the legend element
            //
            // + if(hooks.placementHook) {
            // +    hooks.placementHook(options, legendWidth, legendHeight, spacingBox);
            // + }
            
            if(hooks.placementHook) {
                hooks.placementHook(options, legendWidth, legendHeight, spacingBox);
            }

			if (allItems.length) {
				legendGroup.align(extend(options, {
					width: legendWidth,
					height: legendHeight
				}), true, spacingBox);
			}

			if (!isResizing) {
				positionCheckboxes();
			}
		}


		// run legend
		renderLegend();

		// move checkboxes
		addEvent(chart, 'endResize', positionCheckboxes);

		// expose
		return {
			colorizeItem: colorizeItem,
			destroyItem: destroyItem,
			renderLegend: renderLegend,
			destroy: destroy
		};
	}