How does .#2x work [duplicate] - iphone

This question already has answers here:
Serving high res images to retina display
(3 answers)
Closed 9 years ago.
I am new at formatting my code to fit the iphone (especially 4 and 5). Do you add two images to the css (with no media query)? Or do you need a media query with that background image?

basically yes, you need to do the following:
.repeatingPattern {
background: url(../images/bgPattern.png) repeat;
background-size: 100px 100px;
}
#media only screen and (-webkit-min-device-pixel-ratio: 2) {
.repeatingPattern {
background: url(../images/bgPattern#2x.png) repeat;
}
}
but if you are using jquery it will be more efficient to do that like this:
<img class="hires" alt="" src="search.png" width="100" height="100" />
<script type="text/javascript">
$(function () {
if (window.devicePixelRatio == 2) {
var images = $("img.hires");
// loop through the images and make them hi-res
for(var i = 0; i < images.length; i++) {
// create new image name
var imageType = images[i].src.substr(-4);
var imageName = images[i].src.substr(0, images[i].src.length - 4);
imageName += "#2x" + imageType;
//rename image
images[i].src = imageName;
}
}
});
</script>

Related

how to resize image and reorient it if it rotates when uploaded through IOS devices using image intervention package?

I have developed a Laravel web application with the help of some tutorial videos and codes given by other developers on stackoverflow .The app is working pretty good except for the image upload feature. I am facing an issue related to the uploaded image being cut either on the sides or on the bottom as well as the image when uploaded through any IOS device then the image under goes rotation. I have installed image intervention but i don't know where to put the code inside my files i am sharing my controller code as well as the image displaying code here
controller code
namespace App\Http\Controllers;
use Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\MessageBag;
use App\comment;
use App\User;
use App\post;
use View;
use Lang;
use image;
class usersController extends Controller
{
private $u;
public function __construct(){
$this->u = new User();
}
public function search(Request $request){
$search_input = $request["input"];
$path = $request["path"];
$users = User::where("name","like","%$search_input%")->orWhere("username","like","%$search_input%")->get();
if ($users->isEmpty()) {
return "<p style='text-align: center;width: 100%;color: gray;font-size: 12px;margin: 3px'>".Lang::get('trans.nothingToShow')."</p>";
}else{
foreach ($users as $user) {
if ($user->verify == 1) {
$ifVerify = '<span class="verify-badge" style="width: 420px; height: 700px; background: url(\''.$path.'/imgs/verify.png\') no-repeat; background-size: cover; margin: 0px 2px;"></span>';
}else{
$ifVerify = '';
}
if($user->avatar == "avatar.png"){
$avatar_path = '/imgs/avatar.png';
}else{
$avatar_path = '/storage/avatar/'.$user->avatar;
}
echo '<div class="navbar-search-item">
<a href="'.$path.'/'.$user->username.'">
<div>
<div style="background-image:url(\''.$path.$avatar_path.'\');">
</div>
<p>
'.$user->name.$ifVerify.'<br>
<span>#'.$user->username.'</span>
</p>
</div>
</a>
</div>';
}
}
}
public function profile($username){
$user_info = User::where("username",$username)->get();
foreach ($user_info as $uinfo) {
$user_id = $uinfo->uid;
}
if (isset($user_id)) {
$feedbacks = post::where("to_id",$user_id)->where("privacy",1)->orderBy('time', 'desc')->get();
$feedbacks_count = post::where("to_id",$user_id)->get()->count();
$new_count = post::where("to_id",$user_id)->where('read',0)->get()->count();
// check comments on post (count)
$commentsCount = array();
foreach ($feedbacks as $fb) {
$pid = $fb->pid;
$countComments = comment::where("c_pid",$pid)->get()->count();
array_push($commentsCount,$countComments);
}
return view("pages.profile")->with(["user_info" => $user_info,"feedbacks" => $feedbacks,'feedbacks_count' => $feedbacks_count,'new_count' => $new_count,'commentsCount' => $commentsCount]);
}else{
return view("pages.profile")->with(["user_info" => $user_info]);
}
}
public function settings($username){
$user_info = User::where("username",$username)->get();
if (Auth::user()->username == $username) {
return view("pages.settings")->with("user_info",$user_info);
}else{
return redirect()->back();
}
}
public function s_general(Request $request){
$this->validate($request,[
'avatar' => 'nullable|image|mimes:jpeg,png,jpg|max:3072',
'fullname' => 'required',
'email' => 'required|email'
]);
if ($request['fullname'] == Auth::user()->name && $request['email'] == Auth::user()->email && !$request->hasFile('avatar')) {
return redirect()->back()->with('general_msg', Lang::get('trans.noChanges_MSG'));
}else{
$avatar = $request->file('avatar');
if ($request->hasFile('avatar')) {
$avatar_ext = $avatar->getClientOriginalExtension();
$avatar_name = rand(9,999999999)+time().".".$avatar_ext;
$avatar_new = $avatar->storeAs("avatar",$avatar_name);
}else{
$avatar_name = Auth::user()->avatar;
}
$update_general = User::where('uid',Auth::user()->uid)->update(['name' => $request['fullname'],'email' => $request['email'],'avatar' => $avatar_name]);
return redirect()->back()->with('general_msg', Lang::get('trans.changes_saved'));
}
}
and this is how i display the image
<div class="profile-avatar" style="width: 300px;height:400px; border-radius: 0%;background-image: url('#if(Auth::user()->avatar == "avatar.png") {{ url("/imgs/".Auth::user()->avatar) }} #else {{ url("/storage/avatar/".Auth::user()->avatar) }} #endif');">
please help me with code should i put and where i should put that in order to resolve this issue
this code is for preview of the image
<div style="display: inline-flex;">
<div class="profile-avatar" id="settings_img_elm" style="margin: 10px; width:350px;margin-top: 0; margin-bottom: 0;border-color: #fff; text-align: center;background-image: url('#if(Auth::user()->avatar == "avatar.png") {{ url("/imgs/".Auth::user()->avatar) }} #else {{ url("/storage/avatar/".Auth::user()->avatar) }} #endif');">
</div>
<p style="color: #a7aab5; font-size: 9px;padding: 25px 10px 25px 10px; margin: 0;">#lang("trans.preview")<br>#lang("trans.maxSize")<br>upload vertical <br>images.<br>Save the<br>image first<br> and then<br> check the<br> preview</p>
</div>
<p style="border-bottom: 1px solid #dfe2e6;margin: 0; margin-top: 12px; margin-bottom: 12px;">
<input type="file" name="avatar" style="display: none;" id="settings_img">
<label for="settings_img" class="btn btn-success">#lang("trans.selectImage")</label>
the javascript for the preview image is
function imagePreview(input,elm) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$(elm).css("background-image","url('"+e.target.result+"')");
}
reader.readAsDataURL(input.files[0]);
}
}
$("#settings_img").on("change",function(){
imagePreview(this,"#settings_img_elm");
});
$("#feedback_hFile").on("change",function(){
$(".send_feedback_image").show();
imagePreview(this,"#sfb_image_preview");
});
The code below should get you started. The two key things you are looking for here are Interventions orientate and resize methods which should take care of the two issues you mention. Orientation will rotate the image based on EXIF data, and resize can resize your image to whatever specifications you need.
Import the facade
use Intervention\Image\Facades\Image;
Suggestions
Remove use image; from your imports as it is probably causing or going to cause you issues. It is invalid.
s_general method adjustments
public function s_general(Request $request){
$this->validate($request,[
'avatar' => 'nullable|image|mimes:jpeg,png,jpg|max:3072',
'fullname' => 'required',
'email' => 'required|email'
]);
if ($request['fullname'] === Auth::user()->name && $request['email'] === Auth::user()->email && !$request->hasFile('avatar')) {
return redirect()->back()->with('general_msg', Lang::get('trans.noChanges_MSG'));
}
if ($request->hasFile('avatar')) {
// Grab the original image from the request
$originalImage = $request->file('avatar');
// Grab the original image extension
$originalExtension = $originalImage->getClientOriginalExtension();
// Instantiate a new Intervention Image using our original image,
// read the EXIF 'Orientation' data of the image and rotate the image if needed
$newImage = Image::make($originalImage)->orientate();
// Resize the new image to a width of 300 and a height of null (auto)
// we also use a callback to constrain the aspect ratio so we don't distort the image on resize
$newImage->resize(300, null, function ($constraint) {
$constraint->aspectRatio();
});
// Generate a randomized filename and append the original image extension
$filename = random_int(9, 999999999) + time() . '.' . $originalExtension;
// Save the new image to disk
$newImage->save(storage_path('app/public/avatar/' . $filename));
} else {
$filename = Auth::user()->avatar;
}
User::where('uid', Auth::user()->uid)->update(
[
'name' => $request['fullname'],
'email' => $request['email'],
'avatar' => $filename
]);
return redirect()->back()->with('general_msg', Lang::get('trans.changes_saved'));
}
More suggestions
I know this isn't a code review, but
Use PascalCase for your class names. I see you have a few imports such as App\comment and App\post
Your constructor doesn't seem to be needed. I'd ditch it. If you are keeping it, i would get use to more descriptive variable names. Short names like $u are generally considered bad practice.
You have a few unused imports, Validator, Hash and MessageBag could be removed to clean this up.
Your controller is doing a lot of stuff that most would consider bad practice. Fumbling around with html for example. 9.9 times out of 10 you should probably be leveraging blade for these things as it's one of its main purposes.
Stick to one naming convention or another. You are using a mixture of camelCase and snake_case for your variables. I prefer camelCase but whichever you choose it's best to stick with it and not mix them.
Sorry, i know this isn't suppose to be a code review, i just thought that a few little suggestions might help you in the future.
You can check Intervation docs on how to resize image, I've also created an example for you for s_general function:
$avatar = $request->file('avatar');
if ($request->hasFile('avatar')) {
//pass uploaded avatar to Intervention Image instance
$image = \Image::make($avatar);
//resize image to 300 width, keep height automated adjusted, or any other width you need
$image->resize(300, null, function ($constraint) {
$constraint->aspectRatio();
});
//Or you can set specific width and height
//$image->resize(300, 200);
$avatar_ext = $avatar->getClientOriginalExtension();
$avatar_name = rand(9,999999999) + time().".".$avatar_ext;
//I used public path to store the image you can change it based on your needs
$image->save(public_path('/avatar/'.$avatar_name));
}else{
$avatar_name = Auth::user()->avatar;
}
use image intervention for resizing and for correcting the orientation of the image uploaded from a mobile phone. IF you are showing the preview of this image using simple javascript something like
reader.onload = function (e) {
$(elm).css("background-image","url('"+e.target.result+"')");
then there is a chance that the preview of the image won't be oriented as we want but once you save the image the orientation will be proper.
this problem of orientation is encountered mostly on iphone.
The code for orientation correction and resizing is
$newImage = Image::make($originalImage)->orientate();
$newImage->resize(300, null, function ($constraint) {
$constraint->aspectRatio();
});
///or for resizing use
$newImage->resize(width,height);

Why does my canvas not always display the drawn image?

In my ionic app, I am trying to scale a photo and draw it onto a canvas. Here's my code:
HTML:
<ion-header>
<ion-toolbar>
<ion-icon name="camera" slot="start" style="padding-left: 8px; font-size: x-large"></ion-icon>
<ion-title>Photo</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<canvas id="mainCanvas" #mainCanvas style="display: block; padding-top: 20px; margin: 10px auto; height: 90%;"></canvas>
</ion-content>
<ion-footer>
<ion-item lines="none">
<ion-tabs tabsPlacement="bottom">
<ion-tab-bar slot="bottom">
<ion-tab-button size="small" (click)="openCamera()">
<ion-icon name="camera"></ion-icon>
<ion-label>Add Photo</ion-label>
</ion-tab-button>
</ion-tab-bar>
</ion-tabs>
</ion-item>
</ion-footer>
.ts:
private updateCanvas() {
const img = new Image();
const ctx = this._CONTEXT;
const canvas = this._CANVAS;
// set final size of image to be displayed (half the size of the screen, to allow for other controls to be shown)
const displayWidth = this.plt.width() / 1.60;
const displayHeight = this.plt.height() / 1.60;
canvas.width = displayWidth;
canvas.height = displayHeight;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#ff0000";
if (this.photo == null) {
console.log("updateCanvas: photo object is null");
return;
}
// Create an offscreen buffer to draw the full-sized photo onto
const bufferCanvas = document.createElement('canvas');
const bufferCtx = bufferCanvas.getContext('2d');
const path = this.file.dataDirectory + this.photo.id + "." + this.photo.file_extension;
img.onload = (() => {
console.log("updateCanvas > img.onload > photo: ", this.photo);
// Scale the buffer canvas to match original size of photo
bufferCanvas.width = img.width;
bufferCanvas.height = img.height;
if (bufferCtx && ctx) {
// Draw photo to buffer canvas
console.log("updateCanvas > drawing onto buffer...");
bufferCtx.drawImage(img, 0, 0);
// Get the photo and main canvas aspect ratios
const imgAspect = img.height / img.width;
const mainAspect = canvas.height / canvas.width;
// Should the image fill the canvas width, or height?
const fillWidth = true; // imgAspect > mainAspect;
// Determine the new scale of the image so that it covers the main canvas
// This would need adjusting if we wanted it contained within the main canvas (no overhang)
const scaledWidth = fillWidth ? displayWidth : displayHeight / imgAspect;
const scaledHeight = fillWidth ? displayWidth * imgAspect : displayHeight;
// Translate to the center of the main canvas
ctx.translate(displayWidth / 2, displayHeight / 2);
// Draw the buffer to the main canvas
// Take off half the scaled dimensions so that it doesn't draw in the bottom right corner
ctx.drawImage(bufferCanvas, -scaledWidth / 2, -scaledHeight / 2, scaledWidth, scaledHeight);
}
});
console.log("updateCanvas > path: ", path);
img.src = (<any>window).Ionic.WebView.convertFileSrc(path);
}
However, my updateCanvas method only seems to work randomly when called. It's completely random, sometimes it will draw after two calls, sometimes only after 7 calls. Can anyone spot what might be preventing the canvas from being drawn? I have verified that the photo file exists in the folder specified by the path variable. If I draw to the canvas without scaling, the image is drawn to the canvas without problems.
edit1: noticed something weird - when I display an alert before updating the canvas, the canvas shows the correctly scaled photo. E.g.
this.presentAlert("test", "test")
.then(() => this.updateCanvas());

D3 filtering data points

I'm implementing the classic mercator example (https://github.com/mbostock/d3/blob/master/examples/mercator/mercator.html), which I've changed to zoom into Afghanistan and to use only one custom slider. I'm reading in GeoJSON data of places where explosions have happened and the graph maps them all at load. I want to use the slider to view only a month of explosion points at a time but am having trouble filtering the results. I've tried several things based on posts in the Google group but fail to understand how to filter the data read in previously from 'explosions.json'. Thanks for the help!
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>IED Attacks in Afghanistan (2004-2009)</title>
<script type="text/javascript" src="../d3.v2.js"></script>
<script type="text/javascript" src="../lib/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../lib/jquery-ui/jquery-ui.min.js"></script>
<style type="text/css">
#import url("../lib/jquery-ui/jquery-ui.css");
body, .ui-widget {
font: 14px Helvetica Neue;
}
svg {
width: 960px;
height: 600px;
border: solid 1px #ccc;
background: #eee;
}
line {
stroke: brown;
stroke-dasharray: 4,2;
}
path {
fill: #ccc;
stroke: #fff;
}
div {
width: 960px;
}
</style>
</head>
<body>
<h3>IED Attacks in Afghanistan (2004-2009)</h3>
<script type="text/javascript">
// Create the Mercator Projection (Map)
var xy = d3.geo.mercator(),
path = d3.geo.path().projection(xy);
// Create the states variable
var states = d3.select("body")
.append("svg")
.append("g")
.attr("id", "states");
// Create the equator variable
var equator = d3.select("svg")
.append("line")
.attr("x1", "0%")
.attr("x2", "100%");
// Create the explosions variable
var explosions = d3.select("svg")
.append("g")
.attr("id","explosions");
// Load in the states & equator data from the file 'world-countries.json'
d3.json("world-countries.json", function(collection) {
states
.selectAll("path")
.data(collection.features)
.enter().append("path")
.attr("d", path)
.append("title")
.text(function(d) { return d.properties.name; });
equator
.attr("y1", xy([0, 0])[1])
.attr("y2", xy([0, 0])[1]);
});
// the variable that holds our translate, center on Afghanistan
var translate = xy.translate(); //create translation to center gride in different area
translate[0] = -1741;
translate[1] = 1487;
xy.translate(translate); // center
xy.scale(12000); //zoom in
// Load in the explosions data from the file 'explosions.json'
d3.json("explosions.json", function(collection) {
explosions
.selectAll("path") //make a path and attach data
.data(collection.features)
.enter().append("path")
.attr("d", path)
.style("stroke","red") //color the path points
.style("stroke-width",2) //size of point stroke
.attr("class","explosionpoint")
.append("title") //title is the 'name' field in the json file
.text(function(d) { return d.properties.name; });
});
</script>
<p></p>
<!-- Slider -->
<div id="scale"></div><p></p>
<script type="text/javascript">
$("#scale").slider({
min: 20040101, //min : 1/1/04
max: 20100101, //max: 1/1/10
value: 20060601, //default slider value
step: 100, // step is the allow increments the slider can move. 100 = one month
slide: function(event, ui) {
/* REMOVE ALL EXPLOSION PATHS EXCEPT FOR A PARTICULAR MONTH OR RELOAD WITH FILTERED RESULTS */
}
});
</script>
You'll need to post part or all of your explosions.json object for a concrete answer. However, something like this will filter a JSON if it's structured like {explosion1:{data1:true, data2:true}, explosion2:{data1:true, data2:false}}:
function filterJSON(json, key, value) {
var result = {};
for (var explosionIndex in json) {
if (json[explosionIndex][key] === value) {
result[explosionIndex] = json[explosionIndex];
}
}
return result;
}
(e.g. filterJSON(myjson, "data1", true) will give all explosions with data1:true)
This is not specific to d3.
Then you could use something like this for the d3-side of things:
explosions.data(myFilteredData).exit().remove(); // remove ones you don't want
explosions.enter().append("path")... // add back ones you do want
If I understand your application, it would actually be better to just toggle the visiblity attribute of the SVG elements.
var sliderrange = [20040101, 20040201]; //replace with code based on your slider
explosions.selectAll(".explosionpoint").attr("visibility", function(d) {
//Replace with the correct date comparison logic
return d.date < sliderrange[1] && d.date > sliderrange[0] ? "visible" : "hidden";
});
D3 does have a very natural way of doing this. I'll assume your data looks something like this:
[{name: explosion1name, day: 20040110,...}, {name: explosion2name, day: 20040111,...}]
...and that you've got some variable, we'll call it explosionsData, to reference the data.
You can then draw your explosions with a function that takes the values from your slider. See the .filter I've added below.
function drawExplosions(startDay, endDay) {
explosions.selectAll("path") //make a path and attach data
.data(collection.features)
.enter().append("path")
.filter( function (d) { return ( (d.day > startDay) && (d.day < endDay) )})
.attr("d", path)
.style("stroke","red") //color the path points
.style("stroke-width",2) //size of point stroke
.attr("class","explosionpoint")
.append("title") //title is the 'name' field in the json file
.text(function(d) { return d.properties.name; });
Just call this function whenever your slider values changes.

Change default photoset size on tumblr

I know tumblr has the defualt photoset sizes {photoset-500},{photoset-400},{photoset-250}, but I want to change the width, so that the width could be either 420, or 350. i have looked everywhere and cannot find a code to help me do this.
You can use {Photoset} which just resizes the photoset to fit the container (max size 700px).
https://www.tumblr.com/docs/en/custom_themes
You cannot change default sizes of images with Tumblr markup, but you can visually change size with CSS.
Tumblr markup:
{block:Photoset}
{block:Photos}
<img src="{PhotoURL-500}" class="photoset-img" />
{/block:Photos}
{/block:Photoset}
CSS:
.photoset-img { width: 420px; /* can be any value you want */ }
Add this script before the ending body tag. This will increase or decrease the size of the photoset
<script type="text/javascript">
//This will change the source address and display the correct size.
$(".photoset").each(function() {
var newSrc = $(this).attr("src").replace('700','860');
$(this).attr("src", newSrc);
});
//This will get the new size of the iframe and resize the iframe holder accordingly.
$(function(){
var iFrames = $('.photoset');
function iResize() {
for (var i = 0, j = iFrames.length; i < j; i++) {
iFrames[i].style.height = iFrames[i].contentWindow.document.body.offsetHeight + 'px';}
}
if ($.browser.safari || $.browser.opera) {
iFrames.load(function(){
setTimeout(iResize, 0);
});
for (var i = 0, j = iFrames.length; i < j; i++) {
var iSource = iFrames[i].src;
iFrames[i].src = '';
iFrames[i].src = iSource;
}
} else {
iFrames.load(function() {
this.style.height = this.contentWindow.document.body.offsetHeight + 'px';
});
}
});
</script>

Fancybox Positioning Inside Facebook Canvas iFrame

OK so I have a iframe canvas app with its height set to "Settable" with the facebook javascrip sdk calls to FB.Canvas.setSize(); and FB.Canvas.setAutoGrow();. These are working perfectly, as the iframe gets set to a certain pixel height based on its content.
The problem is that when I make a call to Fancybox, it positions itself based on this height. I know that's exactly what its supposed to do as the fancybox jQuery returns the viewport by:
(line 673 of latest version of jquery.fancybox-1.3.4.js):
_get_viewport = function() {
return [
$(window).width() - (currentOpts.margin * 2),
$(window).height() - (currentOpts.margin * 2),
$(document).scrollTop() + currentOpts.margin
];
},
But the problem is the iframe will, for a lot of viewers, be longer than their browser window. So the Fancybox centers itself in the iframe and ends up only partly visible to the majority of viewers. (i.e. iframe height is 1058px and users browser is say only 650px).
Is there a way to have fancybox just calculate the physical browser height? Or do I need to change some settings in my Facebook canvas app to make it work?
I like how the only scrollbar is the one on Facebook (the parent, if you will).
All suggestions GREATLY appreciated!
For fancybox 2 try:
find:
_start: function(index) {
and replace with:
_start: function(index) {
if ((window.parent != window) && FB && FB.Canvas) {
FB.Canvas.getPageInfo(
function(info) {
window.canvasInfo = info;
F._start_orig(index);
}
);
} else {
F._start_orig(index);
}
},
_start_orig: function (index) {
Then in function getViewport replace return rez; with:
if (window.canvasInfo) {
rez.h = window.canvasInfo.clientHeight;
rez.x = window.canvasInfo.scrollLeft;
rez.y = window.canvasInfo.scrollTop - window.canvasInfo.offsetTop;
}
return rez;
and finally in _getPosition function replace line:
} else if (!current.locked) {
with:
} else if (!current.locked || window.canvasInfo) {
As facebook js api provides page info, then we could use it, so
find
_start = function() {
replace with
_start = function() {
if ((window.parent != window) && FB && FB.Canvas) {
FB.Canvas.getPageInfo(
function(info) {
window.canvasInfo = info;
_start_orig();
}
);
} else {
_start_orig();
}
},
_start_orig = function() {
and also modify _get_viewport function
_get_viewport = function() {
if (window.canvasInfo) {
console.log(window.canvasInfo);
return [
$(window).width() - (currentOpts.margin * 2),
window.canvasInfo.clientHeight - (currentOpts.margin * 2),
$(document).scrollLeft() + currentOpts.margin,
window.canvasInfo.scrollTop - window.canvasInfo.offsetTop + currentOpts.margin
];
} else {
return [
$(window).width() - (currentOpts.margin * 2),
$(window).height() - (currentOpts.margin * 2),
$(document).scrollLeft() + currentOpts.margin,
$(document).scrollTop() + currentOpts.margin
];
}
},
I had the same problem, i used 'centerOnScroll' :true, and now it works fine...
Had the same problem. Thankfully fancybox is accessable through CSS. My solution was to overwrite fancybox's positioning in my CSS file:
#fancybox-wrap {
top: 20px !important;
}
This code places the fancybox always 20px from top of the iframe. Use a different size if you like. The !important sets this positioning even though fancybox sets the position dynamically at runtime.
Here's one way to do it by positioning the Fancybox relative to the position of another element, in my case an Uploadify queue complete div that displays a view link after the user uploads an image.
Have a style block with a set ID like so:
<style id="style-block">
body { background-color: #e7ebf2; overflow: hidden; }
</style>
Then the link to open the Fancybox calls a function with the image name, width, and height to set the content and sizes. The important part is the positioning. By getting the position of the queue complete div, generating a new class declaration (fancy-position), appending it to the style block BEFORE the fancybox loads (!important in class will override positioning from fancybox), then adding the new class using the wrapCSS parameter in the fancybox options, it positions the fancybox exactly where I want it.
function viewImage(image, width, height) {
var complete_pos = $('#image_queue_complete').position();
var css_code = '.fancy-position { top: ' + complete_pos.top.toString() + 'px !important; }';
$('#style-block').append(css_code);
var img_src = '<img src="images/' + image + '" width="' + width.toString() + '" height="' + height.toString() + '" />';
$.fancybox({
content: img_src,
type: 'inline',
autoCenter: false,
wrapCSS: 'fancy-position'
});
}