Skip to content

Commit

Permalink
Extract module
Browse files Browse the repository at this point in the history
  • Loading branch information
gaearon committed Apr 9, 2015
1 parent b11f2cf commit 03dcdde
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 106 deletions.
113 changes: 7 additions & 106 deletions modules/backends/HTML5.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { DragSource } from 'dnd-core';
import NativeTypes from '../NativeTypes';
import EnterLeaveCounter from '../utils/EnterLeaveCounter';
import createMonotonicInterpolant from '../utils/createMonotonicInterpolant';
import shallowEqual from '../utils/shallowEqual';
import defaults from 'lodash/object/defaults';
import memoize from 'lodash/function/memoize';
import invariant from 'react/lib/invariant';
import warning from 'react/lib/warning';

const isSafari = memoize(() => Boolean(window.safari));
const isFirefox = memoize(() => /firefox/i.test(navigator.userAgent));

function isUrlDataTransfer(dataTransfer) {
var types = Array.prototype.slice.call(dataTransfer.types);
return types.indexOf('Url') > -1 || types.indexOf('text/uri-list') > -1;
Expand Down Expand Up @@ -40,110 +45,6 @@ function getMouseEventOffsets(e, sourceNode, dragPreview) {
return { offsetFromClient, offsetFromSource, offsetFromDragPreview };
}

function isDesktopSafari() {
return !!window.safari;
}

function isFirefox() {
return /firefox/i.test(navigator.userAgent);
}

/**
* I took this straight from Wikipedia, it must be good!
*/
function createMonotonicInterpolant(xs, ys) {
const length = xs.length;

// Rearrange xs and ys so that xs is sorted
const indexes = [];
for (let i = 0; i < length; i++) {
indexes.push(i);
}
indexes.sort((a, b) => xs[a] < xs[b] ? -1 : 1);

const oldXs = xs, oldYs = ys;
// Impl: Creating new arrays also prevents problems if the input arrays are mutated later
xs = [];
ys = [];
// Impl: Unary plus properly converts values to numbers
for (let i = 0; i < length; i++) {
xs.push(+oldXs[indexes[i]]);
ys.push(+oldYs[indexes[i]]);
}

// Get consecutive differences and slopes
const dys = [];
const dxs = [];
const ms = [];
let dx, dy;
for (let i = 0; i < length - 1; i++) {
dx = xs[i + 1] - xs[i];
dy = ys[i + 1] - ys[i];
dxs.push(dx);
dys.push(dy);
ms.push(dy / dx);
}

// Get degree-1 coefficients
const c1s = [ms[0]];
for (let i = 0; i < dxs.length - 1; i++) {
const m = ms[i];
const mNext = ms[i + 1];
if (m * mNext <= 0) {
c1s.push(0);
} else {
dx = dxs[i];
const dxNext = dxs[i + 1];
const common = dx + dxNext;
c1s.push(3 * common / ((common + dxNext) / m + (common + dx) / mNext));
}
}
c1s.push(ms[ms.length - 1]);

// Get degree-2 and degree-3 coefficients
const c2s = [];
const c3s = [];
let m;
for (let i = 0; i < c1s.length - 1; i++) {
m = ms[i];
const c1 = c1s[i];
const invDx = 1 / dxs[i];
const common = c1 + c1s[i + 1] - m - m;
c2s.push((m - c1 - common) * invDx);
c3s.push(common * invDx * invDx);
}

// Return interpolant function
return function (x) {
// The rightmost point in the dataset should give an exact result
let i = xs.length - 1;
if (x === xs[i]) {
return ys[i];
}

// Search for the interval x is in, returning the corresponding y if x is one of the original xs
let low = 0;
let high = c3s.length - 1;
let mid;
while (low <= high) {
mid = Math.floor(0.5 * (low + high));
const xHere = xs[mid];
if (xHere < x) {
low = mid + 1;
} else if (xHere > x) {
high = mid - 1;
} else {
return ys[mid];
}
}
i = Math.max(0, high);

// Interpolate
const diff = x - xs[i], diffSq = diff * diff;
return ys[i] + c1s[i] * diff + c2s[i] * diffSq + c3s[i] * diff * diffSq;
};
}

function getDragPreviewOffset(sourceNode, dragPreview, offsetFromDragPreview, anchorPoint) {
const { offsetWidth: sourceWidth, offsetHeight: sourceHeight } = sourceNode;
const { anchorX, anchorY } = anchorPoint;
Expand All @@ -153,7 +54,7 @@ function getDragPreviewOffset(sourceNode, dragPreview, offsetFromDragPreview, an
let dragPreviewHeight = isImage ? dragPreview.height : sourceHeight;

// Work around @2x coordinate discrepancies in browsers
if (isDesktopSafari() && isImage) {
if (isSafari() && isImage) {
dragPreviewHeight /= window.devicePixelRatio;
dragPreviewWidth /= window.devicePixelRatio;
} else if (isFirefox() && !isImage) {
Expand Down Expand Up @@ -183,7 +84,7 @@ function getDragPreviewOffset(sourceNode, dragPreview, offsetFromDragPreview, an
let y = interpolateY(anchorY);

// Work around Safari 8 positioning bug
if (isDesktopSafari() && isImage) {
if (isSafari() && isImage) {
// We'll have to wait for @3x to see if this is entirely correct
y += (window.devicePixelRatio - 1) * dragPreviewHeight;
}
Expand Down
95 changes: 95 additions & 0 deletions modules/utils/createMonotonicInterpolant.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* I took this straight from Wikipedia, it must be good!
*/
export default function createMonotonicInterpolant(xs, ys) {
const length = xs.length;

// Rearrange xs and ys so that xs is sorted
const indexes = [];
for (let i = 0; i < length; i++) {
indexes.push(i);
}
indexes.sort((a, b) => xs[a] < xs[b] ? -1 : 1);

const oldXs = xs, oldYs = ys;
// Impl: Creating new arrays also prevents problems if the input arrays are mutated later
xs = [];
ys = [];
// Impl: Unary plus properly converts values to numbers
for (let i = 0; i < length; i++) {
xs.push(+oldXs[indexes[i]]);
ys.push(+oldYs[indexes[i]]);
}

// Get consecutive differences and slopes
const dys = [];
const dxs = [];
const ms = [];
let dx, dy;
for (let i = 0; i < length - 1; i++) {
dx = xs[i + 1] - xs[i];
dy = ys[i + 1] - ys[i];
dxs.push(dx);
dys.push(dy);
ms.push(dy / dx);
}

// Get degree-1 coefficients
const c1s = [ms[0]];
for (let i = 0; i < dxs.length - 1; i++) {
const m = ms[i];
const mNext = ms[i + 1];
if (m * mNext <= 0) {
c1s.push(0);
} else {
dx = dxs[i];
const dxNext = dxs[i + 1];
const common = dx + dxNext;
c1s.push(3 * common / ((common + dxNext) / m + (common + dx) / mNext));
}
}
c1s.push(ms[ms.length - 1]);

// Get degree-2 and degree-3 coefficients
const c2s = [];
const c3s = [];
let m;
for (let i = 0; i < c1s.length - 1; i++) {
m = ms[i];
const c1 = c1s[i];
const invDx = 1 / dxs[i];
const common = c1 + c1s[i + 1] - m - m;
c2s.push((m - c1 - common) * invDx);
c3s.push(common * invDx * invDx);
}

// Return interpolant function
return function (x) {
// The rightmost point in the dataset should give an exact result
let i = xs.length - 1;
if (x === xs[i]) {
return ys[i];
}

// Search for the interval x is in, returning the corresponding y if x is one of the original xs
let low = 0;
let high = c3s.length - 1;
let mid;
while (low <= high) {
mid = Math.floor(0.5 * (low + high));
const xHere = xs[mid];
if (xHere < x) {
low = mid + 1;
} else if (xHere > x) {
high = mid - 1;
} else {
return ys[mid];
}
}
i = Math.max(0, high);

// Interpolate
const diff = x - xs[i], diffSq = diff * diff;
return ys[i] + c1s[i] * diff + c2s[i] * diffSq + c3s[i] * diff * diffSq;
};
}

0 comments on commit 03dcdde

Please sign in to comment.