-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rendered Paper.text() incorrectly y-positioned on hidden papers #491
Comments
Our web app which draws circumplex graphs also suffers from the same bug. Firefox & Opera display fine whether rendered hidden or not, but IE9, Chrome, and Safari all render fine while NOT hidden, but hidden doubles the Y coordinate. Any outlook on a fix for this? It's been two months. Thanks. :o) |
Ok so I wrote a temporary fix in our own code until Dmitry is able to attend to this issue. Add this to your stylesheet:
Then rather than applying Finally, assuming all your other hidden tabs are set to
or
|
I've found a hack-ish solution that might work for people until this is fixed, wrap your code in a setTimeout() function.
edit: Coming back after learning how to javascript, I've learned why this works (kinda, I mean, I don't understand Raphael's code too much). When you use You probably don't want to litter your code with setTimeouts, as it will screw up the flow of your logic, since some code now executes much later than other code following it, which you'd naively presume is executed in reverse order if you didn't understand how I'd suggest only using this if you need a quick fix and you have no code dependent on the position of your text. I'd try and fix the problem for real but it doesn't look like the repository is getting any love. 👎 |
@gitpullgravity Thanks a lot. Your hack solved my problem! |
I've hit this same issue. Can't really use @pragmaticdave's fix as the items I'm hiding using display:none need to be faded in using jQuery, and @gitpullgravity's hack doesn't seem to want to work with my code either. I'm curious as to whether this is likely to be fixed in the near future or is simply a limitation that can't be avoided? |
I had the same problem and I found a solution similar to @pragmaticdave. <style>
.tab-raphael {
display: block !important;
position: absolute;
top: -9999px;
}
.tab-raphael.active {
position: relative;
top: 0;
}
</style> |
+1 for @pragmaticdave 's solution, I did something similar and it works well. Just remember to block out all of Bootstrap's tab CSS and Javascript or it might not work still |
@oyatek 's solution works fine with Twitter Bootstrap. I wonder if this will be fixed (it's been 9 months already)... |
For me such solution worked, using jQuery: var label = paper.text(x, y, content);
$('tspan', label.node).attr('dy', 0); |
The solution above won't work for me, neither changing CSS helps. I used setTimeout before, but it's not an option anymore, as I don't want to carry a callback for this. |
@MarcinCieslak's solution worked geat for me! Tnx a lot! |
Nevermind my problem, just make sure the container element is already in the DOM, and thereby not hidden. |
@MarcinCieslak works great, i additionally filtered by ":first-child" otherwise multiple lines would overlap in the same space, i.e. $('tspan:first-child', txt.node).attr('dy', 0); |
+1 on getting this fixed. Thanks, everyone, for reporting and posting workarounds. |
+1 |
I'm working on a fix for this, and I'm struggling to understand the rationale and intentions behind the post-adjustment code.
For my own extremely narrow set of uses, I can just replace this line with |
+1, I'm also hitting this. |
+1 I resolved this with setTimeout Function . var element = paper.text(); ... few lines later element.attr(attrObject); In this case I had to put the timeout around the part where I set attributes so this worked for me var element = paper.text(); setTimeout(function(){ |
+1. I'm also running into this issue. |
+1 me too |
+1 , and use @gitpullgravity 's solution worked good. |
@MarcinCieslak's solution worked geat for me! Tnx a lot! |
Any news on this subject? |
A run-once, vanilla javascript hack:
Simply run the above code and then you can just use |
+1, using the suggestions provided here |
@pragmaticdave's solution didn't work for me Looking for this to get fixed by Raphael of course, though |
I do not think Raphael is being developed anymore. If you have a chance, consider switching to Snap |
Snap hasn't seen much activity in the last year. I wouldn't be so sure that it's being actively developed either. |
Any PR for @joshbambrick's fix? Because that code is more like an extension and setTimeout seems hacky... |
@tomasAlabes joshbambrick's fix also uses a setTimeout. It just abstracts it by monkey-patching Raphael's text method. |
The dy attribute seems to be set on all tspans earlier in the function. I've had luck showing and hiding text elements with the following patch. It does not require a setTimeout, but I don't think it addresses the issue of a container object being hidden. It does however prevent the dy value being rewritten based on bounding box height of 0 — occurs when the text element is hidden. Replace this: dif && R.is(dif, "finite") && $(tspans[0], {dy: dif}); With this: if( bb.height ) dif && R.is(dif, "finite") && $(tspans[0], {dy: dif}); |
@aleph1 perfect! |
Why isn't this fixed yet? I ran into the same problem. My canvas is hidden when I draw it, and when it is shown the text has too much dy. I fixed it with by setting the dy manually, but that is a very awkward solution, and I have to figure out the correct value by trying and failing:
|
Maybe we can use 'visibility' instead of 'display' to control the element hidden or show. |
@zhaoruda Maybe you should try that and see if it works |
/* * * */ ;(function ( $, window, document, undefined ) { var config = { radius : 80, paddingX : 40, paddingY : 40, gaugeWidth : 30, fill : '0-#1cb42f:0-#fdbe37:50-#fa4133:100', gaugeBackground : '#f4f4f4', background : '#fff', showNeedle : true, animationSpeed : 500, width : 0, height : 0, centerX : 0, centerY : 0, min : 0, max : 100, value : 80, valueLabel : { display : true, fontFamily : 'Arial', fontColor : '#000', fontSize : '20', fontWeight : 'normal' }, title : { display : true, value : '', fontFamily : 'Arial', fontColor : '#000', fontSize : '20', fontWeight : 'normal' }, label : { display : true, left : 'Low', right : 'High', fontFamily : 'Arial', fontColor : '#000', fontSize : '12', fontWeight : 'normal' } }; // Create an arc with raphael.js Raphael.fn.arc = function(startX, startY, endX, endY, radius1, radius2, angle) { var arcSVG = [radius1, radius2, angle, 0, 1, endX, endY].join(' '); return this.path('M' + startX + ' ' + startY + ' a ' + arcSVG); }; // Calculate a circular arc with raphael.js Raphael.fn.circularArc = function(centerX, centerY, radius, startAngle, endAngle) { var startX = centerX + radius * Math.cos(startAngle * Math.PI / 180); var startY = centerY + radius * Math.sin(startAngle * Math.PI / 180); var endX = centerX + radius * Math.cos(endAngle * Math.PI / 180); var endY = centerY + radius * Math.sin(endAngle * Math.PI / 180); return this.arc(startX, startY, endX-startX, endY-startY, radius, radius, 0); }; // The kuma Gauge constructor function kumaGauge(element, options , method) { // This var _this = this; // The element _this.element = element; _this.$element = $(element); // The config _this.config = $.extend( {}, config, options ); _this._config = config; _this.method = method; // The actual gauge _this.gauge = {}; // Initialise _this.init(); } // Extend the kumaGauge object kumaGauge.prototype = { init: function () { // this _this = this; if (!_this.method) { _this.draw(); } }, _setup : function() { // This _this = this; // Calculate some values needed do draw the gauge _this.config.width = (_this.config.radius * 2) + (_this.config.paddingX * 2); _this.config.height = _this.config.radius + (_this.config.paddingY * 2); _this.config.centerX = _this.config.paddingX + _this.config.radius; _this.config.centerY = _this.config.paddingY + _this.config.radius; // The div wich acts as the canvas needs an id, so we give it a unique one if it doesn't have one if (typeof $(this).attr('id') === 'undefined' || $(this).attr('id') === '') { _this.config.id = 'gauge-' + $('*[id^="gauge-"]').length; _this.$element.attr('id', _this.config.id); } }, _calculateRotation : function(min, max, val) { var _range, _rotation; _range = max - min; if (val < max && val > min) { _rotation = 180 * ((val - min) / _range); } else if (val <= min){ _rotation = 0; } else { _rotation = 180; } return _rotation; }, draw : function() { //this var _this = this; // Setup all the needed config variables _this._setup(); // Make the base drawing Canvas _this.gauge = new Raphael(_this.config.id, _this.config.width, _this.config.height); // Draw the gauge _this.gauge.gauge = _this.gauge.circularArc(_this.config.centerX, _this.config.centerY, _this.config.radius, 180, 0); _this.gauge.gauge.attr({ 'fill' : _this.config.fill, 'stroke' : 'none' }); _this.gauge.gauge.node.setAttribute('class', 'gauge'); // Draw the gauge background _this.gauge.gaugeBackground = _this.gauge.circularArc(_this.config.centerX, _this.config.centerY, _this.config.radius, 180, 0); _this.gauge.gaugeBackground.attr({ 'fill' : _this.config.gaugeBackground, 'stroke' : 'none' }); _this.gauge.gaugeBackground.node.setAttribute('class', 'gauge__background'); // Draw the white center arc _this.gauge.centerArc = _this.gauge.circularArc(_this.config.centerX, _this.config.centerY, _this.config.radius - _this.config.gaugeWidth, 180, 0); _this.gauge.centerArc.attr({ 'fill' : _this.config.background, 'stroke' : 'none' }); _this.gauge.centerArc.node.setAttribute('class', 'gauge__center'); // Draw the needle if (_this.config.showNeedle) { _this.gauge.needle = _this.gauge.rect(_this.config.centerX, _this.config.paddingY, 1, 40); _this.gauge.needle.attr({ 'fill' : '#000', 'stroke' : 'none' }); _this.gauge.needle.node.setAttribute('class', 'gauge__needle'); } // Draw the bottom mask to hide the rotated background arc _this.gauge.bottomMask = _this.gauge.rect(0, _this.config.centerY, _this.config.width, 40); _this.gauge.bottomMask.attr({ 'fill' : _this.config.background, 'stroke' : 'none' }); // Draw the text container for the value if (_this.config.valueLabel.display) { if (_this.config.showNeedle) { _this.gauge.valueLabel = _this.gauge.text(_this.config.centerX, _this.config.centerY - 10, Math.round((_this.config.max - _this.config.min) / 2)); } else { _this.gauge.valueLabel = _this.gauge.text(_this.config.centerX, _this.config.centerY - 10, _this.config.value); } _this.gauge.valueLabel.attr({ 'fill' : _this.config.valueLabel.fontColor, 'font-size' : _this.config.valueLabel.fontSize, 'font-family' : _this.config.valueLabel.fontColor, 'font-weight' : _this.config.valueLabel.fontWeight }); _this.gauge.valueLabel.node.setAttribute('class', 'gauge__value'); } // Draw the title if (_this.config.title.display) { _this.gauge.title = _this.gauge.text(_this.config.centerX, _this.config.paddingY - 5, _this.config.title.value); _this.gauge.title.attr({ 'fill' : _this.config.title.fontColor, 'fill-opacity' : 0, 'font-size' : _this.config.title.fontSize, 'font-family' : _this.config.title.fontFamily, 'font-weight' : _this.config.title.fontWeight }); _this.gauge.title.node.setAttribute('class', 'gauge__title'); } if (_this.config.label.display) { // Draw the left label _this.gauge.leftLabel = _this.gauge.text((_this.config.gaugeWidth / 2) + _this.config.paddingX, _this.config.centerY + 10, _this.config.label.left); _this.gauge.leftLabel.attr({ 'fill' : _this.config.title.fontColor, 'fill-opacity' : 0, 'font-size' : _this.config.label.fontSize, 'font-family' : _this.config.label.fontFamily, 'font-weight' : _this.config.label.fontWeight }); _this.gauge.leftLabel.node.setAttribute('class', 'gauge__label--left'); // Draw the right label _this.gauge.rightLabel = _this.gauge.text((_this.config.width - (_this.config.gaugeWidth / 2)) - _this.config.paddingX, _this.config.centerY + 10, _this.config.label.right); _this.gauge.rightLabel.attr({ 'fill' : _this.config.title.fontColor, 'fill-opacity' : 0, 'font-size' : _this.config.label.fontSize, 'font-family' : _this.config.label.fontFamily, 'font-weight' : _this.config.label.fontWeight }); _this.gauge.rightLabel.node.setAttribute('class', 'gauge__label--right'); } // There is a bug with raphael.js and webkit which renders text element at double the Y value. // Resetting the Y values after a timeout fixes this. // See DmitryBaranovskiy/raphael#491 setTimeout(function() { if (_this.config.valueLabel.display) { _this.gauge.valueLabel.attr('y', _this.config.centerY - 10); } if (_this.config.title.display) { _this.gauge.title.attr({ 'y' : _this.config.paddingY - (_this.gauge.title.getBBox().height / 2), 'fill-opacity' : 1 }); } if (_this.config.label.display) { _this.gauge.leftLabel.attr({ 'y' : _this.config.centerY + (_this.gauge.leftLabel.getBBox().height / 2), 'fill-opacity' : 1, }); _this.gauge.rightLabel.attr({ 'y' : _this.config.centerY + (_this.gauge.rightLabel.getBBox().height / 2), 'fill-opacity' : 1, }); } }, 1000); // Animate the gauge to the right value position _this.gauge.gaugeBackground.animate({transform:'r' + _this._calculateRotation(_this.config.min, _this.config.max, _this.config.value) + ',' + _this.config.centerX + ',' + _this.config.centerY}, _this.config.animationSpeed, '<>'); }, update: function (data) { //this var _this = this; var updateGauge = function(min, max, value) { _this.config.min = min; _this.config.max = max; _this.config.value = value; // Update the rotation of the gauge _this.gauge.gaugeBackground.animate({transform:'r' + _this._calculateRotation(min, max, value) + ',' + _this.config.centerX + ',' + _this.config.centerY}, _this.config.animationSpeed, '<>'); // Update the value label if (_this.config.valueLabel.display) { if (_this.config.showNeedle) { _this.gauge.valueLabel.attr('text', value); } else { _this.gauge.valueLabel.attr('text', (max - min) / 2); } } }; if (typeof data.min !== 'undefined' && typeof data.max !== 'undefined' && typeof data.value !== 'undefined') { updateGauge(data.min, data.max, data.value); } else if (typeof data.value !== 'undefined') { updateGauge(_this.config.min, _this.config.max, data.value); } } }; $.fn.kumaGauge = function ( method, options ) { var _method = method, _arguments = arguments, _this = this; if (typeof _method !== 'string') { if (_arguments.length === 1 ) { options = _method; method = false; return this.each(function() { if ( !$.data( this, 'kumaGauge' ) ) { $.data( this, 'kumaGauge', new kumaGauge( this, options, method ) ); } }); } } else { return this.each(function() { if (typeof $.data(this, 'kumaGauge')[method] === 'function') { $.data(this, 'kumaGauge')[method](options); } }); } }; })( jQuery, window, document );
I've a web app which provides two calendar illustrations, each one on its own tab and rendered with Raphael. The problem is the following: text rendered with Paper.text() is incorrectly y-offset in the tab which is initially hidden (not visible because the other tab is selected). I debugged the situation and the root cause is the following:
On the last line of tuneText() Raphael 2.0.1 tries post-adjust the "dy" value of the first "tspan" element of the "text" element. For this it uses _getBBox() to find out the bounding box of the element. It even is clever enough to first make it temporarily visible (not hidden). But this doesn't make any difference if the outmost container (in my case the tab containing the illustration) is hidden. In WebKit browsers one always gets an empty bounding box with "undefined" "y" and "height" values, in Gecko based browsers one gets "y" and "height" set to "0" . As a result, _getBBox() returns a SVGRect with "y" and "height" set to 0 or undefined. Raphael then for "undefined" does nothing (and as a result has an incorrect y offset) and for "0" incorrectly calculates the new "dy" for the first "tspan" as: "dif = a.y - (bb.y + bb.height / 2);" which results in an effective "dif = ay" and hence if you draw text on say position (100,100) the "text" is at (100,100) and its "tspan" will be on (100,200) because the "tspan" becomes a "dy" = 100 as a result of the empty bounding box. In WekKit browsers one can see this incorrect placement most easily as the "dy" is too large, in Gecko browsers one still sees the problem as texts are offset also a small amount.
I've no real solution at hand, except for never drawing a Raphael illustration on a still hidden paper if the app has to function correctly ;-) Perhaps someone else finds a solution for this...
The text was updated successfully, but these errors were encountered: