Skip to content

Instantly share code, notes, and snippets.

@abernier
Created July 28, 2012 15:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save abernier/3193698 to your computer and use it in GitHub Desktop.
Save abernier/3193698 to your computer and use it in GitHub Desktop.
$.inside

$.fn

Synopsis

$el.inside( <ancestor> [, <includeMargin>] )

Arguments

<ancestor>: The ancestor to compare $el with

    'selector' | jQuery | node

<includeMargin>: Whether to take margins into account

Returns

{
    left: <left>
    top: <top>
}

<left|top>: Position of $el to <ancestor>

    +-----+                   +-----+
    | 0/0 |                   | 1/0 | 
    +-----+                   +-----+
           +-----------------+
           |     +-----+     |
           |     |.5/.5|     |
           |     +-----+     |
           +-----------------+
    +-----+                   +-----+
    | 0/1 |                   | 1/1 |
    +-----+                   +-----+

Example

Determine if an element is in the viewport — and how far:

$('#foo').inside('html');

$.event.special

Synopsis

$(el).bind('inside', {ancestor: 'html'}, function (e, inside) {
  // inside.left
  // inside.top
});
body {margin:auto;}
html, body {height:100%;}
html {display:table;width:100%; overflow:hidden;}
body {display:table-cell; vertical-align:middle; text-align:center;}
#foo,
#bar {
background:rgba(255,255,255,.5);
display:inline-block; width:5em; height:3.75em;
border:.25em solid rgba(0,0,0,.5);
}
#bar {
width:8.75em; height:5em;
font-size:215%;
}
#bar:hover {cursor:move;}
#bar.overlap {background-color:rgba(255,249,0,.25);}
#bar .ui-resizable-handle {width:.5em; height:.5em; position:absolute; right:0; bottom:0; background:rgba(0,0,0,.5); cursor:nwse-resize;}
#bar {min-width:.5em; min-height:.5em;}
.value {font-family:georgia; font-size:500%; position:fixed;width:100%;margin-left:-50%; top:0;left:50%; text-align:center; margin-top:.5em;}
meter {position:fixed; width:100%;}
meter.horizontal {left:0; bottom:0;}
meter.vertical {
left:0; bottom:0;
-webkit-transform:rotate(-90deg);-webkit-transform-origin:left top;
}
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title>$.inside</title>
<link rel="stylesheet" href="index.css">
<script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.21/jquery-ui.min.js"></script>
<script src="jquery.inside.js"></script>
<script src="index.js"></script>
</head>
<body>
<meter class="horizontal" min="0" max="100" value="100"></meter>
<meter class="vertical" min="0" max="100" value="100"></meter>
<span class="value"></span>
<div id="foo">
<div id="bar" style="position:relative; left:-43px;top:-29px;"></div>
</div>
</body>
</html>
$(function () {
function handler(e, inside) {
var insideLeft = zeroOneZero(inside.left),
insideTop = zeroOneZero(inside.top);
$('.value').text(inside.left.toFixed(1) + " / " + inside.top.toFixed(1));
$(this).toggleClass('overlap', insideLeft>=0 && insideLeft<=1 && insideTop>=0 && insideTop<=1);
$('meter.horizontal').val(100 * insideLeft);
$('meter.vertical').val(100 * insideTop);
}
$('#bar')
.draggable()
.resizable()
.bind('inside', {
ancestor: '#foo',
frequency: 1000 / 15
}, handler);
(function resize() {
$('meter.vertical').width($(window).height());
}());
$(window).resize(resize);
// Helper
function zeroOneZero(zeroToOne) {
return -1 * Math.abs((zeroToOne - .5) * 2) + 1;
}
});
(function ($) {
"use strict";
//
// $.fn.offsetRelative dependency (https://gist.github.com/3191472)
//
$.fn.offsetRelative = $.fn.offsetRelative || function (selector) {
selector || (selector = '*');
var elOffset = this.offset(),
parentOffset = this.parent().closest(selector).offset();
return {
left: elOffset.left - parentOffset.left,
top: elOffset.top - parentOffset.top
};
};
//
// Inside plugin
//
$.fn.inside = $.fn.inside || function (container, includeMargin) {
includeMargin || (includeMargin = false);
var $el = this.eq(0),
$container = $(container);
if (!$.contains($container.get(0), $el.get(0))) {
return;
}
var o = $el.offsetRelative($container),
w = $container.outerWidth(includeMargin),
h = $container.outerHeight(includeMargin),
W = $el.outerWidth(includeMargin),
H = $el.outerHeight(includeMargin);
return {
left: (o.left + W) / (w + W),
top: (o.top + H) / (h + H)
};
};
//
// 'inside' special event
//
$.event.special.inside = $.event.special.inside || (function () {
var registry = {};
// Main handler
function handler(key) {
$(this).trigger('inside', $(this).inside(registry[key].handleObj.data.ancestor));
}
return {
add: function (handleObj) {
var frequency = handleObj.data.frequency || 200,
key = handleObj.guid;
// Interval
var interval = setInterval($.proxy(function () {
return handler.apply(this, [key]);
}, this), frequency);
// Store to the registry
registry[key] = {
handleObj: handleObj,
interval: interval
};
},
remove: function (handleObj) {
var key = handleObj.guid;
// Clear from the registry
clearInterval(registry[key].interval);
delete registry[key];
}
};
}());
}(jQuery));
@abernier
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment