Closed
Bug 1217344
Opened 9 years ago
Closed 2 years ago
SVG and jQuery .draggable()
Categories
(Core :: SVG, defect)
Core
SVG
Tracking
()
RESOLVED
INCOMPLETE
Tracking | Status | |
---|---|---|
platform-rel | --- | + |
People
(Reporter: contact, Unassigned)
Details
(Whiteboard: [platform-rel-jQuery])
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/601.2.4 (KHTML, like Gecko) Version/9.0.1 Safari/601.2.4 Steps to reproduce: We’ve created some SVG paths, with cursors on it, and use jQuery .draggable() to move it. We’re using AngularJS for the front end, and all the JS is in the controller of the page. Actual results: When we start to drag one of the cursors, it moves randomly, and do not follow the path. Works well on others explorers. jQuery : v1.11.4, AngularJS : v1.4, Firefox v41.0.2 on MacOS, same problem on Windows. See the bug here : http://d.pr/i/HbHM Expected results: The cursor should follow the path, like that : http://d.pr/i/15lS3 (on Safari, Chrome, Opera)
Comment 1•9 years ago
|
||
We're going to need a minimal testcase rather than a screenshot. I imagine you're using getCTM, getScreenCTM or getTransformToElement incorrectly though.
Flags: needinfo?(contact)
Thank you for your feedback. We don't use fonctions getCTM, getScreenCTM or getTransformToElement. Please find the code below : ### CLASSES ### class Curve constructor: (data = {}, xml = false) -> this.init() if !_.isEmpty(data) @canvasId = data.curve_id+"SVG" if data.curve_id @curveId = data.curve_id if data.curve_id @curveOId = data.curve_id+"O" if data.curve_id @curveBId = data.curve_id+"B" if data.curve_id @curveData = data.curve_data if data.curve_data @cursorAImg = data.cursor_a_img if data.cursor_a_img @cursorBImg = data.cursor_b_img if data.cursor_b_img #TODO: make dynamic size # @width = @canvas.attr().width # @height = @canvas.attr().height @width = 425 @height = 290 @curveOMask = new CurveMask(this, {mask_id: data.curve_id+"OMask"}) @curveBMask = new CurveMask(this, {mask_id: data.curve_id+"BMask"}) @cursorA = new CurveCursor(this, cursor_id: data.curve_id+"CursorA" curve_id: @curveId if @cursorAImg cursor_img: @cursorAImg ) @cursorA.setValue(50) @cursorB = new CurveCursor(this, cursor_id: data.curve_id+"CursorB" curve_id: @curveId if @cursorBImg cursor_img: @cursorBImg ) @cursorB.setValue(150) Curve.curveYAtX = (curve, x) -> #in case we just want to pass the curve DOM ID instead of the whole curve object (must not contain a # (hash)) if (typeof curve == "string") DomId = curve curve = {} curve.curveId = DomId.replace("#","") if(curve == undefined) console.error "Curve#constraint: curve is undefined" return if(x == undefined) console.error "Curve#constraint: x is undefined" return pathLength = document.getElementById(curve.curveId).getTotalLength() beginning = 0 end = pathLength target = undefined while(true) target = Math.floor((beginning + end) / 2); pos = document.getElementById(curve.curveId).getPointAtLength(target) if ((target == end || target == beginning) && pos.x != x) break if (pos.x > x) end = target else if (pos.x < x) beginning = target else break return pos.y class CurveCursor constructor: (parent, data = {}) -> this.init() if !_.isEmpty(data) @value = data.value if data.value @label = data.label if data.label @color = data.color if data.color @min = data.min if data.min @max = data.max if data.max @cursorId = data.cursor_id if data.cursor_id @curveId = data.curve_id if data.curve_id @cursorColor = data.cursor_color if data.cursor_color @cursorImg = data.cursor_img if data.cursor_img if(data.cursor_size) @height = data.cursor_size @width = data.cursor_size #TODO: make max dynamic @max = 425 if !data.max init: () -> @value = 0 @min = 0 @max = 100 @height = 20 @width = 15 @x = 0 @y = 0 @parent = undefined @cursorId = undefined @curveId = undefined @rect = undefined @cursorColor = "#99CE1F" @cursorImg = undefined setValue: (v) -> @value = v @x = @value setMax: (v) -> @max = v xIsBetween: (x1, x2)-> return (@x >= x1 && @x < x2) constraint: (curve) -> if(@x - @width/2 < @min) @x = @min+ @width/2 if(@x + @width/2 > @max) @x = @max - @width/2 @y = Curve.curveYAtX(curve, @x) ### VIEWS #### #Curve <div class="minicurve-container" > <div id="{{curve.curveId}}Container" class="svg-container"> <div class="label-div" > <span id="curve-label" class="curve-label"> {{curve.curveLabel | translate}} </span> </div> <svg height="310" width="425" x="0px" y="0px" id="{{curve.curveId}}SVG"> <defs> <mask id="{{curve.curveBMask.maskId}}"> <curve-mask curve="curve" standalone="false" maskobj="curve.curveBMask"></curve-mask> </mask> <mask id="{{curve.curveOMask.maskId}}"> <curve-mask curve="curve" standalone="true" maskobj="curve.curveOMask"></curve-mask> </mask> <marker id="markerArrow" markerWidth="5" markerHeight="5" refX="0" refY="2.5" orient="auto" markerUnits="strokeWidth"> <path d="m0.03774,0.03774 l4.9434,2.37736 l-4.90566,2.49057 l-0.03774,-4.86792 z" style="fill: #000000;" /> </marker> </defs> <!-- MAIN CURVE --> <path id="{{curve.curveId}}" fill="none" stroke="#9B9B9B" stroke-width="1" d="{{curve.curveData}}"/> <!-- SECONDARY BLACK CURVE --> <path id="{{curve.curveId}}B" stroke-width="2" fill="none" stroke="#000" d="{{curve.curveData}}" mask="url(#{{curve.curveBMask.maskId}})"/> <!-- SECONDARY ORANGE CURVE --> <path id="{{curve.curveId}}O" stroke-width="3" fill="none" stroke="#FEAD00" d="{{curve.curveData}}" mask="url(#{{curve.curveOMask.maskId}})"/> <g fill="none" stroke="black" stroke-width="2" > <line ng-if="curve.curveId == 'profitsCurve'" x1="4" y1="145" x2="415" y2="145" style="marker-end: url(#markerArrow);"></line> <line ng-if="curve.curveId != 'profitsCurve'" x1="4" y1="290" x2="415" y2="290" style="marker-end: url(#markerArrow);"></line> <line x1="4" y1="290" x2="4" y2="10" style="marker-end: url(#markerArrow);"></line> </g> <!-- CURSORS --> <curve-cursor curve="curve" cursor="curve.cursorA"></curve-cursor> <curve-cursor curve="curve" cursor="curve.cursorB"></curve-cursor> </svg> </div> </div> #Cursor <g id="{{cursor.cursorId}}"> <defs> <pattern id="{{cursor.cursorId}}img" width="25" height="25"> <image xlink:href="{{cursor.cursorImg}}" x="0" y="0" width="25" height="25" /> </pattern> </defs> <rect x="{{cursor.x-cursor.width/2}}" y="{{cursor.y-cursor.height/2}}" width="{{cursor.width}}" height="{{cursor.height}}" fill="{{cursor.cursorImg ? 'url(#' + cursor.cursorId + 'img)' : cursor.cursorColor}}" stroke="#000" stroke-width="1px" > </rect> </g> ### DIRECTIVES ### .directive('curveCursor', ["$timeout", function($timeout) { return { restrict: 'E', replace: true, transclude: true, templateNamespace: 'svg', scope: { curve: '=curve', cursor: '=cursor' }, templateUrl: 'views/system_maturity/_curve_cursor.html', link: function(scope, elem, attr){ $timeout(function(){ if(scope.curve.curveId == "MGCurve"){ scope.$parent.$emit("CursorReady", {cursor: scope.cursor, curve: scope.curve}) }else{ scope.$parent.$parent.$emit("CursorReady", {cursor: scope.cursor, curve: scope.curve}) } }) } }; }]); .directive('miniGraph', ["$timeout", function($timeout) { return { restrict: 'E', replace: true, transclude: true, templateUrl: "views/system_maturity/_mini_graph.html" }; }]); ### CONTROLLER ### $scope.$on("CursorReady", (evt, data)-> cursor = data.cursor curve = data.curve domCurve = document.getElementById(cursor.curveId) cursor.max = domCurve.getBoundingClientRect().width + domCurve.getBBox().x cursor.min = domCurve.getBBox().x scope = $scope prevPoint = {x:0, y:0} cursor.constraint(cursor.curveId) $scope.updateOMasks(cursor, false) $scope.constraintPF(cursor) $('#'+cursor.cursorId).draggable start: (event, ui) -> event.stopPropagation() prevPoint = x: parseFloat(event.clientX) y: parseFloat(event.clientY) drag: (event, ui) -> cursor.x = (cursor.x + parseFloat(event.clientX) - prevPoint.x ) event.stopPropagation() prevPoint = x: parseFloat(event.clientX) y: parseFloat(event.clientY) cursor.constraint(cursor.curveId) scope.updateOMasks(cursor, true) scope.constraintPF(cursor) scope.$apply() )
Flags: needinfo?(contact)
Comment 3•9 years ago
|
||
Looks broadly OK, We need something we can run though, e.g. a jsfiddle
Check this out : http://plnkr.co/edit/BQEqTDVLIE95pQ3QzClv?p=preview
Updated•9 years ago
|
Component: Untriaged → Event Handling
Product: Firefox → Core
Comment 5•9 years ago
|
||
I tested on Windows 7 on Firefox 41.0.2 the bug can also be reproduce here. Steps to reproduce: 1 Enter on this link http://plnkr.co/edit/BQEqTDVLIE95pQ3QzClv?p=preview 2 Try to follow the path with the cursor. Actual results: The cursor doesn't follow the path. Expected results: The cursor should follow the path.
Status: UNCONFIRMED → NEW
Ever confirmed: true
Comment 7•9 years ago
|
||
Really needs a much much much smaller testcase in order to progress. Ideally without angular or jQuery.
the point is that we don't have any issues in other browsers ! only with Firefox. So it doesn't come from angular or jQuery. So could you please confirm us that problem comes from Firefox javascript's engine now ? Regards,
Comment 9•9 years ago
|
||
Not till you address comment 7. Without that I've no idea what the problem is.
Updated•8 years ago
|
Whiteboard: [platform-rel-jQuery]
Updated•8 years ago
|
platform-rel: --- → ?
Updated•8 years ago
|
Severity: blocker → normal
Flags: needinfo?(bugs)
Priority: P1 → --
Updated•8 years ago
|
Flags: needinfo?(bugs)
Comment 12•8 years ago
|
||
I might be able to check it on next Tuesday. Keep ni flag to remind me.
Updated•8 years ago
|
Rank: 25
Comment 13•8 years ago
|
||
The links provided in this bug are not working. Looks like there are something wrong of droplr. I'd re-try them later.
Comment 14•8 years ago
|
||
Clear ni flag since these links are no longer valid and I have no idea about how to reproduce the problem.
Flags: needinfo?(sshih)
Comment 15•8 years ago
|
||
I could still reproduce the issue with the link from comment 5.
Comment 16•8 years ago
|
||
Oh, I missed this one. This one is valid and I'll check it.
Comment 17•8 years ago
|
||
It hits the assertion in [1] when I try to reproduce the bug (dragging the green box). [1] http://searchfox.org/mozilla-central/source/layout/svg/nsSVGContainerFrame.cpp#391
Comment 19•7 years ago
|
||
We looked at this during partner triage today and aren't sure how badly it hurts users or what next step should be... Andrew (and Olli) any ideas? Do we think this is an events bug?
Flags: needinfo?(overholt)
Comment 20•7 years ago
|
||
It's almost certainly a bug in their code somewhere. Most probably some co-ordinate system transformation is invalid.
Comment 21•7 years ago
|
||
or in our code. Nothing particularly hints about events bug. Some coordinates are going wrong somewhere. Minimal testcase would be really nice.
Comment 22•7 years ago
|
||
(In reply to Olli Pettay [:smaug] from comment #21) > Some coordinates are going wrong somewhere. Minimal testcase would be really nice. Any chance for a smaller testcase?
Flags: needinfo?(overholt) → needinfo?(contact)
Comment 23•7 years ago
|
||
I tried that in comment 7, comment 8 and comment 9 without much response.
Comment 24•4 years ago
|
||
A minimal testcase would be really nice here.
The example in comment 5 is rather large.
Flags: needinfo?(bugs)
Updated•2 years ago
|
Severity: normal → S3
Comment 25•2 years ago
|
||
Clear a needinfo that is pending on an inactive user.
Inactive users most likely will not respond; if the missing information is essential and cannot be collected another way, the bug maybe should be closed as INCOMPLETE
.
For more information, please visit auto_nag documentation.
Flags: needinfo?(contact)
Updated•2 years ago
|
Status: NEW → RESOLVED
Closed: 2 years ago
Resolution: --- → INCOMPLETE
You need to log in
before you can comment on or make changes to this bug.
Description
•