Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.
Sign up[BUG] iOS click event issue and instanceof failing #4152
Comments
This comment has been minimized.
This comment has been minimized.
|
@Flamenco off the top of my head I'm not sure what's causing this. Do you have a fiddle that reproduces this? Does this only happen on Safari for iOS? Have you tried maybe breakpointing the click event in chrome and seeing what's handling it? I think the remote chrome debugging will work OK for doing that |
This comment has been minimized.
This comment has been minimized.
|
This shows the instanceof issue: The click issue is a bit tricky, as it is in a stack that has many layers and cannot be posted. Ideally if I set events=[], no event listeners should be registered for mouse or touch events. I might strip them out of the source and see if that solves my issue on that front. |
This comment has been minimized.
This comment has been minimized.
|
Seems like the iframe puts some kind of proxy around the elements... |
This comment has been minimized.
This comment has been minimized.
|
The click issue only happens on iOS safari (and chrome because apple makes google use their crap internally). So more likely touch events then click events. |
This comment has been minimized.
This comment has been minimized.
|
Everything in the iframe has it's own prototype. If Chart.js were included inside the iframe it would have the correct definition and would work as you expect. In terms of adding event listeners, we only do that if specified per https://github.com/chartjs/Chart.js/blob/master/src/core/core.controller.js#L704-L707 |
This comment has been minimized.
This comment has been minimized.
|
It does work when I remove the instanceof checks, so perhaps Chart.js should determine validity in a different way. |
This comment has been minimized.
This comment has been minimized.
|
BTW
That's good to know! Thanks. |
This comment has been minimized.
This comment has been minimized.
|
Should I close this, or were you thinking about updating the code to be more inclusive? |
This comment has been minimized.
This comment has been minimized.
|
My inclination is to close this. @simonbrunel thoughts? |
This comment has been minimized.
This comment has been minimized.
|
If I send in a valid context or canvas, that actually does work, I thinks its bug to reject it in acquireContext() |
This comment has been minimized.
This comment has been minimized.
|
The big issue here is sending a context from a different frame. I think you should just include Chart.js inside the iframe and the problem will go away. I don't know that we want to support rendering in one frame with a canvas from another. That seems like a bit of an anti-pattern |
This comment has been minimized.
This comment has been minimized.
|
No, I don't think so. The big issue is you are forcing your library to conform to an implementation and not an interface. Calling my use-case an anti-pattern is just plain off-base. The problem is a weak design pattern in Charts.js. For example, I have developed context2d adapters/renderers that generate PDF and SVG. I send my context2d compatible object into Charts.js and get VECTOR quality charts in PDF and SVG. But I have to hack your library because it discriminates. Also, in this case, there is no IFRAME that I am running the code in. (https://github.com/MrRio/jsPDF/blob/master/plugins/context2d.js) In the example initially posted, I am dynamically creating an iframe and canvas; it makes no sense to load a separate version of Charts.js and configuration into each one when it is absolutely not necessary, and the charts are controlled/integrated with other elements in the main window, outside the IFRAME. I can't understand why anybody in their right mind would want to limit the use of a library in such a way. IMHO, if the canvas has a context2d and the context2d has a canvas, that should be good enough to pass the test. |
This comment has been minimized.
This comment has been minimized.
|
The context2d adapters/renderers is a special case which is not fully compatible with the However, I agree that the IFRAME use case should be handled by // ...
if (item && item.canvas) {
// Support for any object associated to a canvas (including a context2d)
item = item.canvas;
}
// To prevent canvas fingerprinting, some add-ons undefine the getContext
// method, for example: https://github.com/kkapsner/CanvasBlocker
// https://github.com/chartjs/Chart.js/issues/2807
var context = item && item.getContext && item.getContext('2d');
if (context) {
initCanvas(item, config);
return context;
}
return null; |
This comment has been minimized.
This comment has been minimized.
|
@simonbrunel That all makes sense to me :) Splitting the adapter use case into a non-responsive adapter platform seems like a wise choice. Another thought to your solution is to and add an else if after (instead of replacing) the current code, and set a flag in the config so the internals can check if the canvas was embedded, if the need arises. |
This comment has been minimized.
This comment has been minimized.
|
Having a valid canvas is currently one of the requirements of |
This comment has been minimized.
This comment has been minimized.
|
I mean something like this for the first use case (not adapter):
|
This comment has been minimized.
This comment has been minimized.
|
Your var context = item && item.getContext && item.getContext('2d');
if (context) {
config._isInIframe = item.ownerDocument !== document;
initCanvas(item, config);
return context;
}But handling canvas in IFRAME should not become a special case across the code so I would not add this extra |
This comment has been minimized.
This comment has been minimized.
|
This is true. I am just showing a case in point: to have an else statement that detects the condition and sets a flag, whilst keeping your current code. MIght come in handy some day. |
This comment has been minimized.
This comment has been minimized.
|
@simonbrunel just tested your fix in the context of #3887, it works. But the resize detection iframe doesn't seem to pick up on the window resizes; this is however as best I can tell a completely separate bug (the container is |
This comment has been minimized.
This comment has been minimized.
|
@mgetzbw that sounds great, thanks for testing! For the resize detection, are you able to share a live test case of the issue? |
This comment has been minimized.
This comment has been minimized.
|
@simonbrunel not at this time unfortunately. It's most likely an issue I should probably file against Salesforce's aura framework as the iframe is being created in the primary dom. I suspect it has to do with the fact they intercept all event handlers to keep components from messing with each other. If you're using an |
This comment has been minimized.
This comment has been minimized.
|
The "canvas in iframe" issue has been reported in this ticket #4102 |
This comment has been minimized.
This comment has been minimized.
|
Resolved in #4165 |
I have a runtime that adds charts to multiple canvases on the same page. I have a list of charts in the left column, and every time one of those items are clicked, I add a chart on the right column. I am using Vaadin in my runtime stack.
On iOS, after I add a chart, the Vaadin stack no longer receives any click events.
So I set events=[] hoping that would solve the problem. It did not.
So instead of adding canvas, I added iframes, then added canvas to the iframes, and fed that canvas to Charts.js, in hopes of isolating the click eater.
Charts.js would not accept the canvas or it's context2d because BOTH of the instanceof checks in platform.dom.js. fail when the canvas is coming from the iframe. When I remove the type checks, Charts.js works like a charm.
Environment