<?xml version='1.0' encoding='utf-8' ?>

<rss version='2.0' xmlns:lj='http://www.livejournal.org/rss/lj/1.0/' xmlns:atom10='http://www.w3.org/2005/Atom'>
<channel>
  <title>Tang&apos;s DW</title>
  <link>https://tangaroa.dreamwidth.org/</link>
  <description>Tang&apos;s DW - Dreamwidth Studios</description>
  <lastBuildDate>Mon, 08 Oct 2012 02:13:22 GMT</lastBuildDate>
  <generator>LiveJournal / Dreamwidth Studios</generator>
  <lj:journal>tangaroa</lj:journal>
  <lj:journaltype>personal</lj:journaltype>
<item>
  <guid isPermaLink='true'>https://tangaroa.dreamwidth.org/20768.html</guid>
  <pubDate>Mon, 08 Oct 2012 02:13:22 GMT</pubDate>
  <title>Notes on dragging and dropping in Javascript</title>
  <link>https://tangaroa.dreamwidth.org/20768.html</link>
  <description>&lt;p&gt;One of my side projects is a Javascript drag-and-drop list using the
&lt;a href=&quot;http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html&quot;&gt;modern drag and drop specification&lt;/a&gt; with the goal of allowing users to
rearrange the order of items in a list. I quickly ran into a problem: the
drag-and-drop spec was designed for dragging one object onto another single
discrete object which is expecting a drag event. This does not translate well
to a draggable list&apos;s use cases of dragging above, below, and between objects
(or subobjects), or of dragging an item off of the drag area to bring it to the
top or bottom of the list. To do anything fancy, we need to find a relationship
between the coordinates of the MouseEvent parent of a drag event, and the
coordinates of the elements on the screen.

&lt;p&gt;Visual elements have these coordinate attributes:

&lt;ul&gt;
&lt;li&gt;offsetTop
&lt;li&gt;scrollTop
&lt;/li&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Drag events have these coordinate attributes:

&lt;ul&gt;
&lt;li&gt;clientY
&lt;li&gt;pageY
&lt;li&gt;screenY
&lt;/li&gt;&lt;/li&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;There is no correlation between the two sets of coordinates.
I tried summing the offsetTop of an item and its ancestors but found
no correlation between that sum and any of the mouse coordinates. I also
had no luck using the various page and scroll properties for window and
document. Since I couldn&apos;t find the answer, I changed the question.
Element.clientHeight reliably works across browsers, so 
we can do this:

&lt;ol&gt;
&lt;li&gt;Save the initial drag event at the start of a drag.
&lt;li&gt;Calculate the difference between the start and end events.
&lt;li&gt;Count the heights of the elements to see where to place the dragged item.
&lt;li&gt;If we run out of elements, place the dragged item at the head or tail of the list. 
&lt;/li&gt;&lt;/li&gt;&lt;/li&gt;&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;This should work. The MouseEvent gives us three sets of coordinates, so
we should be able to pick one and it should work.

&lt;p&gt;Hah. 

&lt;p&gt;Among the problems: 

&lt;ul&gt;
&lt;li&gt;In Firefox, the clientY of the starting DragEvent is zero. 
&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=505521&quot;&gt;This is bug
#505521&lt;/a&gt; which has been open since 2009.
&lt;li&gt;In Safari 5.1.7, the clientY of the starting DragEvent is measured from top of
window while the clientY of the ending DragEvent is measured from the bottom of the
window.
&lt;li&gt;In Safari, the pageY of the ending DragEvent is some ridiculous number that
seems to be measured from some point over 500px off the bottom of the screen. 
&lt;li&gt;In both Firefox and Safari, the differences in clientY, pageY, and screenY
are different for the same beginning and ending mouse position.
&lt;li&gt;In Opera, the Y values for MouseEvents ending on the sidebar panel are different
from the Y values for MouseEvents  on a page at the same vertical level.
&lt;/li&gt;&lt;/li&gt;&lt;/li&gt;&lt;/li&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;I decided to use the difference in screenY, even though there is the obvious
bug that the math will be wrong if the screen scrolls in the middle of a drag,
because it produces the least number of compatibility problems across browsers.&lt;/p&gt;


&lt;hr /&gt;

&lt;p&gt;Side note: The best practice for defining class methods in Javascript 
is to use the prototype:

&lt;blockquote&gt;ClassName.prototype.method = function(){...}&lt;/blockquote&gt;

&lt;p&gt;This allows every instance of the class to use the same function
instead of giving each instance its own copy of the function. 

&lt;p&gt;Member variables are not in scope in prototype methods; the method is
expected to use &lt;tt&gt;this&lt;/tt&gt; to access them. In the context of an event
handler, however, &lt;tt&gt;this&lt;/tt&gt; is &lt;em&gt;not&lt;/em&gt; the containing object. 
Therefore, using prototyped methods as event handlers is not a good idea.
A solution is to use the old-fashioned &quot;this.method=&quot; declaration which
suffers inefficiency but does the job:

&lt;blockquote&gt;
function ClassName { &lt;br&gt;
	this.method = function(){...}
&lt;/blockquote&gt;

&lt;p&gt;I ran into this problem when I tried to fix my old-style drag-and-drop
code to use the best practice instead. 

&lt;p&gt;Recommended reading: &lt;a href=&quot;http://www.crockford.com/javascript/private.html&quot;&gt;Douglas Crockford&apos;s
tutorial: Private Members in Javascript&lt;/a&gt;.&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;https://www.dreamwidth.org/tools/commentcount?user=tangaroa&amp;ditemid=20768&quot; width=&quot;30&quot; height=&quot;12&quot; alt=&quot;comment count unavailable&quot; style=&quot;vertical-align: middle;&quot;/&gt; comments</description>
  <comments>https://tangaroa.dreamwidth.org/20768.html</comments>
  <category>programming</category>
  <category>computers</category>
  <category>javascript</category>
  <category>webdev</category>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>https://tangaroa.dreamwidth.org/17747.html</guid>
  <pubDate>Thu, 30 Aug 2012 21:21:55 GMT</pubDate>
  <title>If only all of my projects were this close to completion</title>
  <link>https://tangaroa.dreamwidth.org/17747.html</link>
  <description>&lt;p&gt;I finally got my Javascript implementation of &lt;a href=&quot;http://www.red3d.com/cwr/boids/&quot;&gt;Craig Reynolds&apos;s boids algorithm&lt;/a&gt; to work. Here is the relevant code:

&lt;blockquote&gt;&lt;pre&gt;
var weights= new Array(1.0, 1.0, 1.0);

sepvect = sepvect.multiply(weights[0]);
alivect = alivect.multiply(weights[1]);
cohvect = cohvect.multiply(weights[2]);

&lt;/pre&gt;&lt;/blockquote&gt;


&lt;p&gt;I just needed to record magnitudes for one run and fiddle with the weights. (0.5,1.0,0.2) seemed to do the trick, though I should test with different numbers of boids to see if the magnitudes are relative to that variable.

&lt;p&gt;As regards &quot;finally&quot;, I started on this so long ago that I forget when and have intermittently picked it up and re-abandoned it since then. The oldest timestamp that I can find for it is 2006, but I think it goes back to 2003 or 2004 when it was going to be something that I would put together during spring break. The biggest problem was a trig error that I fixed last month after having &lt;em&gt;almost&lt;/em&gt; fixed it earlier, causing directions to be wrong in one or two of the four quadrants.&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;https://www.dreamwidth.org/tools/commentcount?user=tangaroa&amp;ditemid=17747&quot; width=&quot;30&quot; height=&quot;12&quot; alt=&quot;comment count unavailable&quot; style=&quot;vertical-align: middle;&quot;/&gt; comments</description>
  <comments>https://tangaroa.dreamwidth.org/17747.html</comments>
  <category>algorithms</category>
  <category>javascript</category>
  <category>computers</category>
  <category>programming</category>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
</channel>
</rss>
