I need to set the resources object within the Highcharts exporting module's exportChart method but can't seem to overwrite it.
The export module source code is located at http://code.highcharts.com/modules/exporting.src.js and the specific subsection of this that I am overwriting looks like this:
'use strict';
(function (factory) {
if (typeof module === 'object' && module.exports) {
module.exports = factory;
} else {
factory(Highcharts);
}
}(function (Highcharts) {
(function (H) {
// create shortcuts
var Chart = H.Chart,
merge = H.merge,
extend = H.extend;
//... Removed extra code not needed for example
extend(Chart.prototype, /** #lends Highcharts.Chart.prototype */ {
exportChart: function (exportingOptions, chartOptions) {
var svg = this.getSVGForExport(exportingOptions, chartOptions);
// merge the options
exportingOptions = merge(this.options.exporting, exportingOptions);
// do the post
H.post(exportingOptions.url, {
filename: exportingOptions.filename || 'chart',
type: exportingOptions.type,
// IE8 fails to post undefined correctly, so use 0
width: exportingOptions.width || 0,
scale: exportingOptions.scale,
svg: svg
}, exportingOptions.formAttributes);
}
//... Removed extra code not needed for example
});
//... Removed extra code not needed for example
}(Highcharts));
}));
To test the ability to overwrite the method I am using the following code:
(function (H) {
var Chart = H.Chart,
extend = H.extend;
extend(Chart.prototype, /** #lends Highcharts.Chart.prototype */ {
exportChart: function (exportingOptions, chartOptions) {
alert('changed it');
}
});
}(Highcharts));
The alert never fires but instead the normal export is still happening.
I've created a JSFiddle showing this issue here: https://jsfiddle.net/j005v79j/
Can anyone tell me why the overwriting of this method isn't working?
I realized I was also loading code.highcharts.com/modules/offline-exporting.js on my side which was not in the fiddle. This script overwrote the export buttons to use a different method called exportChartLocal(). Since the buttons were now tied to a method that would never be called my alert was not firing.
I've removed the call to offline-exporting for now and will write overwrites into my code for this version at a later date.
Thanks to #Kamil for pointing out the issue.
Related
I am using require.js to organize my js:
define([
'underscore',
'sylvester',
'glUtils',
'GLFacade',
'Item',
'Attribute',
'Buffer',
], function(
_,
sylv,
glUtils,
GLFacade,
Item,
Attribute,
Buffer
) {
"use strict";
function Sprite() { this.init.apply(this, arguments); }
_.extend(Sprite.prototype, {
init: function(prog, img, viewPort) {
this._frameNum = 0;
this._framesPerAnimation = 4;
this._prog = prog;
this._viewPort = viewPort;
this._img = new ImageWrapper(img);
//...other initialization stuff...
},
//...other methods...
});
return Sprite;
});
but I consistently run into the error that I forget to add a module to the top of the file. Above I've forgotten to add ImageWrapper to my dependencies. When I do this, my code silently fails with no error messages, even though ImageWrapper is undefined. If I try to log console.log(ImageWrapper) I do indeed get an error.
Why doesn't the constructor call to new ImageWrapper(img) fail with an error? And is there something similar to "use strict;" that I can use to increase the error information during development?
You could lint your code using a tool like http://jshint.com/ - you will get something like:
One undefined variable
27 ImageWrapper
Depending on your setup there are different ways to automate this, some editors have built this in or plugins can extend this functionality. There also is a command line version on npm if you want to run jshint manually: https://npmjs.org/package/jshint
Your code should throw an error but only if you instantiate a new Sprite.
When I try to simplify your code like this
define('Sprite', ['underscore'], function(_) {
'use strict';
function Sprite() {
this.init.apply(this, arguments);
}
_.extend(Sprite.prototype, {
init: function() {
this._foo = new DoesntExist();
}
});
return Sprite;
});
require(['Sprite'], function(Sprite) {
var sprite = new Sprite();
});
it throws a ReferenceError as expected.
I am having some issues trying to work out what is going ok with MVC SPA and Knockout.
When you create a new project some files are created for knockout.js as examples, but I am struggling to understand what is going on.
Primarily the issue is with the app.viewmodel.js and the function AddViewModel.
Here is some code which I will attempt to breakdown:
self.addViewModel = function (options) {
var viewItem = {},
navigator;
// Example options
//{
// name: "Home",
// bindingMemberName: "home",
// factory: HomeViewModel
//}
// Add view to AppViewModel.Views enum (for example, app.Views.Home).
self.Views[options.name] = viewItem; // Don't really get this, seems to add a blank object to app.Views.Home
// Add binding member to AppViewModel (for example, app.home);
self[options.bindingMemberName] = ko.computed(function () {
//if (self.view() !== viewItem) {
// console.log(self.view()); // returns {}
// console.log(viewItem); // returns {}
// return null; // should never hit this?
//}
return new options.factory(self, dataModel); // This adds our ViewModel to app.home, app.login, etc
});
// This checks to see if we have defined a navigatorFactory in our viewmodel (AddViewModel)
if (typeof (options.navigatorFactory) !== "undefined") {
navigator = options.navigatorFactory(self, dataModel);
} else {
navigator = function () {
console.log(viewItem);
self.view(viewItem);
};
}
// Add navigation member to AppViewModel (for example, app.NavigateToHome());
self["navigateTo" + options.name] = navigator;
};
ok, so let's start. First of all we declare 2 variables:
var viewItem = {},
navigator;
viewItem is set as a blank object and navigator is undefined.
The first thing we do, is set self.Views[options.name] to our viewItem, so in my understanding, this would mean:
self.Views.Home = {}
If we look at the declaration in app.viewmodel.js self.Views looks like this:
self.Views = {
Loading: {} // Other views are added dynamically by app.addViewModel(...).
};
So in here there is already a view called Loading. So I am confused as to what is actually happening here.
The next bit of code creates a function:
self[options.bindingMemberName] = ko.computed(function () {
return new options.factory(self, dataModel);
});
This is a lot easier to understand. It basically takes our ViewModel and adds it to a function under the name of self.home (or whatever the bindingMemberName of our ViewModel is.
This next piece is what confuses me:
if (typeof (options.navigatorFactory) !== "undefined") {
navigator = options.navigatorFactory(self, dataModel);
} else {
navigator = function () {
console.log(viewItem);
self.view(viewItem);
};
}
// Add navigation member to AppViewModel (for example, app.NavigateToHome());
self["navigateTo" + options.name] = navigator;
If I strip this down, it basically says if we define a navigatorFactory, then the navigator (which is currently undefined!) is equal to our navigatorFactory. That bit is easy.
It's the next bit I don't get.
It says, else, the navigator is a function that returns our self.view(viewItem) (remember that viewItem is just a blank object.
Then we set self["navigateTo" + options.name] = navigator.
So in english, this looks like it is saying, get our blank viewItem, assign it to self.view for every ViewModel we add. Then assign a function returning our self.view(viewItem) to our navigator variable (which is currently undefined) and assign this to our self.naviateToHome() (or whatever).
So to me, that looks like self.navigateToHome(), self.navigateToLogin(), self.navigateToTimbucktoo() would all return the same function with the same self.view.
So, can anyone explain to me what is actually happening?
Update 1
So, I have figured some things out. First things first, the navigator is setting the current view, so basically self.Views looks like this after all the models are added:
self.Views = {
Loading: { },
Home: { },
Login: { }
}
So even though self.view() returns an empty object, it isn't the same as the viewItem because it is stored with the name into self.Views.
So, the navigator is actually applying the viewItem to self.views.
I tested this out by changing the viewItem to this:
var viewItem = { options.name }
and sure enough, self.Views looked liked this:
self.Views = {
Loading: { },
Home: { name: "Home" },
Login: { name: "Login" }
}
so when we set self.view using our navigator, the function is called (app.home for example) and it runs the code to return our factory or null if it isn't the current view.
In YUI3 is it possible to overwrite a method from e.g. the Node module? For example, I want to do something like this:
Y.Node.prototype.get = function () {
// Do some stuff then call the original function
};
That works perfectly (as you would expect) when Y is the globally available instance of YUI that I presume is created by the library. It does not work when you use the module loader and pass a callback:
YUI().use("*", function (DifferentY) {
DifferentY.Node.prototype.get === Y.Node.prototype.get; // false
});
I've spent a while digging through the YUI source but have so far failed to work out where and how DifferentY in the previous example is created (and by extension, where DifferentY.Node is created).
I have never used YUI before so it may be that I'm going about this in the completely wrong way.
Ok If I look at that example there seems to be a misunderstanding about Y. In YUI3 every thing is sandboxed, so you can have multiple instances of YUI running simultaneously. Y is not a global variable, it will be instantiated when you call the YUI().use method and only exists inside that function. That's why in the code of SO only DifferentY exists, but not Y.
YUI().use('node', 'event', function (Y) {
// The Node and Event modules are loaded and ready to use.
// Y exists in here...
});
So if you want to enhance YUI "from outside" I would build on YUI's module strategy and create a YUI module with YUI.add()
if (YUI) {
YUI.add('node-enhancement', function (Y) {
Y.Node.prototype.get = function () {
// Do some stuff then call the original function
};
}, '0.0.1', {
requires: [Node]
});
}
and let the developer load the enhancement as a module (how he would do it anyway with yui3)
YUI().use('node-enhancement'), function(Y) {
// just use YUI as allways
});
for an explanation of how the global YUI object works, this overview might help: http://yuilibrary.com/yui/docs/yui/
Here is an usage example of monkey patching technique.
Check out the console output here: http://jsfiddle.net/jslayer/XmF6L/
YUI.add('node-custom-module', function(Y){
console.warn('Override Y.Node');
Y.Node.YOUR_NODE = 'custom Node';
});
YUI.add('widget-custom-module', function(Y){
console.warn('Override Y.Widget');
Y.Widget.YOUR_WIDGET = 'custom Widget';
});
YUI.GlobalConfig = {
modules : {
'node-custom-module' : {
condition : {
name : 'node-custom-module',
trigger : 'node',
test : function(){
return true;
}
}
},
'widget-custom-module' : {
condition : {
name : 'widget-custom-module',
trigger : 'widget',
test : function(){
return true;
}
}
}
}
};
YUI().use('node', function(Y) {
console.group('Node');
console.log('Y.Node.YOUR_NODE : ', Y.Node.YOUR_NODE);
console.groupEnd('Node');
});
YUI().use('widget', function(Y) {
console.group('Widget');
console.log('Y.Node.YOUR_NODE : ', Y.Node.YOUR_NODE);
console.log('Y.Widget.YOUR_WIDGET : ', Y.Widget.YOUR_WIDGET);
console.groupEnd('Widget');
});
Surely it is not necessary to use YUI.GlobalConfig.
Also, it is comfortably to use groups (http://yuilibrary.com/yui/docs/yui/loader.html) inside YUI config's
groups : {
patches : {
modules : {
/* Define your mp modules here */
}
}
}
I've a page that is generated dynamically, and that includes certain number (user-dynamically-defined) of advanced scatter plot charts. I intend to create a JavaScript object which defines the scatter plot itself, i.e. which takes some parameters, some data, and some container ID, and which will create the various elements needed to obtain the visualisation: canvas elements, toolbar, etc.. To do so, I started with the following (simplified) class:
(function () {
if (!this.namespace) { this.namespace = {};}
this._instances = { index: 0 };
this.namespace.ScatterPlot = function (containerId, file, options) {
_instances.index ++;
this.id = this.containerId+"-"+_instances.index ;
this.containerId = containerId ;
_instances [this.id] = this;
// ... Do stuffs with file and options ...
// Initialize elements once the DOM is ready
$(this.updateDOM);
}
namespace.ScatterPlot.prototype = {
updateDOM: function() {
$("<canvas>")
.click(clickCallback)
.appendTo("#"+this.containerId);
//(...)
},
clickCallback: function() {
alert("Some click: "+this.id);
}
}
})();
Each object can be created with:
var v1 = new namespace.ScatterPlot("container1", "foo", "foo");
var v2 = new namespace.ScatterPlot("container2", "foo", "foo");
There are two problems here: (1) in updateDOM, 'this' does not make reference to my initial ScatterPlot object, which means that this example will never work, and (2) similarly, the clickCallback will not be able reference the scatterplot with 'this' either.
I'm new to javascript, and I'm still struggeling to understand the logic of OO programming in javascript, so the question is: I'm I taking the wrong direction here ? After some digging, I could roughly achieve what I wanted by passing this to updateDOM:
$(this.updateDOM(this)); // This blows my eyes but does the trick, at least partially
updateDOM: function(that) {
$("<canvas>")
.click(that.clickCallback)
.appendTo("#"+that.containerId);
//(...)
},
clickCallback: function() {
// Not working either... Should pass 'that' to the function too
alert("Some click: "+this.id);
}
But I don't feel this patters to be very elegant... And the problem is not fixed either regarding the click callback.
Thoughts ?
Have a look at MDN's introduction to the this keyword.
The standard ways of dealing with that issue are using a that variable - not as an argument, but in a separate function:
var that = this;
$(function() {
that.updateDOM();
});
// or
$(this.getClickCallback());
...
namespace.ScatterPlot.prototype.getClickCallback = function() {
var that = this;
return function clickCallback(e) {
alert("Some click: "+that.id);
};
};
Alternatively, you can always use .bind() (or $.proxy for older browsers) which do quite what the second example does in a more generic way:
$(this.clickCallback.bind(this));
I have a "master" view, a layout if you will, that loads other views through the loadView method. My problem is that these view classes perform some initialisation logic (in initialize) that can only be performed once (to do with templating). If, however, I try and instantiate these classes more than once, I get an error symptomatic of calling initialize on the same instance.
I have tried, in the console, instantiating them separately by loading the class and creating two new instances using var x = new MyViewClass(); but each time the first one instantiates and the second one fails because of this error caused by the templates already being initialised.
This really shouldn't be happening, but I cannot for the life of me see what is causing the problem.
The layout's loading code is below.
loadView: function(name, bootstrap_function) {
this.unloadView();
var _class = require('View/'+name), // Let's load the view file
pretty = name.replace('/', ''), // Prettify the name by removing slashes (should end up with some camelcased niceness)
bs_name = '__bootstrap'+pretty, // Generate the name of the bootstrap function
view = new _class(); // Pass the event aggregator in
// If there is a bootstrap function, bootstrap
if(typeOf(bootstrap_function) == 'function') { // Check if one has been passed in
bootstrap_function.call(this, view); // Bootstrap: function(AppView, LoadedView)
}
this._loaded = view; // Store the view in _loaded
// Now that we have a view to play with
// we should insert it into our container object
view.$el.appendTo(this.$container);
// And render!
view.render();
},
unloadView: function() {
if(this._loaded !== null) {
this._loaded.remove();
this._loaded.unbind();
this._loaded = null;
}
}
EDIT
The templating code that is having the errors is this:
processTemplates: function() {
if(this.templates === undefined) return this;
console.log(this.templates);
if(Object.getLength(this.templates) > 0) {
Object.each(this.templates, function(template, name) {
this.templates[name] = _.template(template);
}, this);
}
return this;
},
The console.log(this.templates) output shows that on the first initialisation, this.templates contains strings, as it should, but on second initialisation it shows template functions (which should only be the case after processTemplates() is called.
I wonder if it could have anything to do with the way my class is defined, for example:
define(
['backbone', 'View/Kords', 'text!Template/Pages/Landing.html', 'Collection/TenantTypes'],
function(Backbone, KordsView, landing_html, TenantTypesCollection) {
var LandingView = KordsView.extend({
tagName: 'div',
className: 'tiled-light',
templates: {
'main': landing_html
},
landing_html is defined like this in the class, but could there be a reference problem? _.template should not be affecting the value of landing_html within the scope, should it?
EDIT #2
It is not to do with the reference to landing_html. I tried just setting templates.main to a string in the class definition but I still got the errors as before.