AppGeo-geo-f763e47/0000775000175000017500000000000012005347446012753 5ustar daviddavidAppGeo-geo-f763e47/libs/0000775000175000017500000000000012005347446013704 5ustar daviddavidAppGeo-geo-f763e47/libs/qunit/0000775000175000017500000000000012005347446015044 5ustar daviddavidAppGeo-geo-f763e47/libs/qunit/qunit.js0000664000175000017500000012441112005347446016545 0ustar daviddavid/** * QUnit v1.4.0 - A JavaScript Unit Testing Framework * * http://docs.jquery.com/QUnit * * Copyright (c) 2012 John Resig, Jörn Zaefferer * Dual licensed under the MIT (MIT-LICENSE.txt) * or GPL (GPL-LICENSE.txt) licenses. */ (function(window) { var defined = { setTimeout: typeof window.setTimeout !== "undefined", sessionStorage: (function() { var x = "qunit-test-string"; try { sessionStorage.setItem(x, x); sessionStorage.removeItem(x); return true; } catch(e) { return false; } }()) }; var testId = 0, toString = Object.prototype.toString, hasOwn = Object.prototype.hasOwnProperty; var Test = function(name, testName, expected, async, callback) { this.name = name; this.testName = testName; this.expected = expected; this.async = async; this.callback = callback; this.assertions = []; }; Test.prototype = { init: function() { var tests = id("qunit-tests"); if (tests) { var b = document.createElement("strong"); b.innerHTML = "Running " + this.name; var li = document.createElement("li"); li.appendChild( b ); li.className = "running"; li.id = this.id = "test-output" + testId++; tests.appendChild( li ); } }, setup: function() { if (this.module != config.previousModule) { if ( config.previousModule ) { runLoggingCallbacks('moduleDone', QUnit, { name: config.previousModule, failed: config.moduleStats.bad, passed: config.moduleStats.all - config.moduleStats.bad, total: config.moduleStats.all } ); } config.previousModule = this.module; config.moduleStats = { all: 0, bad: 0 }; runLoggingCallbacks( 'moduleStart', QUnit, { name: this.module } ); } else if (config.autorun) { runLoggingCallbacks( 'moduleStart', QUnit, { name: this.module } ); } config.current = this; this.testEnvironment = extend({ setup: function() {}, teardown: function() {} }, this.moduleTestEnvironment); runLoggingCallbacks( 'testStart', QUnit, { name: this.testName, module: this.module }); // allow utility functions to access the current test environment // TODO why?? QUnit.current_testEnvironment = this.testEnvironment; if ( !config.pollution ) { saveGlobal(); } if ( config.notrycatch ) { this.testEnvironment.setup.call(this.testEnvironment); return; } try { this.testEnvironment.setup.call(this.testEnvironment); } catch(e) { QUnit.pushFailure( "Setup failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) ); } }, run: function() { config.current = this; if ( this.async ) { QUnit.stop(); } if ( config.notrycatch ) { this.callback.call(this.testEnvironment); return; } try { this.callback.call(this.testEnvironment); } catch(e) { QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + ": " + e.message, extractStacktrace( e, 1 ) ); // else next test will carry the responsibility saveGlobal(); // Restart the tests if they're blocking if ( config.blocking ) { QUnit.start(); } } }, teardown: function() { config.current = this; if ( config.notrycatch ) { this.testEnvironment.teardown.call(this.testEnvironment); return; } else { try { this.testEnvironment.teardown.call(this.testEnvironment); } catch(e) { QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) ); } } checkPollution(); }, finish: function() { config.current = this; if ( this.expected != null && this.expected != this.assertions.length ) { QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" ); } else if ( this.expected == null && !this.assertions.length ) { QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions." ); } var good = 0, bad = 0, li, i, tests = id("qunit-tests"); config.stats.all += this.assertions.length; config.moduleStats.all += this.assertions.length; if ( tests ) { var ol = document.createElement("ol"); for ( i = 0; i < this.assertions.length; i++ ) { var assertion = this.assertions[i]; li = document.createElement("li"); li.className = assertion.result ? "pass" : "fail"; li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed"); ol.appendChild( li ); if ( assertion.result ) { good++; } else { bad++; config.stats.bad++; config.moduleStats.bad++; } } // store result when possible if ( QUnit.config.reorder && defined.sessionStorage ) { if (bad) { sessionStorage.setItem("qunit-test-" + this.module + "-" + this.testName, bad); } else { sessionStorage.removeItem("qunit-test-" + this.module + "-" + this.testName); } } if (bad === 0) { ol.style.display = "none"; } var b = document.createElement("strong"); b.innerHTML = this.name + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; var a = document.createElement("a"); a.innerHTML = "Rerun"; a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); addEvent(b, "click", function() { var next = b.nextSibling.nextSibling, display = next.style.display; next.style.display = display === "none" ? "block" : "none"; }); addEvent(b, "dblclick", function(e) { var target = e && e.target ? e.target : window.event.srcElement; if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { target = target.parentNode; } if ( window.location && target.nodeName.toLowerCase() === "strong" ) { window.location = QUnit.url({ filter: getText([target]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); } }); li = id(this.id); li.className = bad ? "fail" : "pass"; li.removeChild( li.firstChild ); li.appendChild( b ); li.appendChild( a ); li.appendChild( ol ); } else { for ( i = 0; i < this.assertions.length; i++ ) { if ( !this.assertions[i].result ) { bad++; config.stats.bad++; config.moduleStats.bad++; } } } QUnit.reset(); runLoggingCallbacks( 'testDone', QUnit, { name: this.testName, module: this.module, failed: bad, passed: this.assertions.length - bad, total: this.assertions.length } ); }, queue: function() { var test = this; synchronize(function() { test.init(); }); function run() { // each of these can by async synchronize(function() { test.setup(); }); synchronize(function() { test.run(); }); synchronize(function() { test.teardown(); }); synchronize(function() { test.finish(); }); } // defer when previous test run passed, if storage is available var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-test-" + this.module + "-" + this.testName); if (bad) { run(); } else { synchronize(run, true); } } }; var QUnit = { // call on start of module test to prepend name to all tests module: function(name, testEnvironment) { config.currentModule = name; config.currentModuleTestEnviroment = testEnvironment; }, asyncTest: function(testName, expected, callback) { if ( arguments.length === 2 ) { callback = expected; expected = null; } QUnit.test(testName, expected, callback, true); }, test: function(testName, expected, callback, async) { var name = '' + escapeInnerText(testName) + ''; if ( arguments.length === 2 ) { callback = expected; expected = null; } if ( config.currentModule ) { name = '' + config.currentModule + ": " + name; } if ( !validTest(config.currentModule + ": " + testName) ) { return; } var test = new Test(name, testName, expected, async, callback); test.module = config.currentModule; test.moduleTestEnvironment = config.currentModuleTestEnviroment; test.queue(); }, // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. expect: function(asserts) { config.current.expected = asserts; }, // Asserts true. // @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); ok: function(result, msg) { if (!config.current) { throw new Error("ok() assertion outside test context, was " + sourceFromStacktrace(2)); } result = !!result; var details = { result: result, message: msg }; msg = escapeInnerText(msg || (result ? "okay" : "failed")); if ( !result ) { var source = sourceFromStacktrace(2); if (source) { details.source = source; msg += '
Source:
' + escapeInnerText(source) + '
'; } } runLoggingCallbacks( 'log', QUnit, details ); config.current.assertions.push({ result: result, message: msg }); }, // Checks that the first two arguments are equal, with an optional message. Prints out both actual and expected values. // @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." ); equal: function(actual, expected, message) { QUnit.push(expected == actual, actual, expected, message); }, notEqual: function(actual, expected, message) { QUnit.push(expected != actual, actual, expected, message); }, deepEqual: function(actual, expected, message) { QUnit.push(QUnit.equiv(actual, expected), actual, expected, message); }, notDeepEqual: function(actual, expected, message) { QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message); }, strictEqual: function(actual, expected, message) { QUnit.push(expected === actual, actual, expected, message); }, notStrictEqual: function(actual, expected, message) { QUnit.push(expected !== actual, actual, expected, message); }, raises: function(block, expected, message) { var actual, ok = false; if (typeof expected === 'string') { message = expected; expected = null; } try { block(); } catch (e) { actual = e; } if (actual) { // we don't want to validate thrown error if (!expected) { ok = true; // expected is a regexp } else if (QUnit.objectType(expected) === "regexp") { ok = expected.test(actual); // expected is a constructor } else if (actual instanceof expected) { ok = true; // expected is a validation function which returns true is validation passed } else if (expected.call({}, actual) === true) { ok = true; } } QUnit.ok(ok, message); }, start: function(count) { config.semaphore -= count || 1; if (config.semaphore > 0) { // don't start until equal number of stop-calls return; } if (config.semaphore < 0) { // ignore if start is called more often then stop config.semaphore = 0; } // A slight delay, to avoid any current callbacks if ( defined.setTimeout ) { window.setTimeout(function() { if (config.semaphore > 0) { return; } if ( config.timeout ) { clearTimeout(config.timeout); } config.blocking = false; process(true); }, 13); } else { config.blocking = false; process(true); } }, stop: function(count) { config.semaphore += count || 1; config.blocking = true; if ( config.testTimeout && defined.setTimeout ) { clearTimeout(config.timeout); config.timeout = window.setTimeout(function() { QUnit.ok( false, "Test timed out" ); config.semaphore = 1; QUnit.start(); }, config.testTimeout); } } }; //We want access to the constructor's prototype (function() { function F(){} F.prototype = QUnit; QUnit = new F(); //Make F QUnit's constructor so that we can add to the prototype later QUnit.constructor = F; }()); // deprecated; still export them to window to provide clear error messages // next step: remove entirely QUnit.equals = function() { QUnit.push(false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead"); }; QUnit.same = function() { QUnit.push(false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead"); }; // Maintain internal state var config = { // The queue of tests to run queue: [], // block until document ready blocking: true, // when enabled, show only failing tests // gets persisted through sessionStorage and can be changed in UI via checkbox hidepassed: false, // by default, run previously failed tests first // very useful in combination with "Hide passed tests" checked reorder: true, // by default, modify document.title when suite is done altertitle: true, urlConfig: ['noglobals', 'notrycatch'], //logging callback queues begin: [], done: [], log: [], testStart: [], testDone: [], moduleStart: [], moduleDone: [] }; // Load paramaters (function() { var location = window.location || { search: "", protocol: "file:" }, params = location.search.slice( 1 ).split( "&" ), length = params.length, urlParams = {}, current; if ( params[ 0 ] ) { for ( var i = 0; i < length; i++ ) { current = params[ i ].split( "=" ); current[ 0 ] = decodeURIComponent( current[ 0 ] ); // allow just a key to turn on a flag, e.g., test.html?noglobals current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; urlParams[ current[ 0 ] ] = current[ 1 ]; } } QUnit.urlParams = urlParams; config.filter = urlParams.filter; // Figure out if we're running the tests from a server or not QUnit.isLocal = location.protocol === 'file:'; }()); // Expose the API as global variables, unless an 'exports' // object exists, in that case we assume we're in CommonJS - export everything at the end if ( typeof exports === "undefined" || typeof require === "undefined" ) { extend(window, QUnit); window.QUnit = QUnit; } // define these after exposing globals to keep them in these QUnit namespace only extend(QUnit, { config: config, // Initialize the configuration options init: function() { extend(config, { stats: { all: 0, bad: 0 }, moduleStats: { all: 0, bad: 0 }, started: +new Date(), updateRate: 1000, blocking: false, autostart: true, autorun: false, filter: "", queue: [], semaphore: 0 }); var qunit = id( "qunit" ); if ( qunit ) { qunit.innerHTML = '

' + escapeInnerText( document.title ) + '

' + '

' + '
' + '

' + '
    '; } var tests = id( "qunit-tests" ), banner = id( "qunit-banner" ), result = id( "qunit-testresult" ); if ( tests ) { tests.innerHTML = ""; } if ( banner ) { banner.className = ""; } if ( result ) { result.parentNode.removeChild( result ); } if ( tests ) { result = document.createElement( "p" ); result.id = "qunit-testresult"; result.className = "result"; tests.parentNode.insertBefore( result, tests ); result.innerHTML = 'Running...
     '; } }, // Resets the test setup. Useful for tests that modify the DOM. // If jQuery is available, uses jQuery's html(), otherwise just innerHTML. reset: function() { if ( window.jQuery ) { jQuery( "#qunit-fixture" ).html( config.fixture ); } else { var main = id( 'qunit-fixture' ); if ( main ) { main.innerHTML = config.fixture; } } }, // Trigger an event on an element. // @example triggerEvent( document.body, "click" ); triggerEvent: function( elem, type, event ) { if ( document.createEvent ) { event = document.createEvent("MouseEvents"); event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, 0, 0, 0, 0, 0, false, false, false, false, 0, null); elem.dispatchEvent( event ); } else if ( elem.fireEvent ) { elem.fireEvent("on"+type); } }, // Safe object type checking is: function( type, obj ) { return QUnit.objectType( obj ) == type; }, objectType: function( obj ) { if (typeof obj === "undefined") { return "undefined"; // consider: typeof null === object } if (obj === null) { return "null"; } var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || ''; switch (type) { case 'Number': if (isNaN(obj)) { return "nan"; } return "number"; case 'String': case 'Boolean': case 'Array': case 'Date': case 'RegExp': case 'Function': return type.toLowerCase(); } if (typeof obj === "object") { return "object"; } return undefined; }, push: function(result, actual, expected, message) { if (!config.current) { throw new Error("assertion outside test context, was " + sourceFromStacktrace()); } var details = { result: result, message: message, actual: actual, expected: expected }; message = escapeInnerText(message) || (result ? "okay" : "failed"); message = '' + message + ""; var output = message; if (!result) { expected = escapeInnerText(QUnit.jsDump.parse(expected)); actual = escapeInnerText(QUnit.jsDump.parse(actual)); output += ''; if (actual != expected) { output += ''; output += ''; } var source = sourceFromStacktrace(); if (source) { details.source = source; output += ''; } output += "
    Expected:
    ' + expected + '
    Result:
    ' + actual + '
    Diff:
    ' + QUnit.diff(expected, actual) +'
    Source:
    ' + escapeInnerText(source) + '
    "; } runLoggingCallbacks( 'log', QUnit, details ); config.current.assertions.push({ result: !!result, message: output }); }, pushFailure: function(message, source) { var details = { result: false, message: message }; var output = escapeInnerText(message); if (source) { details.source = source; output += '
    Source:
    ' + escapeInnerText(source) + '
    '; } runLoggingCallbacks( 'log', QUnit, details ); config.current.assertions.push({ result: false, message: output }); }, url: function( params ) { params = extend( extend( {}, QUnit.urlParams ), params ); var querystring = "?", key; for ( key in params ) { if ( !hasOwn.call( params, key ) ) { continue; } querystring += encodeURIComponent( key ) + "=" + encodeURIComponent( params[ key ] ) + "&"; } return window.location.pathname + querystring.slice( 0, -1 ); }, extend: extend, id: id, addEvent: addEvent }); //QUnit.constructor is set to the empty F() above so that we can add to it's prototype later //Doing this allows us to tell if the following methods have been overwritten on the actual //QUnit object, which is a deprecated way of using the callbacks. extend(QUnit.constructor.prototype, { // Logging callbacks; all receive a single argument with the listed properties // run test/logs.html for any related changes begin: registerLoggingCallback('begin'), // done: { failed, passed, total, runtime } done: registerLoggingCallback('done'), // log: { result, actual, expected, message } log: registerLoggingCallback('log'), // testStart: { name } testStart: registerLoggingCallback('testStart'), // testDone: { name, failed, passed, total } testDone: registerLoggingCallback('testDone'), // moduleStart: { name } moduleStart: registerLoggingCallback('moduleStart'), // moduleDone: { name, failed, passed, total } moduleDone: registerLoggingCallback('moduleDone') }); if ( typeof document === "undefined" || document.readyState === "complete" ) { config.autorun = true; } QUnit.load = function() { runLoggingCallbacks( 'begin', QUnit, {} ); // Initialize the config, saving the execution queue var oldconfig = extend({}, config); QUnit.init(); extend(config, oldconfig); config.blocking = false; var urlConfigHtml = '', len = config.urlConfig.length; for ( var i = 0, val; i < len; i++ ) { val = config.urlConfig[i]; config[val] = QUnit.urlParams[val]; urlConfigHtml += ''; } var userAgent = id("qunit-userAgent"); if ( userAgent ) { userAgent.innerHTML = navigator.userAgent; } var banner = id("qunit-header"); if ( banner ) { banner.innerHTML = ' ' + banner.innerHTML + ' ' + urlConfigHtml; addEvent( banner, "change", function( event ) { var params = {}; params[ event.target.name ] = event.target.checked ? true : undefined; window.location = QUnit.url( params ); }); } var toolbar = id("qunit-testrunner-toolbar"); if ( toolbar ) { var filter = document.createElement("input"); filter.type = "checkbox"; filter.id = "qunit-filter-pass"; addEvent( filter, "click", function() { var ol = document.getElementById("qunit-tests"); if ( filter.checked ) { ol.className = ol.className + " hidepass"; } else { var tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; ol.className = tmp.replace(/ hidepass /, " "); } if ( defined.sessionStorage ) { if (filter.checked) { sessionStorage.setItem("qunit-filter-passed-tests", "true"); } else { sessionStorage.removeItem("qunit-filter-passed-tests"); } } }); if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) { filter.checked = true; var ol = document.getElementById("qunit-tests"); ol.className = ol.className + " hidepass"; } toolbar.appendChild( filter ); var label = document.createElement("label"); label.setAttribute("for", "qunit-filter-pass"); label.innerHTML = "Hide passed tests"; toolbar.appendChild( label ); } var main = id('qunit-fixture'); if ( main ) { config.fixture = main.innerHTML; } if (config.autostart) { QUnit.start(); } }; addEvent(window, "load", QUnit.load); // addEvent(window, "error") gives us a useless event object window.onerror = function( message, file, line ) { if ( QUnit.config.current ) { QUnit.pushFailure( message, file + ":" + line ); } else { QUnit.test( "global failure", function() { QUnit.pushFailure( message, file + ":" + line ); }); } }; function done() { config.autorun = true; // Log the last module results if ( config.currentModule ) { runLoggingCallbacks( 'moduleDone', QUnit, { name: config.currentModule, failed: config.moduleStats.bad, passed: config.moduleStats.all - config.moduleStats.bad, total: config.moduleStats.all } ); } var banner = id("qunit-banner"), tests = id("qunit-tests"), runtime = +new Date() - config.started, passed = config.stats.all - config.stats.bad, html = [ 'Tests completed in ', runtime, ' milliseconds.
    ', '', passed, ' tests of ', config.stats.all, ' passed, ', config.stats.bad, ' failed.' ].join(''); if ( banner ) { banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass"); } if ( tests ) { id( "qunit-testresult" ).innerHTML = html; } if ( config.altertitle && typeof document !== "undefined" && document.title ) { // show ✖ for good, ✔ for bad suite result in title // use escape sequences in case file gets loaded with non-utf-8-charset document.title = [ (config.stats.bad ? "\u2716" : "\u2714"), document.title.replace(/^[\u2714\u2716] /i, "") ].join(" "); } // clear own sessionStorage items if all tests passed if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) { for (var key in sessionStorage) { if (sessionStorage.hasOwnProperty(key) && key.indexOf("qunit-test-") === 0 ) { sessionStorage.removeItem(key); } } } runLoggingCallbacks( 'done', QUnit, { failed: config.stats.bad, passed: passed, total: config.stats.all, runtime: runtime } ); } function validTest( name ) { var filter = config.filter, run = false; if ( !filter ) { return true; } var not = filter.charAt( 0 ) === "!"; if ( not ) { filter = filter.slice( 1 ); } if ( name.indexOf( filter ) !== -1 ) { return !not; } if ( not ) { run = true; } return run; } // so far supports only Firefox, Chrome and Opera (buggy) // could be extended in the future to use something like https://github.com/csnover/TraceKit function extractStacktrace( e, offset ) { offset = offset || 3; if (e.stacktrace) { // Opera return e.stacktrace.split("\n")[offset + 3]; } else if (e.stack) { // Firefox, Chrome var stack = e.stack.split("\n"); if (/^error$/i.test(stack[0])) { stack.shift(); } return stack[offset]; } else if (e.sourceURL) { // Safari, PhantomJS // hopefully one day Safari provides actual stacktraces // exclude useless self-reference for generated Error objects if ( /qunit.js$/.test( e.sourceURL ) ) { return; } // for actual exceptions, this is useful return e.sourceURL + ":" + e.line; } } function sourceFromStacktrace(offset) { try { throw new Error(); } catch ( e ) { return extractStacktrace( e, offset ); } } function escapeInnerText(s) { if (!s) { return ""; } s = s + ""; return s.replace(/[\&<>]/g, function(s) { switch(s) { case "&": return "&"; case "<": return "<"; case ">": return ">"; default: return s; } }); } function synchronize( callback, last ) { config.queue.push( callback ); if ( config.autorun && !config.blocking ) { process(last); } } function process( last ) { function next() { process( last ); } var start = new Date().getTime(); config.depth = config.depth ? config.depth + 1 : 1; while ( config.queue.length && !config.blocking ) { if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) { config.queue.shift()(); } else { window.setTimeout( next, 13 ); break; } } config.depth--; if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { done(); } } function saveGlobal() { config.pollution = []; if ( config.noglobals ) { for ( var key in window ) { if ( !hasOwn.call( window, key ) ) { continue; } config.pollution.push( key ); } } } function checkPollution( name ) { var old = config.pollution; saveGlobal(); var newGlobals = diff( config.pollution, old ); if ( newGlobals.length > 0 ) { QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") ); } var deletedGlobals = diff( old, config.pollution ); if ( deletedGlobals.length > 0 ) { QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") ); } } // returns a new Array with the elements that are in a but not in b function diff( a, b ) { var result = a.slice(); for ( var i = 0; i < result.length; i++ ) { for ( var j = 0; j < b.length; j++ ) { if ( result[i] === b[j] ) { result.splice(i, 1); i--; break; } } } return result; } function extend(a, b) { for ( var prop in b ) { if ( b[prop] === undefined ) { delete a[prop]; // Avoid "Member not found" error in IE8 caused by setting window.constructor } else if ( prop !== "constructor" || a !== window ) { a[prop] = b[prop]; } } return a; } function addEvent(elem, type, fn) { if ( elem.addEventListener ) { elem.addEventListener( type, fn, false ); } else if ( elem.attachEvent ) { elem.attachEvent( "on" + type, fn ); } else { fn(); } } function id(name) { return !!(typeof document !== "undefined" && document && document.getElementById) && document.getElementById( name ); } function registerLoggingCallback(key){ return function(callback){ config[key].push( callback ); }; } // Supports deprecated method of completely overwriting logging callbacks function runLoggingCallbacks(key, scope, args) { //debugger; var callbacks; if ( QUnit.hasOwnProperty(key) ) { QUnit[key].call(scope, args); } else { callbacks = config[key]; for( var i = 0; i < callbacks.length; i++ ) { callbacks[i].call( scope, args ); } } } // Test for equality any JavaScript type. // Author: Philippe Rathé QUnit.equiv = (function() { var innerEquiv; // the real equiv function var callers = []; // stack to decide between skip/abort functions var parents = []; // stack to avoiding loops from circular referencing // Call the o related callback with the given arguments. function bindCallbacks(o, callbacks, args) { var prop = QUnit.objectType(o); if (prop) { if (QUnit.objectType(callbacks[prop]) === "function") { return callbacks[prop].apply(callbacks, args); } else { return callbacks[prop]; // or undefined } } } var getProto = Object.getPrototypeOf || function (obj) { return obj.__proto__; }; var callbacks = (function () { // for string, boolean, number and null function useStrictEquality(b, a) { if (b instanceof a.constructor || a instanceof b.constructor) { // to catch short annotaion VS 'new' annotation of a // declaration // e.g. var i = 1; // var j = new Number(1); return a == b; } else { return a === b; } } return { "string" : useStrictEquality, "boolean" : useStrictEquality, "number" : useStrictEquality, "null" : useStrictEquality, "undefined" : useStrictEquality, "nan" : function(b) { return isNaN(b); }, "date" : function(b, a) { return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf(); }, "regexp" : function(b, a) { return QUnit.objectType(b) === "regexp" && // the regex itself a.source === b.source && // and its modifers a.global === b.global && // (gmi) ... a.ignoreCase === b.ignoreCase && a.multiline === b.multiline; }, // - skip when the property is a method of an instance (OOP) // - abort otherwise, // initial === would have catch identical references anyway "function" : function() { var caller = callers[callers.length - 1]; return caller !== Object && typeof caller !== "undefined"; }, "array" : function(b, a) { var i, j, loop; var len; // b could be an object literal here if (QUnit.objectType(b) !== "array") { return false; } len = a.length; if (len !== b.length) { // safe and faster return false; } // track reference to avoid circular references parents.push(a); for (i = 0; i < len; i++) { loop = false; for (j = 0; j < parents.length; j++) { if (parents[j] === a[i]) { loop = true;// dont rewalk array } } if (!loop && !innerEquiv(a[i], b[i])) { parents.pop(); return false; } } parents.pop(); return true; }, "object" : function(b, a) { var i, j, loop; var eq = true; // unless we can proove it var aProperties = [], bProperties = []; // collection of // strings // comparing constructors is more strict than using // instanceof if (a.constructor !== b.constructor) { // Allow objects with no prototype to be equivalent to // objects with Object as their constructor. if (!((getProto(a) === null && getProto(b) === Object.prototype) || (getProto(b) === null && getProto(a) === Object.prototype))) { return false; } } // stack constructor before traversing properties callers.push(a.constructor); // track reference to avoid circular references parents.push(a); for (i in a) { // be strict: don't ensures hasOwnProperty // and go deep loop = false; for (j = 0; j < parents.length; j++) { if (parents[j] === a[i]) { // don't go down the same path twice loop = true; } } aProperties.push(i); // collect a's properties if (!loop && !innerEquiv(a[i], b[i])) { eq = false; break; } } callers.pop(); // unstack, we are done parents.pop(); for (i in b) { bProperties.push(i); // collect b's properties } // Ensures identical properties name return eq && innerEquiv(aProperties.sort(), bProperties.sort()); } }; }()); innerEquiv = function() { // can take multiple arguments var args = Array.prototype.slice.apply(arguments); if (args.length < 2) { return true; // end transition } return (function(a, b) { if (a === b) { return true; // catch the most you can } else if (a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || QUnit.objectType(a) !== QUnit.objectType(b)) { return false; // don't lose time with error prone cases } else { return bindCallbacks(a, callbacks, [ b, a ]); } // apply transition with (1..n) arguments }(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length - 1))); }; return innerEquiv; }()); /** * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | * http://flesler.blogspot.com Licensed under BSD * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008 * * @projectDescription Advanced and extensible data dumping for Javascript. * @version 1.0.0 * @author Ariel Flesler * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} */ QUnit.jsDump = (function() { function quote( str ) { return '"' + str.toString().replace(/"/g, '\\"') + '"'; } function literal( o ) { return o + ''; } function join( pre, arr, post ) { var s = jsDump.separator(), base = jsDump.indent(), inner = jsDump.indent(1); if ( arr.join ) { arr = arr.join( ',' + s + inner ); } if ( !arr ) { return pre + post; } return [ pre, inner + arr, base + post ].join(s); } function array( arr, stack ) { var i = arr.length, ret = new Array(i); this.up(); while ( i-- ) { ret[i] = this.parse( arr[i] , undefined , stack); } this.down(); return join( '[', ret, ']' ); } var reName = /^function (\w+)/; var jsDump = { parse: function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance stack = stack || [ ]; var parser = this.parsers[ type || this.typeOf(obj) ]; type = typeof parser; var inStack = inArray(obj, stack); if (inStack != -1) { return 'recursion('+(inStack - stack.length)+')'; } //else if (type == 'function') { stack.push(obj); var res = parser.call( this, obj, stack ); stack.pop(); return res; } // else return (type == 'string') ? parser : this.parsers.error; }, typeOf: function( obj ) { var type; if ( obj === null ) { type = "null"; } else if (typeof obj === "undefined") { type = "undefined"; } else if (QUnit.is("RegExp", obj)) { type = "regexp"; } else if (QUnit.is("Date", obj)) { type = "date"; } else if (QUnit.is("Function", obj)) { type = "function"; } else if (typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined") { type = "window"; } else if (obj.nodeType === 9) { type = "document"; } else if (obj.nodeType) { type = "node"; } else if ( // native arrays toString.call( obj ) === "[object Array]" || // NodeList objects ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) ) { type = "array"; } else { type = typeof obj; } return type; }, separator: function() { return this.multiline ? this.HTML ? '
    ' : '\n' : this.HTML ? ' ' : ' '; }, indent: function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing if ( !this.multiline ) { return ''; } var chr = this.indentChar; if ( this.HTML ) { chr = chr.replace(/\t/g,' ').replace(/ /g,' '); } return new Array( this._depth_ + (extra||0) ).join(chr); }, up: function( a ) { this._depth_ += a || 1; }, down: function( a ) { this._depth_ -= a || 1; }, setParser: function( name, parser ) { this.parsers[name] = parser; }, // The next 3 are exposed so you can use them quote: quote, literal: literal, join: join, // _depth_: 1, // This is the list of parsers, to modify them, use jsDump.setParser parsers: { window: '[Window]', document: '[Document]', error: '[ERROR]', //when no parser is found, shouldn't happen unknown: '[Unknown]', 'null': 'null', 'undefined': 'undefined', 'function': function( fn ) { var ret = 'function', name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE if ( name ) { ret += ' ' + name; } ret += '('; ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join(''); return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' ); }, array: array, nodelist: array, 'arguments': array, object: function( map, stack ) { var ret = [ ], keys, key, val, i; QUnit.jsDump.up(); if (Object.keys) { keys = Object.keys( map ); } else { keys = []; for (key in map) { keys.push( key ); } } keys.sort(); for (i = 0; i < keys.length; i++) { key = keys[ i ]; val = map[ key ]; ret.push( QUnit.jsDump.parse( key, 'key' ) + ': ' + QUnit.jsDump.parse( val, undefined, stack ) ); } QUnit.jsDump.down(); return join( '{', ret, '}' ); }, node: function( node ) { var open = QUnit.jsDump.HTML ? '<' : '<', close = QUnit.jsDump.HTML ? '>' : '>'; var tag = node.nodeName.toLowerCase(), ret = open + tag; for ( var a in QUnit.jsDump.DOMAttrs ) { var val = node[QUnit.jsDump.DOMAttrs[a]]; if ( val ) { ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' ); } } return ret + close + open + '/' + tag + close; }, functionArgs: function( fn ) {//function calls it internally, it's the arguments part of the function var l = fn.length; if ( !l ) { return ''; } var args = new Array(l); while ( l-- ) { args[l] = String.fromCharCode(97+l);//97 is 'a' } return ' ' + args.join(', ') + ' '; }, key: quote, //object calls it internally, the key part of an item in a map functionCode: '[code]', //function calls it internally, it's the content of the function attribute: quote, //node calls it internally, it's an html attribute value string: quote, date: quote, regexp: literal, //regex number: literal, 'boolean': literal }, DOMAttrs:{//attributes to dump from nodes, name=>realName id:'id', name:'name', 'class':'className' }, HTML:false,//if true, entities are escaped ( <, >, \t, space and \n ) indentChar:' ',//indentation unit multiline:true //if true, items in a collection, are separated by a \n, else just a space. }; return jsDump; }()); // from Sizzle.js function getText( elems ) { var ret = "", elem; for ( var i = 0; elems[i]; i++ ) { elem = elems[i]; // Get the text from text nodes and CDATA nodes if ( elem.nodeType === 3 || elem.nodeType === 4 ) { ret += elem.nodeValue; // Traverse everything else, except comment nodes } else if ( elem.nodeType !== 8 ) { ret += getText( elem.childNodes ); } } return ret; } //from jquery.js function inArray( elem, array ) { if ( array.indexOf ) { return array.indexOf( elem ); } for ( var i = 0, length = array.length; i < length; i++ ) { if ( array[ i ] === elem ) { return i; } } return -1; } /* * Javascript Diff Algorithm * By John Resig (http://ejohn.org/) * Modified by Chu Alan "sprite" * * Released under the MIT license. * * More Info: * http://ejohn.org/projects/javascript-diff-algorithm/ * * Usage: QUnit.diff(expected, actual) * * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick brown fox jumped jumps over" */ QUnit.diff = (function() { function diff(o, n) { var ns = {}; var os = {}; var i; for (i = 0; i < n.length; i++) { if (ns[n[i]] == null) { ns[n[i]] = { rows: [], o: null }; } ns[n[i]].rows.push(i); } for (i = 0; i < o.length; i++) { if (os[o[i]] == null) { os[o[i]] = { rows: [], n: null }; } os[o[i]].rows.push(i); } for (i in ns) { if ( !hasOwn.call( ns, i ) ) { continue; } if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) { n[ns[i].rows[0]] = { text: n[ns[i].rows[0]], row: os[i].rows[0] }; o[os[i].rows[0]] = { text: o[os[i].rows[0]], row: ns[i].rows[0] }; } } for (i = 0; i < n.length - 1; i++) { if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null && n[i + 1] == o[n[i].row + 1]) { n[i + 1] = { text: n[i + 1], row: n[i].row + 1 }; o[n[i].row + 1] = { text: o[n[i].row + 1], row: i + 1 }; } } for (i = n.length - 1; i > 0; i--) { if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null && n[i - 1] == o[n[i].row - 1]) { n[i - 1] = { text: n[i - 1], row: n[i].row - 1 }; o[n[i].row - 1] = { text: o[n[i].row - 1], row: i - 1 }; } } return { o: o, n: n }; } return function(o, n) { o = o.replace(/\s+$/, ''); n = n.replace(/\s+$/, ''); var out = diff(o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/)); var str = ""; var i; var oSpace = o.match(/\s+/g); if (oSpace == null) { oSpace = [" "]; } else { oSpace.push(" "); } var nSpace = n.match(/\s+/g); if (nSpace == null) { nSpace = [" "]; } else { nSpace.push(" "); } if (out.n.length === 0) { for (i = 0; i < out.o.length; i++) { str += '' + out.o[i] + oSpace[i] + ""; } } else { if (out.n[0].text == null) { for (n = 0; n < out.o.length && out.o[n].text == null; n++) { str += '' + out.o[n] + oSpace[n] + ""; } } for (i = 0; i < out.n.length; i++) { if (out.n[i].text == null) { str += '' + out.n[i] + nSpace[i] + ""; } else { var pre = ""; for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) { pre += '' + out.o[n] + oSpace[n] + ""; } str += " " + out.n[i].text + nSpace[i] + pre; } } } return str; }; }()); // for CommonJS enviroments, export everything if ( typeof exports !== "undefined" || typeof require !== "undefined" ) { extend(exports, QUnit); } // get at whatever the global object is, like window in browsers }( (function() {return this;}.call()) )); AppGeo-geo-f763e47/libs/qunit/qunit.css0000664000175000017500000001076712005347446016731 0ustar daviddavid/** * QUnit v1.4.0 - A JavaScript Unit Testing Framework * * http://docs.jquery.com/QUnit * * Copyright (c) 2012 John Resig, Jörn Zaefferer * Dual licensed under the MIT (MIT-LICENSE.txt) * or GPL (GPL-LICENSE.txt) licenses. */ /** Font Family and Sizes */ #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; } #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } #qunit-tests { font-size: smaller; } /** Resets */ #qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult { margin: 0; padding: 0; } /** Header */ #qunit-header { padding: 0.5em 0 0.5em 1em; color: #8699a4; background-color: #0d3349; font-size: 1.5em; line-height: 1em; font-weight: normal; border-radius: 15px 15px 0 0; -moz-border-radius: 15px 15px 0 0; -webkit-border-top-right-radius: 15px; -webkit-border-top-left-radius: 15px; } #qunit-header a { text-decoration: none; color: #c2ccd1; } #qunit-header a:hover, #qunit-header a:focus { color: #fff; } #qunit-header label { display: inline-block; } #qunit-banner { height: 5px; } #qunit-testrunner-toolbar { padding: 0.5em 0 0.5em 2em; color: #5E740B; background-color: #eee; } #qunit-userAgent { padding: 0.5em 0 0.5em 2.5em; background-color: #2b81af; color: #fff; text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; } /** Tests: Pass/Fail */ #qunit-tests { list-style-position: inside; } #qunit-tests li { padding: 0.4em 0.5em 0.4em 2.5em; border-bottom: 1px solid #fff; list-style-position: inside; } #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { display: none; } #qunit-tests li strong { cursor: pointer; } #qunit-tests li a { padding: 0.5em; color: #c2ccd1; text-decoration: none; } #qunit-tests li a:hover, #qunit-tests li a:focus { color: #000; } #qunit-tests ol { margin-top: 0.5em; padding: 0.5em; background-color: #fff; border-radius: 15px; -moz-border-radius: 15px; -webkit-border-radius: 15px; box-shadow: inset 0px 2px 13px #999; -moz-box-shadow: inset 0px 2px 13px #999; -webkit-box-shadow: inset 0px 2px 13px #999; } #qunit-tests table { border-collapse: collapse; margin-top: .2em; } #qunit-tests th { text-align: right; vertical-align: top; padding: 0 .5em 0 0; } #qunit-tests td { vertical-align: top; } #qunit-tests pre { margin: 0; white-space: pre-wrap; word-wrap: break-word; } #qunit-tests del { background-color: #e0f2be; color: #374e0c; text-decoration: none; } #qunit-tests ins { background-color: #ffcaca; color: #500; text-decoration: none; } /*** Test Counts */ #qunit-tests b.counts { color: black; } #qunit-tests b.passed { color: #5E740B; } #qunit-tests b.failed { color: #710909; } #qunit-tests li li { margin: 0.5em; padding: 0.4em 0.5em 0.4em 0.5em; background-color: #fff; border-bottom: none; list-style-position: inside; } /*** Passing Styles */ #qunit-tests li li.pass { color: #5E740B; background-color: #fff; border-left: 26px solid #C6E746; } #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } #qunit-tests .pass .test-name { color: #366097; } #qunit-tests .pass .test-actual, #qunit-tests .pass .test-expected { color: #999999; } #qunit-banner.qunit-pass { background-color: #C6E746; } /*** Failing Styles */ #qunit-tests li li.fail { color: #710909; background-color: #fff; border-left: 26px solid #EE5757; white-space: pre; } #qunit-tests > li:last-child { border-radius: 0 0 15px 15px; -moz-border-radius: 0 0 15px 15px; -webkit-border-bottom-right-radius: 15px; -webkit-border-bottom-left-radius: 15px; } #qunit-tests .fail { color: #000000; background-color: #EE5757; } #qunit-tests .fail .test-name, #qunit-tests .fail .module-name { color: #000000; } #qunit-tests .fail .test-actual { color: #EE5757; } #qunit-tests .fail .test-expected { color: green; } #qunit-banner.qunit-fail { background-color: #EE5757; } /** Result */ #qunit-testresult { padding: 0.5em 0.5em 0.5em 2.5em; color: #2b81af; background-color: #D2E0E6; border-bottom: 1px solid white; } /** Fixture */ #qunit-fixture { position: absolute; top: -10000px; left: -10000px; width: 1000px; height: 1000px; } AppGeo-geo-f763e47/libs/jquery/0000775000175000017500000000000012036234152015214 5ustar daviddavidAppGeo-geo-f763e47/js/0000775000175000017500000000000012036234152013360 5ustar daviddavidAppGeo-geo-f763e47/js/jquery.geo.core.js0000664000175000017500000010103212005347446016741 0ustar daviddavid(function ($, window, undefined) { var pos_oo = Number.POSITIVE_INFINITY, neg_oo = Number.NEGATIVE_INFINITY; $.geo = { // // utility functions // _allCoordinates: function (geom) { // return array of all positions in all geometries of geom // not in JTS var geometries = this._flatten(geom), curGeom = 0, result = []; for (; curGeom < geometries.length; curGeom++) { var coordinates = geometries[curGeom].coordinates, isArray = coordinates && $.isArray(coordinates[0]), isDblArray = isArray && $.isArray(coordinates[0][0]), isTriArray = isDblArray && $.isArray(coordinates[0][0][0]), i, j, k; if (!isTriArray) { if (!isDblArray) { if (!isArray) { coordinates = [coordinates]; } coordinates = [coordinates]; } coordinates = [coordinates]; } for (i = 0; i < coordinates.length; i++) { for (j = 0; j < coordinates[i].length; j++) { for (k = 0; k < coordinates[i][j].length; k++) { result.push(coordinates[i][j][k]); } } } } return result; }, _isGeodetic: function( coords ) { // returns true if the first coordinate it can find is geodetic while ( $.isArray( coords ) ) { if ( coords.length > 1 && ! $.isArray( coords[ 0 ] ) ) { return ( coords[ 0 ] >= -180 && coords[ 0 ] <= 180 && coords[ 1 ] >= -85 && coords[ 1 ] <= 85 ); } else { coords = coords[ 0 ]; } } return false; }, // // bbox functions // center: function (bbox, _ignoreGeo /* Internal Use Only */) { // Envelope.centre in JTS // bbox only, use centroid for geom var wasGeodetic = false; if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( bbox ) ) { wasGeodetic = true; bbox = $.geo.proj.fromGeodetic(bbox); } var center = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2]; return wasGeodetic ? $.geo.proj.toGeodetic(center) : center; }, expandBy: function (bbox, dx, dy, _ignoreGeo /* Internal Use Only */) { var wasGeodetic = false; if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( bbox ) ) { wasGeodetic = true; bbox = $.geo.proj.fromGeodetic(bbox); } bbox = [bbox[0] - dx, bbox[1] - dy, bbox[2] + dx, bbox[3] + dy]; return wasGeodetic ? $.geo.proj.toGeodetic(bbox) : bbox; }, height: function (bbox, _ignoreGeo /* Internal Use Only */ ) { if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( bbox ) ) { bbox = $.geo.proj.fromGeodetic(bbox); } return bbox[3] - bbox[1]; }, _in: function(bbox1, bbox2) { return bbox1[0] <= bbox2[0] && bbox1[1] <= bbox2[1] && bbox1[2] >= bbox2[2] && bbox1[3] >= bbox2[3]; }, _bboxDisjoint: function( bbox1, bbox2 ) { return bbox2[ 0 ] > bbox1[ 2 ] || bbox2[ 2 ] < bbox1[ 0 ] || bbox2[ 1 ] > bbox1[ 3 ] || bbox2[ 3 ] < bbox1[ 1 ]; }, include: function( bbox, value, _ignoreGeo /* Internal Use Only */ ) { // similar to Envelope.expandToInclude in JTS if ( !value || !$.isArray( value ) ) { return bbox; } var wasGeodetic = false; if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( bbox || value ) ) { wasGeodetic = true; } if ( !bbox ) { bbox = [ pos_oo, pos_oo, neg_oo, neg_oo ]; } else if ( wasGeodetic ) { bbox = $.geo.proj.fromGeodetic( bbox ); } if ( value.length === 2 ) { value = [ value[ 0 ], value[ 1 ], value[ 0 ], value[ 1 ] ]; } value = $.geo.proj.fromGeodetic( value ); bbox[0] = Math.min( value[ 0 ], bbox[ 0 ] ); bbox[1] = Math.min( value[ 1 ], bbox[ 1 ] ); bbox[2] = Math.max( value[ 2 ], bbox[ 2 ] ); bbox[3] = Math.max( value[ 3 ], bbox[ 3 ] ); return wasGeodetic ? $.geo.proj.toGeodetic( bbox ) : bbox; }, polygonize: function( bbox, _ignoreGeo /* Internal Use Only */ ) { // adaptation of Polygonizer class in JTS for use with bboxes var wasGeodetic = false; if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( bbox ) ) { wasGeodetic = true; bbox = $.geo.proj.fromGeodetic(bbox); } var polygon = { type: "Polygon", coordinates: [ [ [ bbox[ 0 ], bbox[ 1 ] ], [ bbox[ 0 ], bbox[ 3 ] ], [ bbox[ 2 ], bbox[ 3 ] ], [ bbox[ 2 ], bbox[ 1 ] ], [ bbox[ 0 ], bbox[ 1 ] ] ] ] }; if ( wasGeodetic ) { polygon.coordinates = $.geo.proj.toGeodetic( polygon.coordinates ); } return polygon; }, reaspect: function (bbox, ratio, _ignoreGeo /* Internal Use Only */ ) { // not in JTS var wasGeodetic = false; if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( bbox ) ) { wasGeodetic = true; bbox = $.geo.proj.fromGeodetic(bbox); } var width = this.width(bbox, true), height = this.height(bbox, true), center = this.center(bbox, true), dx, dy; if (width !== 0 && height !== 0 && ratio > 0) { if (width / height > ratio) { dx = width / 2; dy = dx / ratio; } else { dy = height / 2; dx = dy * ratio; } bbox = [center[0] - dx, center[1] - dy, center[0] + dx, center[1] + dy]; } return wasGeodetic ? $.geo.proj.toGeodetic(bbox) : bbox; }, recenter: function( bbox, center, _ignoreGeo /* Internal Use Only */ ) { // not in JTS var wasGeodetic = false; if ( !_ignoreGeo && $.geo.proj ) { if ( this._isGeodetic( bbox ) ) { wasGeodetic = true; bbox = $.geo.proj.fromGeodetic(bbox); } if ( this._isGeodetic( center ) ) { center = $.geo.proj.fromGeodetic(center); } } var halfWidth = ( bbox[ 2 ] - bbox[ 0 ] ) / 2, halfHeight = ( bbox[ 3 ] - bbox[ 1 ] ) / 2; bbox = [ center[ 0 ] - halfWidth, center[ 1 ] - halfHeight, center[ 0 ] + halfWidth, center[ 1 ] + halfHeight ]; return wasGeodetic ? $.geo.proj.toGeodetic(bbox) : bbox; }, scaleBy: function ( bbox, scale, _ignoreGeo /* Internal Use Only */ ) { // not in JTS var wasGeodetic = false; if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( bbox ) ) { wasGeodetic = true; bbox = $.geo.proj.fromGeodetic(bbox); } var c = this.center(bbox, true), dx = (bbox[2] - bbox[0]) * scale / 2, dy = (bbox[3] - bbox[1]) * scale / 2; bbox = [c[0] - dx, c[1] - dy, c[0] + dx, c[1] + dy]; return wasGeodetic ? $.geo.proj.toGeodetic(bbox) : bbox; }, width: function (bbox, _ignoreGeo /* Internal Use Only */ ) { if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( bbox ) ) { bbox = $.geo.proj.fromGeodetic(bbox); } return bbox[2] - bbox[0]; }, // // geometry functions // // bbox (Geometry.getEnvelope in JTS) bbox: function ( geom, _ignoreGeo /* Internal Use Only */ ) { var result, wasGeodetic = false; if ( !geom ) { return undefined; } else if ( geom.bbox ) { result = ( !_ignoreGeo && $.geo.proj && this._isGeodetic( geom.bbox ) ) ? $.geo.proj.fromGeodetic( geom.bbox ) : geom.bbox; } else { result = [ pos_oo, pos_oo, neg_oo, neg_oo ]; var coordinates = this._allCoordinates( geom ), curCoord = 0; if ( coordinates.length === 0 ) { return undefined; } if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( coordinates ) ) { wasGeodetic = true; coordinates = $.geo.proj.fromGeodetic( coordinates ); } for ( ; curCoord < coordinates.length; curCoord++ ) { result[0] = Math.min(coordinates[curCoord][0], result[0]); result[1] = Math.min(coordinates[curCoord][1], result[1]); result[2] = Math.max(coordinates[curCoord][0], result[2]); result[3] = Math.max(coordinates[curCoord][1], result[3]); } } return wasGeodetic ? $.geo.proj.toGeodetic(result) : result; }, // centroid centroid: function( geom, _ignoreGeo /* Internal Use Only */ ) { switch (geom.type) { case "Point": return $.extend({}, geom); case "LineString": case "Polygon": var a = 0, c = [0, 0], coords = $.merge( [ ], geom.type == "Polygon" ? geom.coordinates[0] : geom.coordinates ), i = 1, j, n, bbox = [ pos_oo, pos_oo, neg_oo, neg_oo ]; var wasGeodetic = false; if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( coords ) ) { wasGeodetic = true; coords = $.geo.proj.fromGeodetic(coords); } //if (coords[0][0] != coords[coords.length - 1][0] || coords[0][1] != coords[coords.length - 1][1]) { // coords.push(coords[0]); //} for (; i <= coords.length; i++) { j = i % coords.length; bbox[0] = Math.min(coords[j][0], bbox[0]); bbox[1] = Math.min(coords[j][1], bbox[1]); bbox[2] = Math.max(coords[j][0], bbox[2]); bbox[3] = Math.max(coords[j][1], bbox[3]); n = (coords[i - 1][0] * coords[j][1]) - (coords[j][0] * coords[i - 1][1]); a += n; c[0] += (coords[i - 1][0] + coords[j][0]) * n; c[1] += (coords[i - 1][1] + coords[j][1]) * n; } if (a === 0) { if (coords.length > 0) { c[0] = Math.min( Math.max( coords[0][0], bbox[ 0 ] ), bbox[ 2 ] ); c[1] = Math.min( Math.max( coords[0][1], bbox[ 1 ] ), bbox[ 3 ] ); return { type: "Point", coordinates: wasGeodetic ? $.geo.proj.toGeodetic(c) : c }; } else { return undefined; } } a *= 3; //c[0] /= a; //c[1] /= a; c[0] = Math.min( Math.max( c[0] / a, bbox[ 0 ] ), bbox[ 2 ] ); c[1] = Math.min( Math.max( c[1] / a, bbox[ 1 ] ), bbox[ 3 ] ); return { type: "Point", coordinates: wasGeodetic ? $.geo.proj.toGeodetic(c) : c }; } return undefined; }, // contains contains: function (geom1, geom2) { if (geom1.type != "Polygon") { return false; } switch (geom2.type) { case "Point": return this._containsPolygonPoint(geom1.coordinates, geom2.coordinates); case "LineString": return this._containsPolygonLineString(geom1.coordinates, geom2.coordinates); case "Polygon": return this._containsPolygonLineString(geom1.coordinates, geom2.coordinates[0]); default: return false; } }, _containsPolygonPoint: function (polygonCoordinates, pointCoordinate) { if (polygonCoordinates.length === 0 || polygonCoordinates[0].length < 4) { return false; } var rayCross = 0, a = polygonCoordinates[0][0], i = 1, b, x; for (; i < polygonCoordinates[0].length; i++) { b = polygonCoordinates[0][i]; if ((a[1] <= pointCoordinate[1] && pointCoordinate[1] < b[1]) || (b[1] <= pointCoordinate[1] && pointCoordinate[1] < a[1]) && (pointCoordinate[0] < a[0] || pointCoordinate[0] < b[0])) { x = a[0] + (b[0] - a[0]) * (pointCoordinate[1] - a[1]) / (b[1] - a[1]); if (x > pointCoordinate[0]) { rayCross++; } } a = b; } return rayCross % 2 == 1; }, _containsPolygonLineString: function (polygonCoordinates, lineStringCoordinates) { for (var i = 0; i < lineStringCoordinates.length; i++) { if (!this._containsPolygonPoint(polygonCoordinates, lineStringCoordinates[i])) { return false; } } return true; }, // distance distance: function ( geom1, geom2, _ignoreGeo /* Internal Use Only */ ) { var geom1CoordinatesProjected = ( !_ignoreGeo && $.geo.proj && this._isGeodetic( geom1.coordinates ) ) ? $.geo.proj.fromGeodetic(geom1.coordinates) : geom1.coordinates, geom2CoordinatesProjected = ( !_ignoreGeo && $.geo.proj && this._isGeodetic( geom2.coordinates ) ) ? $.geo.proj.fromGeodetic(geom2.coordinates) : geom2.coordinates; switch (geom1.type) { case "Point": switch (geom2.type) { case "Point": return this._distancePointPoint(geom2CoordinatesProjected, geom1CoordinatesProjected); case "LineString": return this._distanceLineStringPoint(geom2CoordinatesProjected, geom1CoordinatesProjected); case "Polygon": return this._containsPolygonPoint(geom2CoordinatesProjected, geom1CoordinatesProjected) ? 0 : this._distanceLineStringPoint(geom2CoordinatesProjected[0], geom1CoordinatesProjected); default: return undefined; } break; case "LineString": switch (geom2.type) { case "Point": return this._distanceLineStringPoint(geom1CoordinatesProjected, geom2CoordinatesProjected); case "LineString": return this._distanceLineStringLineString(geom1CoordinatesProjected, geom2CoordinatesProjected); case "Polygon": return this._containsPolygonLineString(geom2CoordinatesProjected, geom1CoordinatesProjected) ? 0 : this._distanceLineStringLineString(geom2CoordinatesProjected[0], geom1CoordinatesProjected); default: return undefined; } break; case "Polygon": switch (geom2.type) { case "Point": return this._containsPolygonPoint(geom1CoordinatesProjected, geom2CoordinatesProjected) ? 0 : this._distanceLineStringPoint(geom1CoordinatesProjected[0], geom2CoordinatesProjected); case "LineString": return this._containsPolygonLineString(geom1CoordinatesProjected, geom2CoordinatesProjected) ? 0 : this._distanceLineStringLineString(geom1CoordinatesProjected[0], geom2CoordinatesProjected); case "Polygon": return this._containsPolygonLineString(geom1CoordinatesProjected, geom2CoordinatesProjected[0]) ? 0 : this._distanceLineStringLineString(geom1CoordinatesProjected[0], geom2CoordinatesProjected[0]); default: return undefined; } break; } }, _distancePointPoint: function (coordinate1, coordinate2) { var dx = coordinate2[0] - coordinate1[0], dy = coordinate2[1] - coordinate1[1]; return Math.sqrt((dx * dx) + (dy * dy)); }, _distanceLineStringPoint: function (lineStringCoordinates, pointCoordinate) { var minDist = pos_oo; if (lineStringCoordinates.length > 0) { var a = lineStringCoordinates[0], apx = pointCoordinate[0] - a[0], apy = pointCoordinate[1] - a[1]; if (lineStringCoordinates.length == 1) { return Math.sqrt(apx * apx + apy * apy); } else { for (var i = 1; i < lineStringCoordinates.length; i++) { var b = lineStringCoordinates[i], abx = b[0] - a[0], aby = b[1] - a[1], bpx = pointCoordinate[0] - b[0], bpy = pointCoordinate[1] - b[1], d = this._distanceSegmentPoint(abx, aby, apx, apy, bpx, bpy); if (d === 0) { return 0; } if (d < minDist) { minDist = d; } a = b; apx = bpx; apy = bpy; } } } return Math.sqrt(minDist); }, _distanceSegmentPoint: function (abx, aby, apx, apy, bpx, bpy) { var dot1 = abx * apx + aby * apy; if (dot1 <= 0) { return apx * apx + apy * apy; } var dot2 = abx * abx + aby * aby; if (dot1 >= dot2) { return bpx * bpx + bpy * bpy; } return apx * apx + apy * apy - dot1 * dot1 / dot2; }, _distanceLineStringLineString: function (lineStringCoordinates1, lineStringCoordinates2) { var minDist = pos_oo; for (var i = 0; i < lineStringCoordinates2.length; i++) { minDist = Math.min(minDist, this._distanceLineStringPoint(lineStringCoordinates1, lineStringCoordinates2[i])); } return minDist; }, // buffer _buffer: function( geom, distance, _ignoreGeo /* Internal Use Only */ ) { var wasGeodetic = false, coords = geom.coordinates; if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( geom.coordinates ) ) { wasGeodetic = true; coords = $.geo.proj.fromGeodetic( geom.coordinates ); } if ( geom.type === "Point" ) { var resultCoords = [], slices = 180, i = 0, a; for ( ; i <= slices; i++ ) { a = ( i * 360 / slices ) * ( Math.PI / 180 ); resultCoords.push( [ coords[ 0 ] + Math.cos( a ) * distance, coords[ 1 ] + Math.sin( a ) * distance ] ); } return { type: "Polygon", coordinates: [ ( wasGeodetic ? $.geo.proj.toGeodetic( resultCoords ) : resultCoords ) ] }; } else { return undefined; } }, // // feature // _flatten: function (geom) { // return an array of all basic geometries // not in JTS var geometries = [], curGeom = 0; switch (geom.type) { case "Feature": $.merge(geometries, this._flatten(geom.geometry)); break; case "FeatureCollection": for (; curGeom < geom.features.length; curGeom++) { $.merge(geometries, this._flatten(geom.features[curGeom].geometry)); } break; case "GeometryCollection": for (; curGeom < geom.geometries.length; curGeom++) { $.merge(geometries, this._flatten(geom.geometries[curGeom])); } break; default: geometries[0] = geom; break; } return geometries; }, length: function( geom, _ignoreGeo /* Internal Use Only */ ) { var sum = 0, lineStringCoordinates, i = 1, dx, dy; switch ( geom.type ) { case "Point": return 0; case "LineString": lineStringCoordinates = geom.coordinates; break; case "Polygon": lineStringCoordinates = geom.coordinates[ 0 ]; break; } if ( lineStringCoordinates ) { if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( lineStringCoordinates ) ) { lineStringCoordinates = $.geo.proj.fromGeodetic( lineStringCoordinates ); } for ( ; i < lineStringCoordinates.length; i++ ) { dx = lineStringCoordinates[ i ][0] - lineStringCoordinates[ i - 1 ][0]; dy = lineStringCoordinates[ i ][1] - lineStringCoordinates[ i - 1 ][1]; sum += Math.sqrt((dx * dx) + (dy * dy)); } return sum; } // return undefined; }, area: function( geom, _ignoreGeo /* Internal Use Only */ ) { var sum = 0, polygonCoordinates, i = 1, j; switch ( geom.type ) { case "Point": case "LineString": return 0; case "Polygon": polygonCoordinates = geom.coordinates[ 0 ]; break; } if ( polygonCoordinates ) { if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( polygonCoordinates ) ) { polygonCoordinates = $.geo.proj.fromGeodetic( polygonCoordinates ); } for ( ; i <= polygonCoordinates.length; i++) { j = i % polygonCoordinates.length; sum += ( polygonCoordinates[ i - 1 ][ 0 ] - polygonCoordinates[ j ][ 0 ] ) * ( polygonCoordinates[ i - 1 ][ 1 ] + polygonCoordinates[ j ][ 1 ] ) / 2; } return Math.abs( sum ); } }, pointAlong: function( geom, percentage, _ignoreGeo /* Internal Use Only */ ) { var totalLength = 0, previousPercentageSum = 0, percentageSum = 0, remainderPercentageSum, len, lineStringCoordinates, segmentLengths = [], i = 1, dx, dy, c, c0, c1, wasGeodetic = false; switch ( geom.type ) { case "Point": return $.extend( { }, geom ); case "LineString": lineStringCoordinates = geom.coordinates; break; case "Polygon": lineStringCoordinates = geom.coordinates[ 0 ]; break; } if ( lineStringCoordinates ) { if ( percentage === 0 ) { return { type: "Point", coordinates: [ lineStringCoordinates[ 0 ][ 0 ], lineStringCoordinates[ 0 ][ 1 ] ] }; } else if ( percentage === 1 ) { i = lineStringCoordinates.length - 1; return { type: "Point", coordinates: [ lineStringCoordinates[ i ][ 0 ], lineStringCoordinates[ i ][ 1 ] ] }; } else { if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( lineStringCoordinates ) ) { wasGeodetic = true; lineStringCoordinates = $.geo.proj.fromGeodetic( lineStringCoordinates ); } for ( ; i < lineStringCoordinates.length; i++ ) { dx = lineStringCoordinates[ i ][ 0 ] - lineStringCoordinates[ i - 1 ][ 0 ]; dy = lineStringCoordinates[ i ][ 1 ] - lineStringCoordinates[ i - 1 ][ 1 ]; len = Math.sqrt((dx * dx) + (dy * dy)); segmentLengths.push( len ); totalLength += len; } for ( i = 0; i < segmentLengths.length && percentageSum < percentage; i++ ) { previousPercentageSum = percentageSum; percentageSum += ( segmentLengths[ i ] / totalLength ); } remainderPercentageSum = percentage - previousPercentageSum; c0 = lineStringCoordinates[ i - 1 ]; c1 = lineStringCoordinates[ i ]; c = [ c0[ 0 ] + ( remainderPercentageSum * ( c1[ 0 ] - c0[ 0 ] ) ), c0[ 1 ] + ( remainderPercentageSum * ( c1[ 1 ] - c0[ 1 ] ) ) ]; return { type: "Point", coordinates: wasGeodetic ? $.geo.proj.toGeodetic(c) : c }; } } }, // // WKT functions // _WKT: (function () { function pointToString(value) { return "POINT " + pointToUntaggedString(value.coordinates); } function pointToUntaggedString(coordinates) { if (!(coordinates && coordinates.length)) { return "EMPTY"; } else { return "(" + coordinates.join(" ") + ")"; } } function lineStringToString(value) { return "LINESTRING " + lineStringToUntaggedString(value.coordinates); } function lineStringToUntaggedString(coordinates) { if (!(coordinates && coordinates.length)) { return "EMPTY"; } else { var points = []; for (var i = 0; i < coordinates.length; i++) { points.push(coordinates[i].join(" ")); } return "(" + points + ")"; } } function polygonToString(value) { return "POLYGON " + polygonToUntaggedString(value.coordinates); } function polygonToUntaggedString(coordinates) { if (!(coordinates && coordinates.length)) { return "EMTPY"; } else { var lineStrings = []; for (var i = 0; i < coordinates.length; i++) { lineStrings.push(lineStringToUntaggedString(coordinates[i])); } return "(" + lineStrings + ")"; } } function multiPointToString(value) { return "MULTIPOINT " + lineStringToUntaggedString(value.coordinates); } function multiLineStringToString(value) { return "MULTILINSTRING " + polygonToUntaggedString(value.coordinates); } function multiPolygonToString(value) { return "MULTIPOLYGON " + multiPolygonToUntaggedString(value.coordinates); } function multiPolygonToUntaggedString(coordinates) { if (!(coordinates && coordinates.length)) { return "EMPTY"; } else { var polygons = []; for (var i = 0; i < coordinates.length; i++) { polygons.push(polygonToUntaggedString(coordinates[i])); } return "(" + polygons + ")"; } } function geometryCollectionToString(value) { return "GEOMETRYCOLLECTION " + geometryCollectionToUntaggedString(value.geometries); } function geometryCollectionToUntaggedString(geometries) { if (!(geometries && geometries.length)) { return "EMPTY"; } else { var geometryText = []; for (var i = 0; i < geometries.length; i++) { geometryText.push(stringify(geometries[i])); } return "(" + geometries + ")"; } } function stringify(value) { if (!(value && value.type)) { return ""; } else { switch (value.type) { case "Point": return pointToString(value); case "LineString": return lineStringToString(value); case "Polygon": return polygonToString(value); case "MultiPoint": return multiPointToString(value); case "MultiLineString": return multiLineStringToString(value); case "MultiPolygon": return multiPolygonToString(value); case "GeometryCollection": return geometryCollectionToString(value); default: return ""; } } } function pointParseUntagged(wkt) { var pointString = wkt.match( /\(\s*([\d\.\-]+)\s+([\d\.\-]+)\s*\)/ ); return pointString && pointString.length > 2 ? { type: "Point", coordinates: [ parseFloat(pointString[1]), parseFloat(pointString[2]) ] } : null; } function lineStringParseUntagged(wkt) { var lineString = wkt.match( /\s*\((.*)\)/ ), coords = [], pointStrings, pointParts, i = 0; if ( lineString.length > 1 ) { pointStrings = lineString[ 1 ].match( /[\d\.\-]+\s+[\d\.\-]+/g ); for ( ; i < pointStrings.length; i++ ) { pointParts = pointStrings[ i ].match( /\s*([\d\.\-]+)\s+([\d\.\-]+)\s*/ ); coords[ i ] = [ parseFloat( pointParts[ 1 ] ), parseFloat( pointParts[ 2 ] ) ]; } return { type: "LineString", coordinates: coords }; } else { return null; } } function polygonParseUntagged(wkt) { var polygon = wkt.match( /\s*\(\s*\((.*)\)\s*\)/ ), coords = [], pointStrings, pointParts, i = 0; if ( polygon.length > 1 ) { pointStrings = polygon[ 1 ].match( /[\d\.\-]+\s+[\d\.\-]+/g ); for ( ; i < pointStrings.length; i++ ) { pointParts = pointStrings[ i ].match( /\s*([\d\.\-]+)\s+([\d\.\-]+)\s*/ ); coords[ i ] = [ parseFloat( pointParts[ 1 ] ), parseFloat( pointParts[ 2 ] ) ]; } return { type: "Polygon", coordinates: [ coords ] }; } else { return null; } } function parse(wkt) { wkt = $.trim(wkt); var typeIndex = wkt.indexOf( " " ), untagged = wkt.substr( typeIndex + 1 ); switch (wkt.substr(0, typeIndex).toUpperCase()) { case "POINT": return pointParseUntagged( untagged ); case "LINESTRING": return lineStringParseUntagged( untagged ); case "POLYGON": return polygonParseUntagged( untagged ); default: return null; } } return { stringify: stringify, parse: parse }; }()), // // projection functions // proj: (function () { var halfPi = 1.5707963267948966192, quarterPi = 0.7853981633974483096, radiansPerDegree = 0.0174532925199432958, degreesPerRadian = 57.295779513082320877, semiMajorAxis = 6378137; return { fromGeodeticPos: function (coordinate) { return [ semiMajorAxis * coordinate[ 0 ] * radiansPerDegree, semiMajorAxis * Math.log(Math.tan(quarterPi + coordinate[ 1 ] * radiansPerDegree / 2)) ]; }, fromGeodetic: function ( coordinates ) { if ( ! $.geo._isGeodetic( coordinates ) ) { return coordinates; } var isMultiPointOrLineString = $.isArray(coordinates[ 0 ]), fromGeodeticPos = this.fromGeodeticPos; if (!isMultiPointOrLineString && coordinates.length == 4) { // bbox var min = fromGeodeticPos([ coordinates[ 0 ], coordinates[ 1 ] ]), max = fromGeodeticPos([ coordinates[ 2 ], coordinates[ 3 ] ]); return [ min[ 0 ], min[ 1 ], max[ 0 ], max[ 1 ] ]; } else { // geometry var isMultiLineStringOrPolygon = isMultiPointOrLineString && $.isArray(coordinates[ 0 ][ 0 ]), isMultiPolygon = isMultiLineStringOrPolygon && $.isArray(coordinates[ 0 ][ 0 ][ 0 ]), result = [ ], i, j, k; if (!isMultiPolygon) { if (!isMultiLineStringOrPolygon) { if (!isMultiPointOrLineString) { coordinates = [ coordinates ]; } coordinates = [ coordinates ]; } coordinates = [ coordinates ]; } for ( i = 0; i < coordinates.length; i++ ) { result[ i ] = [ ]; for ( j = 0; j < coordinates[ i ].length; j++ ) { result[ i ][ j ] = [ ]; for ( k = 0; k < coordinates[ i ][ j ].length; k++ ) { result[ i ][ j ][ k ] = fromGeodeticPos(coordinates[ i ][ j ][ k ]); } } } return isMultiPolygon ? result : isMultiLineStringOrPolygon ? result[ 0 ] : isMultiPointOrLineString ? result[ 0 ][ 0 ] : result[ 0 ][ 0 ][ 0 ]; } }, toGeodeticPos: function (coordinate) { return [ (coordinate[ 0 ] / semiMajorAxis) * degreesPerRadian, (halfPi - 2 * Math.atan(1 / Math.exp(coordinate[ 1 ] / semiMajorAxis))) * degreesPerRadian ]; }, toGeodetic: function (coordinates) { if ( $.geo._isGeodetic( coordinates ) ) { return coordinates; } var isMultiPointOrLineString = $.isArray(coordinates[ 0 ]), toGeodeticPos = this.toGeodeticPos; if (!isMultiPointOrLineString && coordinates.length == 4) { // bbox var min = toGeodeticPos([ coordinates[ 0 ], coordinates[ 1 ] ]), max = toGeodeticPos([ coordinates[ 2 ], coordinates[ 3 ] ]); return [ min[ 0 ], min[ 1 ], max[ 0 ], max[ 1 ] ]; } else { // geometry var isMultiLineStringOrPolygon = isMultiPointOrLineString && $.isArray(coordinates[ 0 ][ 0 ]), isMultiPolygon = isMultiLineStringOrPolygon && $.isArray(coordinates[ 0 ][ 0 ][ 0 ]), result = [ ], i, j, k; if (!isMultiPolygon) { if (!isMultiLineStringOrPolygon) { if (!isMultiPointOrLineString) { coordinates = [ coordinates ]; } coordinates = [ coordinates ]; } coordinates = [ coordinates ]; } for ( i = 0; i < coordinates.length; i++ ) { result[ i ] = [ ]; for ( j = 0; j < coordinates[ i ].length; j++ ) { result[ i ][ j ] = [ ]; for ( k = 0; k < coordinates[ i ][ j ].length; k++ ) { result[ i ][ j ][ k ] = toGeodeticPos(coordinates[ i ][ j ][ k ]); } } } return isMultiPolygon ? result : isMultiLineStringOrPolygon ? result[ 0 ] : isMultiPointOrLineString ? result[ 0 ][ 0 ] : result[ 0 ][ 0 ][ 0 ]; } } }; }()), // // service types (defined in other files) // _serviceTypes: {} }; }(jQuery, this)); AppGeo-geo-f763e47/js/jquery.geo.tiled.js0000664000175000017500000003076612005347446017131 0ustar daviddavid(function ($, undefined) { $.geo._serviceTypes.tiled = (function () { return { create: function (map, serviceContainer, service, index) { var serviceState = $.data(service, "geoServiceState"); if ( !serviceState ) { serviceState = { loadCount: 0, reloadTiles: false }; var scHtml = '
    '; serviceContainer.append(scHtml); serviceState.serviceContainer = serviceContainer.children( ":last" ); $.data(service, "geoServiceState", serviceState); } return serviceState.serviceContainer; }, destroy: function (map, serviceContainer, service) { var serviceState = $.data(service, "geoServiceState"); serviceState.serviceContainer.remove(); $.removeData(service, "geoServiceState"); }, interactiveTransform: function ( map, service, center, pixelSize ) { //console.log( "tiled.interactiveTransform( " + center.join( ", " ) + ", " + pixelSize + ")" ); var serviceState = $.data( service, "geoServiceState" ), tilingScheme = map.options[ "tilingScheme" ]; if ( serviceState ) { this._cancelUnloaded( map, service ); serviceState.serviceContainer.children( ).each( function ( i ) { var $scaleContainer = $(this), scalePixelSize = $scaleContainer.data("pixelSize"), scaleRatio = scalePixelSize / pixelSize; if ( scalePixelSize > 0 ) { scaleRatio = Math.round(scaleRatio * 1000) / 1000; var oldMapCoord = $scaleContainer.data("scaleOrigin"), newPixelPoint = map._toPixel(oldMapCoord, center, pixelSize); $scaleContainer.css( { left: Math.round(newPixelPoint[0]) + "px", top: Math.round(newPixelPoint[1]) + "px", width: tilingScheme.tileWidth * scaleRatio, height: tilingScheme.tileHeight * scaleRatio } ); /* if ( $("body")[0].filters !== undefined ) { $scaleContainer.children().each( function ( i ) { $( this ).css( "filter", "progid:DXImageTransform.Microsoft.Matrix(FilterType=bilinear,M11=" + scaleRatio + ",M22=" + scaleRatio + ",sizingmethod='auto expand')" ); } ); } */ } }); } }, refresh: function (map, service, force) { //console.log( "tiled.refresh( " + map._center.join( ", " ) + ", " + map._pixelSize + ")" ); var serviceState = $.data( service, "geoServiceState" ); this._cancelUnloaded(map, service); if ( serviceState && force ) { // if hidden atm, we want to make sure we reload this service after it becomes visible serviceState.reloadTiles = true; } if ( serviceState && service && service.style.visibility === "visible" && !( serviceState.serviceContainer.is( ":hidden" ) ) ) { var bbox = map._getBbox(), pixelSize = map._pixelSize, serviceObj = this, $serviceContainer = serviceState.serviceContainer, contentBounds = map._getContentBounds(), mapWidth = contentBounds["width"], mapHeight = contentBounds["height"], image = map.options[ "axisLayout" ] === "image", ySign = image ? +1 : -1, tilingScheme = map.options["tilingScheme"], tileWidth = tilingScheme.tileWidth, tileHeight = tilingScheme.tileHeight, tileX = Math.floor((bbox[0] - tilingScheme.origin[0]) / (pixelSize * tileWidth)), tileY = Math.max( Math.floor( ( image ? bbox[1] - tilingScheme.origin[1] : tilingScheme.origin[1] - bbox[ 3 ] ) / (pixelSize * tileHeight) ), 0 ), tileX2 = Math.ceil((bbox[2] - tilingScheme.origin[0]) / (pixelSize * tileWidth)), tileY2 = Math.ceil( ( image ? bbox[3] - tilingScheme.origin[1] : tilingScheme.origin[1] - bbox[ 1 ] ) / (pixelSize * tileHeight) ), bboxMax = map._getBboxMax(), pixelSizeAtZero = map._getPixelSize(0), ratio = pixelSizeAtZero / pixelSize, fullXAtScale = Math.floor((bboxMax[0] - tilingScheme.origin[0]) / (pixelSizeAtZero * tileWidth)) * ratio, fullYAtScale = Math.floor((tilingScheme.origin[1] + ySign * bboxMax[3]) / (pixelSizeAtZero * tileHeight)) * ratio, fullXMinX = tilingScheme.origin[0] + (fullXAtScale * tileWidth) * pixelSize, fullYMinOrMaxY = tilingScheme.origin[1] + ySign * (fullYAtScale * tileHeight) * pixelSize, serviceLeft = Math.round((fullXMinX - bbox[0]) / pixelSize), serviceTop = Math.round( ( image ? fullYMinOrMaxY - bbox[1] : bbox[3] - fullYMinOrMaxY ) / pixelSize), scaleContainers = $serviceContainer.children().show(), scaleContainer = scaleContainers.filter("[data-pixel-size='" + pixelSize + "']").appendTo($serviceContainer), opacity = service.style.opacity, x, y, loadImageDeferredDone = function( url ) { // when a Deferred call is done, add the image to the map // a reference to the correct img element is on the Deferred object itself serviceObj._loadImage( $.data( this, "img" ), url, pixelSize, map, serviceState, opacity ); }, loadImageDeferredFail = function( ) { $.data( this, "img" ).remove( ); serviceState.loadCount--; map._requestComplete(); }; if (serviceState.reloadTiles) { scaleContainers.find("img").attr("data-dirty", "true"); } if (!scaleContainer.size()) { $serviceContainer.append("
    "); scaleContainer = $serviceContainer.children(":last").data("scaleOrigin", map._toMap( [ (serviceLeft % tileWidth), (serviceTop % tileHeight) ] ) ); } else { scaleContainer.css({ left: (serviceLeft % tileWidth) + "px", top: (serviceTop % tileHeight) + "px" }).data("scaleOrigin", map._toMap( [ (serviceLeft % tileWidth), (serviceTop % tileHeight) ] ) ); scaleContainer.children().each(function (i) { var $img = $(this), tile = $img.attr("data-tile").split(","); $img.css({ left: Math.round(((parseInt(tile[0], 10) - fullXAtScale) * 100) + (serviceLeft - (serviceLeft % tileWidth)) / tileWidth * 100) + "%", top: Math.round(((parseInt(tile[1], 10) - fullYAtScale) * 100) + (serviceTop - (serviceTop % tileHeight)) / tileHeight * 100) + "%" }); if (opacity < 1) { $img.fadeTo(0, opacity); } }); } for (x = tileX; x < tileX2; x++) { for (y = tileY; y < tileY2; y++) { var tileStr = "" + x + "," + y, $img = scaleContainer.children("[data-tile='" + tileStr + "']").removeAttr("data-dirty"); if ($img.size() === 0 || serviceState.reloadTiles) { var bottomLeft = [ tilingScheme.origin[0] + (x * tileWidth) * pixelSize, tilingScheme.origin[1] + ySign * (y * tileHeight) * pixelSize ], topRight = [ tilingScheme.origin[0] + ((x + 1) * tileWidth - 1) * pixelSize, tilingScheme.origin[1] + ySign * ((y + 1) * tileHeight - 1) * pixelSize ], tileBbox = [bottomLeft[0], bottomLeft[1], topRight[0], topRight[1]], urlProp = ( service.hasOwnProperty( "src" ) ? "src" : "getUrl" ), urlArgs = { bbox: tileBbox, width: tileWidth, height: tileHeight, zoom: map._getZoom(), tile: { row: y, column: x }, index: Math.abs(y + x) }, isFunc = $.isFunction( service[ urlProp ] ), imageUrl; if ( isFunc ) { imageUrl = service[ urlProp ]( urlArgs ); } else { $.templates( "geoSrc", service[ urlProp ] ); imageUrl = $.render[ "geoSrc" ]( urlArgs ); } serviceState.loadCount++; map._requestQueued(); if (serviceState.reloadTiles && $img.size() > 0) { $img.attr("src", imageUrl); } else { var imgMarkup = ""; scaleContainer.append(imgMarkup); $img = scaleContainer.children(":last"); } if ( typeof imageUrl === "string" ) { serviceObj._loadImage( $img, imageUrl, pixelSize, map, serviceState, opacity ); } else if ( imageUrl ) { // assume Deferred $.data( imageUrl, "img", $img ); imageUrl.done( loadImageDeferredDone ).fail( loadImageDeferredFail ); } else { $img.remove( ); } } } } scaleContainers.find("[data-dirty]").remove(); serviceState.reloadTiles = false; } }, resize: function (map, service) { }, opacity: function ( map, service ) { var serviceState = $.data( service, "geoServiceState" ); serviceState.serviceContainer.find( "img" ).stop( true ).fadeTo( "fast", service.style.opacity ); }, toggle: function ( map, service ) { var serviceState = $.data( service, "geoServiceState" ); serviceState.serviceContainer.css( "display", service.style.visibility === "visible" ? "block" : "none" ); }, _cancelUnloaded: function (map, service) { var serviceState = $.data( service, "geoServiceState" ); if (serviceState && serviceState.loadCount > 0) { serviceState.serviceContainer.find("img:hidden").remove(); while (serviceState.loadCount > 0) { serviceState.loadCount--; map._requestComplete(); } } }, _loadImage: function ( $img, url, pixelSize, map, serviceState, opacity ) { var serviceContainer = serviceState.serviceContainer; $img.load(function (e) { if (opacity < 1) { $(e.target).fadeTo(0, opacity); } else { $(e.target).show(); } serviceState.loadCount--; map._requestComplete(); if (serviceState.loadCount <= 0) { serviceContainer.children(":not([data-pixel-size='" + pixelSize + "'])").remove(); serviceState.loadCount = 0; } }).error(function (e) { $(e.target).remove(); serviceState.loadCount--; map._requestComplete(); if (serviceState.loadCount <= 0) { serviceContainer.children(":not([data-pixel-size='" + pixelSize + "'])").remove(); serviceState.loadCount = 0; } }).attr("src", url); } }; }()); }(jQuery)); AppGeo-geo-f763e47/js/jquery.geo.head.js0000664000175000017500000000141512005347446016716 0ustar daviddavid// excanvas // Copyright 2006 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* * AppGeo/geo * (c) 2007-2011, Applied Geographics, Inc. All rights reserved. * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license */ AppGeo-geo-f763e47/js/jquery.geo.geomap.js0000664000175000017500000023060012005347446017265 0ustar daviddavid(function ($, undefined) { var _widgetIdSeed = 0, _ieVersion = ( function () { var v = 5, div = document.createElement("div"), a = div.all || []; do { div.innerHTML = ""; } while ( a[0] ); return v > 6 ? v : !v; }() ), _defaultOptions = { bbox: [-180, -85, 180, 85], bboxMax: [-180, -85, 180, 85], center: [0, 0], cursors: { "static": "default", pan: "url(data:image/vnd.microsoft.icon;base64,AAACAAEAICACAAgACAAwAQAAFgAAACgAAAAgAAAAQAAAAAEAAQAAAAAAAAEAAAAAAAAAAAAAAgAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8AAAA/AAAAfwAAAP+AAAH/gAAB/8AAA//AAAd/wAAGf+AAAH9gAADbYAAA2yAAAZsAAAGbAAAAGAAAAAAAAA//////////////////////////////////////////////////////////////////////////////////////gH///4B///8Af//+AD///AA///wAH//4AB//8AAf//AAD//5AA///gAP//4AD//8AF///AB///5A////5///8=), move", zoom: "crosshair", dragBox: "crosshair", dragCircle: "crosshair", drawPoint: "crosshair", drawLineString: "crosshair", drawPolygon: "crosshair", measureLength: "crosshair", measureArea: "crosshair" }, measureLabels: { length: "{{:length.toFixed( 2 )}} m", area: "{{:area.toFixed( 2 )}} sq m" }, drawStyle: {}, shapeStyle: {}, mode: "pan", pannable: true, scroll: "default", shift: "default", services: [ { "class": "osm", type: "tiled", src: function (view) { return "http://otile" + ((view.index % 4) + 1) + ".mqcdn.com/tiles/1.0.0/osm/" + view.zoom + "/" + view.tile.column + "/" + view.tile.row + ".png"; }, attr: "Tiles Courtesy of MapQuest " } ], tilingScheme: { tileWidth: 256, tileHeight: 256, levels: 18, basePixelSize: 156543.03392799936, origin: [-20037508.342787, 20037508.342787] }, axisLayout: "map", zoom: 0, zoomMin: 0, zoomMax: Number.POSITIVE_INFINITY, pixelSize: 0 }; $.widget("geo.geomap", { // private widget members _$elem: undefined, //< map div for maps, service div for services _map: undefined, //< only defined in services _created: false, _createdGraphics: false, _widgetId: 0, _tmplLengthId: "", _tmplAreaId: "", _contentBounds: {}, _$resizeContainer: undefined, //< all elements that should match _contentBounds' size _$eventTarget: undefined, _$contentFrame: undefined, _$existingChildren: undefined, _$attrList: undefined, _$servicesContainer: undefined, _$shapesContainers: undefined, //< all shapesContainer divs (map only) _$panContainer: undefined, //< all non-service elements that move while panning _$shapesContainer: undefined, //< just "our" shapesContainer div (map & service) _$drawContainer: undefined, _$measureContainer: undefined, _$measureLabel: undefined, _dpi: 96, _currentServices: [], //< internal copy _center: undefined, _pixelSize: undefined, _centerMax: undefined, _pixelSizeMax: undefined, _userGeodetic: true, _centerInteractive: undefined, _pixelSizeInteractive: undefined, _timeoutInteractive: null, _triggerInteractive: false, _loadCount: 0, _wheelTimeout: null, _wheelLevel: 0, _zoomFactor: 2, //< determines what a zoom level means _fullZoomFactor: 2, //< interactiveScale factor needed to zoom a whole level _partialZoomFactor: 1.18920711500273, //< interactiveScale factor needed to zoom a fraction of a level (the fourth root of 2) _mouseDown: undefined, _inOp: undefined, _toolPan: undefined, _shiftDown: undefined, _anchor: undefined, _current: undefined, _downDate: undefined, _moveDate: undefined, _clickDate: undefined, _lastMove: undefined, _lastDrag: undefined, _windowHandler: null, _resizeTimeout: null, _panning: undefined, _velocity: undefined, _friction: undefined, _supportTouch: undefined, _softDblClick: undefined, _isTap: undefined, _isDbltap: undefined, _isMultiTouch: undefined, _multiTouchAnchor: [], //< TouchList _multiTouchAnchorBbox: undefined, //< bbox _multiTouchCurrentBbox: undefined, //< bbox _drawTimeout: null, //< used in drawPoint mode so we don't send two shape events on dbltap _drawPixels: [], //< an array of coordinate arrays for drawing lines & polygons, in pixel coordinates _drawCoords: [], _graphicShapes: [], //< an array of objects containing style object refs & GeoJSON object refs _initOptions: {}, _options: {}, options: $.extend({}, _defaultOptions), _createWidget: function (options, element) { this._$elem = $(element); if (this._$elem.is(".geo-service")) { this._graphicShapes = []; $.Widget.prototype._createWidget.apply(this, arguments); return; } this._widgetId = _widgetIdSeed++; this._tmplLengthId = "geoMeasureLength" + this._widgetId; this._tmplAreaId = "geoMeasureArea" + this._widgetId; this._$elem.addClass("geo-map").css( { webkitTransform: "translateZ(0)" } ); this._initOptions = options || {}; this._forcePosition(this._$elem); this._$elem.css("text-align", "left"); var size = this._findMapSize(); this._contentBounds = { x: parseInt(this._$elem.css("padding-left"), 10), y: parseInt(this._$elem.css("padding-top"), 10), width: size["width"], height: size["height"] }; this._createChildren(); this._center = [ 0, 0 ]; this._centerMax = [ 0, 0 ]; this._centerInteractive = [ 0, 0 ]; this.options["pixelSize"] = this._pixelSize = this._pixelSizeMax = 156543.03392799936; this._mouseDown = this._inOp = this._toolPan = this._shiftDown = this._panning = this._isTap = this._isDbltap = false; this._anchor = [ 0, 0 ]; this._current = [ 0, 0 ]; this._lastMove = [ 0, 0 ]; this._lastDrag = [ 0, 0 ]; this._velocity = [ 0, 0 ]; this._friction = [0.8, 0.8]; this._downDate = this._moveDate = this._clickDate = 0; this._drawPixels = []; this._drawCoords = []; this._graphicShapes = []; $.Widget.prototype._createWidget.apply(this, arguments); }, _create: function () { this._options = this.options; if (this._$elem.is(".geo-service")) { this._map = this._$elem.data( "geoMap" ); this._$elem.data( "geoService", this ); return; } this._map = this; this._supportTouch = "ontouchend" in document; this._softDblClick = this._supportTouch || _ieVersion == 7; var geomap = this, touchStartEvent = this._supportTouch ? "touchstart" : "mousedown", touchStopEvent = this._supportTouch ? "touchend touchcancel" : "mouseup", touchMoveEvent = this._supportTouch ? "touchmove" : "mousemove"; $(document).keydown($.proxy(this._document_keydown, this)); this._$eventTarget.dblclick($.proxy(this._eventTarget_dblclick, this)); this._$eventTarget.bind(touchStartEvent, $.proxy(this._eventTarget_touchstart, this)); var dragTarget = (this._$eventTarget[0].setCapture) ? this._$eventTarget : $(document); dragTarget.bind(touchMoveEvent, $.proxy(this._dragTarget_touchmove, this)); dragTarget.bind(touchStopEvent, $.proxy(this._dragTarget_touchstop, this)); this._$eventTarget.mousewheel($.proxy(this._eventTarget_mousewheel, this)); this._windowHandler = function () { if (geomap._resizeTimeout) { clearTimeout(geomap._resizeTimeout); } geomap._resizeTimeout = setTimeout(function () { if (geomap._created) { geomap._$elem.geomap( "resize", true ); } }, 500); }; $(window).resize(this._windowHandler); this._$drawContainer.geographics({ style: this._initOptions.drawStyle || {} }); this._options["drawStyle"] = this._$drawContainer.geographics("option", "style"); this._$shapesContainer.geographics( { style: this._initOptions.shapeStyle || { } } ); this._createdGraphics = true; this._options["shapeStyle"] = this._$shapesContainer.geographics("option", "style"); if (this._initOptions) { // always init tilingScheme right away, even if it's null if ( this._initOptions.tilingScheme !== undefined ) { this._setOption("tilingScheme", this._initOptions.tilingScheme || null, false); } if ( this._initOptions.services ) { // jQuery UI Widget Factory merges user services with our default, we want to clobber the default this._options[ "services" ] = $.merge( [ ], this._initOptions.services ); } if (this._initOptions.bboxMax) { this._setOption("bboxMax", this._initOptions.bboxMax, false); this._setOption("bbox", this._initOptions.bboxMax, false); } if (this._initOptions.zoomMin !== undefined) { this._setOption("zoomMin", this._initOptions.zoomMin, false); } if (this._initOptions.zoomMax !== undefined) { this._setOption("zoomMax", this._initOptions.zoomMax, false); } if (this._initOptions.bbox) { this._setOption("bbox", this._initOptions.bbox, false); } if (this._initOptions.center) { this._setOption("center", this._initOptions.center, false); } if (this._initOptions.zoom !== undefined) { this._setOption("zoom", this._initOptions.zoom, false); } } $.templates( this._tmplLengthId, this._options[ "measureLabels" ].length ); $.templates( this._tmplAreaId, this._options[ "measureLabels" ].area ); this._$eventTarget.css("cursor", this._options["cursors"][this._options["mode"]]); this._createServices(); this._refresh(); this._created = true; }, _setOption: function (key, value, refresh) { if ( key == "pixelSize" ) { return; } refresh = (refresh === undefined || refresh); if ( this._$elem.is( ".geo-map" ) ) { this._panFinalize(); } var center, pixelSize, bbox, zoom; switch (key) { case "bbox": if ( this._created ) { this._clearInteractiveTimeout( ); } this._userGeodetic = $.geo.proj && $.geo._isGeodetic( value ); if ( this._userGeodetic ) { value = $.geo.proj.fromGeodetic( value ); } center = [value[0] + (value[2] - value[0]) / 2, value[1] + (value[3] - value[1]) / 2]; pixelSize = Math.max($.geo.width(value, true) / this._contentBounds.width, $.geo.height(value, true) / this._contentBounds.height); // clamp to zoom zoom = this._getZoom( center, pixelSize ); if ( this._options[ "tilingScheme" ] ) { pixelSize = this._getPixelSize( Math.min( Math.max( zoom, this._options[ "zoomMin" ] ), this._options[ "zoomMax" ] ) ); } else { if ( zoom < this._options[ "zoomMin" ] ) { pixelSize = this._getPixelSize( this._options[ "zoomMin" ] ); } else if ( zoom > this._options[ "zoomMax" ] ) { pixelSize = this._getPixelSize( this._options[ "zoomMax" ] ); } } if ( this._created ) { this._setInteractiveCenterAndSize( center, pixelSize ); this._setInteractiveTimeout( false ); } else { this._setCenterAndSize( center, pixelSize, false, refresh ); } value = this._getBbox(); break; case "bboxMax": this._userGeodetic = $.geo.proj && $.geo._isGeodetic( value ); break; case "center": if ( this._created ) { this._clearInteractiveTimeout( ); } this._userGeodetic = $.geo.proj && $.geo._isGeodetic( value ); if ( this._userGeodetic ) { value = $.geo.proj.fromGeodetic( value ); } if ( this._created ) { this._setInteractiveCenterAndSize( value, this._pixelSize ); this._setInteractiveTimeout( false ); } else { this._setCenterAndSize( value, this._pixelSize, false, refresh ); } break; case "measureLabels": value = $.extend( this._options[ "measureLabels" ], value ); $.templates( this._tmplLengthId, this._options[ "measureLabels" ].length ); $.templates( this._tmplAreaId, this._options[ "measureLabels" ].area ); break; case "drawStyle": if (this._$drawContainer) { this._$drawContainer.geographics("option", "style", value); value = this._$drawContainer.geographics("option", "style"); } break; case "shapeStyle": if ( this._$elem.is( ".geo-service" ) && !this._createdGraphics ) { this._createServiceGraphics( ); } if ( this._createdGraphics ) { this._$shapesContainer.geographics("option", "style", value); value = this._$shapesContainer.geographics("option", "style"); } break; case "mode": this._resetDrawing( ); this._$eventTarget.css("cursor", this._options["cursors"][value]); break; case "zoom": if ( this._created ) { this._setZoom(value, false, refresh); } else { value = Math.max( value, 0 ); this._setCenterAndSize( this._center, this._getPixelSize( value ), false, refresh ); } break; } $.Widget.prototype._setOption.apply(this, arguments); switch ( key ) { case "bbox": case "center": if ( this._userGeodetic ) { this._options[ "bbox" ] = $.geo.proj.toGeodetic( this._options[ "bbox" ] ); this._options[ "center" ] = $.geo.proj.toGeodetic( this._center ); } break; case "tilingScheme": if ( value !== null ) { this._pixelSizeMax = this._getPixelSize( 0 ); this._centerMax = [ value.origin[ 0 ] + this._pixelSizeMax * value.tileWidth / 2, value.origin[ 1 ] + this._pixelSizeMax * value.tileHeight / 2 ]; } break; case "bboxMax": if ( $.geo.proj && $.geo._isGeodetic( value ) ) { bbox = $.geo.proj.fromGeodetic( value ); } else { bbox = value; } this._centerMax = $.geo.center( bbox ); this._pixelSizeMax = Math.max( $.geo.width( bbox, true ) / this._contentBounds.width, $.geo.height( bbox, true ) / this._contentBounds.height ); break; case "services": this._createServices(); if (refresh) { this._refresh(); } break; case "shapeStyle": if ( refresh && this._createdGraphics ) { this._$shapesContainer.geographics("clear"); this._refreshShapes( this._$shapesContainer, this._graphicShapes, this._graphicShapes, this._graphicShapes ); } break; } }, destroy: function () { if ( this._$elem.is(".geo-service") ) { if ( this._createdGraphics ) { this._$shapesContainer.geographics("destroy"); this._$shapesContainer = undefined; this._createdGraphics = false; } } else { clearTimeout( this._timeoutInteractive ); this._timeoutInteractive = null; this._created = false; $(window).unbind("resize", this._windowHandler); for ( var i = 0; i < this._currentServices.length; i++ ) { this._currentServices[ i ].serviceContainer.geomap("destroy"); $.geo["_serviceTypes"][this._currentServices[i].type].destroy(this, this._$servicesContainer, this._currentServices[i]); } this._$shapesContainer.geographics("destroy"); this._$shapesContainer = undefined; this._createdGraphics = false; this._$drawContainer.geographics("destroy"); this._$drawContainer = undefined; this._$existingChildren.detach(); this._$elem.html(""); this._$elem.append(this._$existingChildren); this._$elem.removeClass("geo-map"); } $.Widget.prototype.destroy.apply(this, arguments); }, toMap: function (p) { p = this._toMap(p); return this._userGeodetic ? $.geo.proj.toGeodetic(p) : p; }, toPixel: function ( p, _center /* Internal Use Only */, _pixelSize /* Internal Use Only */ ) { return this._toPixel( $.geo.proj ? $.geo.proj.fromGeodetic( p ) : p, _center, _pixelSize ); }, opacity: function ( value, _serviceContainer ) { if ( this._$elem.is( ".geo-service" ) ) { this._$elem.closest( ".geo-map" ).geomap( "opacity", value, this._$elem ); } else { if ( value >= 0 || value <= 1 ) { for ( var i = 0; i < this._currentServices.length; i++ ) { var service = this._currentServices[ i ]; if ( !_serviceContainer || service.serviceContainer[ 0 ] == _serviceContainer[ 0 ] ) { service.style.opacity = value; // update the original service object's style property service.serviceObject.style = $.extend( { }, service.serviceObject.style, service.style ); $.geo[ "_serviceTypes" ][ service.type ].opacity( this, service ); } } } } }, toggle: function ( value, _serviceContainer ) { if ( this._$elem.is( ".geo-service" ) ) { this._$elem.closest( ".geo-map" ).geomap( "toggle", value, this._$elem ); } else { for ( var i = 0; i < this._currentServices.length; i++ ) { var service = this._currentServices[ i ]; if ( !_serviceContainer || service.serviceContainer[ 0 ] == _serviceContainer[ 0 ] ) { if ( value === undefined ) { // toggle visibility value = ( service.style.visibility !== "visible" ); } service.style.visibility = ( value ? "visible" : "hidden" ); // update the original service object's style property service.serviceObject.style = $.extend( { }, service.serviceObject.style, service.style ); service.serviceContainer.toggle( value ); if ( value ) { $.geo[ "_serviceTypes" ][ service.type ].refresh( this, service ); } } } } }, zoom: function (numberOfLevels) { if (numberOfLevels !== null) { this._setZoom(this._options["zoom"] + numberOfLevels, false, true); } }, refresh: function ( force, _serviceContainer ) { if ( this._$elem.is( ".geo-service" ) ) { this._$elem.closest( ".geo-map" ).geomap( "refresh", force, this._$elem ); } else { this._refresh( force, _serviceContainer ); } }, resize: function ( _trigger /* Internal Use Only */ ) { var size = this._findMapSize(), dx = size["width"]/2 - this._contentBounds.width/2, dy = size["height"]/2 - this._contentBounds.height/2, i; this._contentBounds = { x: parseInt(this._$elem.css("padding-left"), 10), y: parseInt(this._$elem.css("padding-top"), 10), width: size["width"], height: size["height"] }; this._$resizeContainer.css( { width: size["width"], height: size["height"] } ); for (i = 0; i < this._currentServices.length; i++) { $.geo["_serviceTypes"][this._currentServices[i].type].resize(this, this._currentServices[i]); } this._$elem.find( ".geo-graphics" ).css( { width: size["width"], height: size["height"] }).geographics( "resize" ); for (i = 0; i < this._drawPixels.length; i++) { this._drawPixels[i][0] += dx; this._drawPixels[i][1] += dy; } this._setCenterAndSize(this._center, this._pixelSize, _trigger, true); }, append: function ( shape, style, label, refresh ) { if ( shape && ( $.isPlainObject( shape ) || ( $.isArray( shape ) && shape.length > 0 ) ) ) { if ( !this._createdGraphics ) { this._createServiceGraphics( ); } var shapes, arg, i, realStyle, realLabel, realRefresh; if ( $.isArray( shape ) ) { shapes = shape; } else if ( shape.type == "FeatureCollection" ) { shapes = shape.features; } else { shapes = [ shape ]; } for ( i = 1; i < arguments.length; i++ ) { arg = arguments[ i ]; if ( typeof arg === "object" ) { realStyle = arg; } else if ( typeof arg === "number" || typeof arg === "string" ) { realLabel = arg; } else if ( typeof arg === "boolean" ) { realRefresh = arg; } } for ( i = 0; i < shapes.length; i++ ) { if ( shapes[ i ].type != "Point" ) { var bbox = $.geo.bbox( shapes[ i ] ); if ( $.geo.proj && $.geo._isGeodetic( bbox ) ) { bbox = $.geo.proj.fromGeodetic( bbox ); } $.data( shapes[ i ], "geoBbox", bbox ); } this._graphicShapes.push( { shape: shapes[ i ], style: realStyle, label: realLabel } ); } if ( realRefresh === undefined || realRefresh ) { if ( this._$elem.is( ".geo-service" ) ) { this._refresh( false, this._$elem ); } else { this._refresh( ); } } } }, empty: function ( refresh ) { for ( var i = 0; i < this._graphicShapes.length; i++ ) { $.removeData( this._graphicShapes[ i ].shape, "geoBbox" ); } this._graphicShapes = []; if ( refresh === undefined || refresh ) { if ( this._$elem.is( ".geo-service" ) ) { this._refresh( false, this._$elem ); } else { this._refresh( ); } } }, find: function ( selector, pixelTolerance ) { var isPoint = $.isPlainObject( selector ), searchPixel = isPoint ? this._map.toPixel( selector.coordinates ) : undefined, mapTol = this._map._pixelSize * pixelTolerance, result = [], graphicShape, geometries, curGeom, i = 0; for ( ; i < this._graphicShapes.length; i++ ) { graphicShape = this._graphicShapes[ i ]; if ( isPoint ) { if ( graphicShape.shape.type == "Point" ) { if ( $.geo.distance( graphicShape.shape, selector ) <= mapTol ) { result.push( graphicShape.shape ); } } else { var bbox = $.data( graphicShape.shape, "geoBbox" ), bboxPolygon = { type: "Polygon", coordinates: [ [ [bbox[0], bbox[1]], [bbox[0], bbox[3]], [bbox[2], bbox[3]], [bbox[2], bbox[1]], [bbox[0], bbox[1]] ] ] }, projectedPoint = { type: "Point", coordinates: $.geo.proj && $.geo._isGeodetic( selector.coordinates ) ? $.geo.proj.fromGeodetic( selector.coordinates ) : selector.coordinates }; if ( $.geo.distance( bboxPolygon, projectedPoint, true ) <= mapTol ) { geometries = $.geo._flatten( graphicShape.shape ); for ( curGeom = 0; curGeom < geometries.length; curGeom++ ) { if ( $.geo.distance( geometries[ curGeom ], selector ) <= mapTol ) { result.push( graphicShape.shape ); break; } } } } } else { result.push( graphicShape.shape ); } } if ( this._$elem.is( ".geo-map" ) ) { this._$elem.find( ".geo-service" ).each( function( ) { result = $.merge( result, $( this ).geomap( "find", selector, pixelTolerance ) ); } ); } return result; }, remove: function ( shape, refresh ) { if ( shape && ( $.isPlainObject( shape ) || ( $.isArray( shape ) && shape.length > 0 ) ) ) { var shapes = $.isArray( shape ) ? shape : [ shape ], rest; for ( var i = 0; i < this._graphicShapes.length; i++ ) { if ( $.inArray( this._graphicShapes[ i ].shape, shapes ) >= 0 ) { $.removeData( shape, "geoBbox" ); rest = this._graphicShapes.slice( i + 1 ); this._graphicShapes.length = i; this._graphicShapes.push.apply( this._graphicShapes, rest ); i--; } } if ( refresh === undefined || refresh ) { if ( this._$elem.is( ".geo-service" ) ) { this._refresh( false, this._$elem ); } else { this._refresh( ); } } } }, _getBbox: function (center, pixelSize) { center = center || this._center; pixelSize = pixelSize || this._pixelSize; // calculate the internal bbox var halfWidth = this._contentBounds[ "width" ] / 2 * pixelSize, halfHeight = this._contentBounds[ "height" ] / 2 * pixelSize; return [ center[ 0 ] - halfWidth, center[ 1 ] - halfHeight, center[ 0 ] + halfWidth, center[ 1 ] + halfHeight ]; }, _setBbox: function (value, trigger, refresh) { var center = [value[0] + (value[2] - value[0]) / 2, value[1] + (value[3] - value[1]) / 2], pixelSize = Math.max($.geo.width(value, true) / this._contentBounds.width, $.geo.height(value, true) / this._contentBounds.height), zoom = this._getZoom( center, pixelSize ); // clamp to zoom if ( this._options[ "tilingScheme" ] ) { pixelSize = this._getPixelSize( Math.min( Math.max( zoom, this._options[ "zoomMin" ] ), this._options[ "zoomMax" ] ) ); } else { if ( zoom < this._options[ "zoomMin" ] ) { pixelSize = this._getPixelSize( this._options[ "zoomMin" ] ); } else if ( zoom > this._options[ "zoomMax" ] ) { pixelSize = this._getPixelSize( this._options[ "zoomMax" ] ); } } this._setInteractiveCenterAndSize( center, pixelSize ); this._interactiveTransform( ); }, _getBboxMax: function () { // calculate the internal bboxMax var halfWidth = this._contentBounds["width"] / 2 * this._pixelSizeMax, halfHeight = this._contentBounds["height"] / 2 * this._pixelSizeMax; return [this._centerMax[0] - halfWidth, this._centerMax[1] - halfHeight, this._centerMax[0] + halfWidth, this._centerMax[1] + halfHeight]; }, _getCenter: function () { return this._center; }, _getContentBounds: function () { return this._contentBounds; }, _getServicesContainer: function () { return this._$servicesContainer; }, _getZoom: function ( center, pixelSize ) { // calculate the internal zoom level, vs. public zoom property // this does not take zoomMin or zoomMax into account center = center || this._center; pixelSize = pixelSize || this._pixelSize; var tilingScheme = this._options["tilingScheme"]; if ( tilingScheme ) { if ( tilingScheme.pixelSizes ) { var roundedPixelSize = Math.floor(pixelSize * 1000), levels = tilingScheme.pixelSizes.length, i = levels - 1; for ( ; i >= 0; i-- ) { if ( Math.floor( tilingScheme.pixelSizes[ i ] * 1000 ) >= roundedPixelSize ) { return i; } } return 0; } else { return Math.round( Math.log( tilingScheme.basePixelSize / pixelSize) / Math.log( 2 ) ); } } else { var ratio = this._contentBounds["width"] / this._contentBounds["height"], bbox = $.geo.reaspect( this._getBbox( center, pixelSize ), ratio, true ), bboxMax = $.geo.reaspect(this._getBboxMax(), ratio, true); return Math.round( Math.log($.geo.width(bboxMax, true) / $.geo.width(bbox, true)) / Math.log(this._zoomFactor) ); } }, _setZoom: function ( value, trigger, refresh ) { // set the map widget's zoom, taking zoomMin and zoomMax into account this._clearInteractiveTimeout( ); value = Math.min( Math.max( value, this._options[ "zoomMin" ] ), this._options[ "zoomMax" ] ); this._setInteractiveCenterAndSize( this._center, this._getPixelSize( value ) ); this._interactiveTransform( ); this._setInteractiveTimeout( trigger ); }, _createChildren: function () { this._$existingChildren = this._$elem.children(); this._forcePosition(this._$existingChildren); this._$existingChildren.detach().css( { mozUserSelect: "none" } ); var contentSizeCss = "width:" + this._contentBounds["width"] + "px; height:" + this._contentBounds["height"] + "px; margin:0; padding:0;", contentPosCss = "position:absolute; left:0; top:0;"; this._$elem.prepend('
    '); this._$eventTarget = this._$contentFrame = this._$elem.children(':first'); this._$contentFrame.append('
    '); this._$servicesContainer = this._$contentFrame.children(':last'); this._$contentFrame.append('
    '); this._$shapesContainer = this._$contentFrame.children(':last'); this._$contentFrame.append( '' ); this._$attrList = this._$contentFrame.children( ":last" ); this._$contentFrame.append('
    '); this._$drawContainer = this._$contentFrame.children(':last'); this._$contentFrame.append('
    '); this._$measureContainer = this._$contentFrame.children(':last'); this._$measureLabel = this._$measureContainer.children(); this._$panContainer = $( [ this._$shapesContainer[ 0 ], this._$drawContainer[ 0 ], this._$measureContainer[ 0 ] ] ); this._$resizeContainer = $( [ this._$contentFrame[ 0 ], this._$servicesContainer[ 0 ], this._$eventTarget[ 0 ], this._$measureContainer[ 0 ] ] ); this._$contentFrame.append(this._$existingChildren); if ( ! $("#geo-measure-style").length ) { $("head").prepend( '' ); } }, _createServices: function () { var service, i; for ( i = 0; i < this._currentServices.length; i++ ) { this._currentServices[ i ].serviceContainer.geomap( "destroy" ); $.geo[ "_serviceTypes" ][ this._currentServices[ i ].type ].destroy( this, this._$servicesContainer, this._currentServices[ i ] ); } this._currentServices = [ ]; this._$servicesContainer.html( "" ); this._$attrList.html( "" ); for ( i = 0; i < this._options[ "services" ].length; i++ ) { service = this._currentServices[ i ] = $.extend( { }, this._options[ "services" ][ i ] ); // keep a reference to the original service.serviceObject = this._options[ "services" ][ i ]; // default the service style property on our copy service.style = $.extend( { visibility: "visible", opacity: 1 }, service.style ); var idString = service.id ? ' id="' + service.id + '"' : "", classString = 'class="geo-service ' + ( service["class"] ? service["class"] : '' ) + '"', scHtml = '
    ', servicesContainer; this._$servicesContainer.append( scHtml ); serviceContainer = this._$servicesContainer.children( ":last" ); service.serviceContainer = serviceContainer; $.geo[ "_serviceTypes" ][ service.type ].create( this, serviceContainer, service, i ); serviceContainer.data( "geoMap", this ).geomap(); if ( service.attr ) { this._$attrList.append( '
  1. ' + service.attr + '
  2. ' ); } } // start with our map-level shapesContainer this._$shapesContainers = this._$shapesContainer; this._$attrList.find( "a" ).css( { position: "relative", zIndex: 100 } ); }, _createServiceGraphics: function( ) { // only called in the context of a service-level geomap var $contentFrame = this._$elem.closest( ".geo-content-frame" ); this._$elem.append('
    '); this._$shapesContainer = this._$elem.children(':last'); this._map._$shapesContainers = this._map._$shapesContainers.add( this._$shapesContainer ); this._$shapesContainer.geographics( ); this._createdGraphics = true; this._options["shapeStyle"] = this._$shapesContainer.geographics("option", "style"); }, _refreshDrawing: function ( ) { this._$drawContainer.geographics("clear"); if ( this._drawPixels.length > 0 ) { var mode = this._options[ "mode" ], pixels = this._drawPixels, coords = this._drawCoords, label, labelShape, labelPixel, widthOver, heightOver; switch ( mode ) { case "measureLength": mode = "drawLineString"; labelShape = { type: "LineString", coordinates: coords }; label = $.render[ this._tmplLengthId ]( { length: $.geo.length( labelShape, true ) } ); labelPixel = $.merge( [], pixels[ pixels.length - 1 ] ); break; case "measureArea": mode = "drawPolygon"; labelShape = { type: "Polygon", coordinates: [ $.merge( [ ], coords ) ] }; labelShape.coordinates[ 0 ].push( coords[ 0 ] ); label = $.render[ this._tmplAreaId ]( { area: $.geo.area( labelShape, true ) } ); labelPixel = this._toPixel( $.geo.centroid( labelShape ).coordinates ); pixels = [ pixels ]; break; case "drawPolygon": pixels = [ pixels ]; break; } this._$drawContainer.geographics( mode, pixels ); if ( label ) { this._$measureLabel.html( label ); widthOver = this._contentBounds.width - ( this._$measureLabel.outerWidth( true ) + labelPixel[ 0 ] ); heightOver = this._contentBounds.height - ( this._$measureLabel.outerHeight( true ) + labelPixel[ 1 ] ); if ( widthOver < 0 ) { labelPixel[ 0 ] += widthOver; } if ( heightOver < 0 ) { labelPixel[ 1 ] += heightOver; } this._$measureLabel.css( { left: Math.max( labelPixel[ 0 ], 0 ), top: Math.max( labelPixel[ 1 ], 0 ) } ).show(); } } }, _resetDrawing: function () { this._drawPixels = []; this._drawCoords = []; this._$drawContainer.geographics("clear"); this._$measureLabel.hide(); }, _refreshShapes: function (geographics, shapes, styles, labels, center, pixelSize) { var i, mgi, shape, shapeBbox, style, label, hasLabel, labelPixel, bbox = this._map._getBbox(center, pixelSize); for (i = 0; i < shapes.length; i++) { shape = shapes[i].shape || shapes[i]; shape = shape.geometry || shape; shapeBbox = $.data(shape, "geoBbox"); if ( shapeBbox && $.geo._bboxDisjoint( bbox, shapeBbox ) ) { continue; } style = $.isArray(styles) ? styles[i].style : styles; label = $.isArray(labels) ? labels[i].label : labels; hasLabel = ( label !== undefined ); labelPixel = undefined; switch (shape.type) { case "Point": labelPixel = this._map.toPixel( shape.coordinates, center, pixelSize ); this._$shapesContainer.geographics("drawPoint", labelPixel, style); break; case "LineString": this._$shapesContainer.geographics("drawLineString", this._map.toPixel(shape.coordinates, center, pixelSize), style); if ( hasLabel ) { labelPixel = this._map.toPixel( $.geo.pointAlong( shape, 0.5 ).coordinates, center, pixelSize ); } break; case "Polygon": this._$shapesContainer.geographics("drawPolygon", this._map.toPixel(shape.coordinates, center, pixelSize), style); if ( hasLabel ) { labelPixel = this._map.toPixel( $.geo.centroid( shape ).coordinates, center, pixelSize ); } break; case "MultiPoint": for (mgi = 0; mgi < shape.coordinates.length; mgi++) { this._$shapesContainer.geographics("drawPoint", this._map.toPixel(shape.coordinates[mgi], center, pixelSize), style); } if ( hasLabel ) { labelPixel = this._map.toPixel( $.geo.centroid( shape ).coordinates, center, pixelSize ); } break; case "MultiLineString": for (mgi = 0; mgi < shape.coordinates.length; mgi++) { this._$shapesContainer.geographics("drawLineString", this._map.toPixel(shape.coordinates[mgi], center, pixelSize), style); } if ( hasLabel ) { labelPixel = this._map.toPixel( $.geo.centroid( shape ).coordinates, center, pixelSize ); } break; case "MultiPolygon": for (mgi = 0; mgi < shape.coordinates.length; mgi++) { this._$shapesContainer.geographics("drawPolygon", this._map.toPixel(shape.coordinates[mgi], center, pixelSize), style); } if ( hasLabel ) { labelPixel = this._map.toPixel( $.geo.centroid( shape ).coordinates, center, pixelSize ); } break; case "GeometryCollection": this._refreshShapes(geographics, shape.geometries, style, label, center, pixelSize); break; } if ( hasLabel && labelPixel ) { this._$shapesContainer.geographics( "drawLabel", labelPixel, label ); } } }, _findMapSize: function () { // really, really attempt to find a size for this thing // even if it's hidden (look at parents) var size = { width: 0, height: 0 }, sizeContainer = this._$elem; while (sizeContainer.size() && !(size["width"] > 0 && size["height"] > 0)) { size = { width: sizeContainer.width(), height: sizeContainer.height() }; if (size["width"] <= 0 || size["height"] <= 0) { size = { width: parseInt(sizeContainer.css("width"), 10), height: parseInt(sizeContainer.css("height"), 10) }; } sizeContainer = sizeContainer.parent(); } return size; }, _forcePosition: function (elem) { var cssPosition = elem.css("position"); if (cssPosition != "relative" && cssPosition != "absolute" && cssPosition != "fixed") { elem.css("position", "relative"); } }, _getPixelSize: function ( zoom ) { var tilingScheme = this._options["tilingScheme"]; if (tilingScheme !== null) { if (zoom === 0) { return tilingScheme.pixelSizes ? tilingScheme.pixelSizes[0] : tilingScheme.basePixelSize; } zoom = Math.round(zoom); zoom = Math.max(zoom, 0); var levels = tilingScheme.pixelSizes ? tilingScheme.pixelSizes.length : tilingScheme.levels; zoom = Math.min(zoom, levels - 1); if ( tilingScheme.pixelSizes ) { return tilingScheme.pixelSizes[zoom]; } else { return tilingScheme.basePixelSize / Math.pow(2, zoom); } } else { var bbox = $.geo.scaleBy( this._getBboxMax(), 1 / Math.pow( this._zoomFactor, zoom ), true ); return Math.max( $.geo.width( bbox, true ) / this._contentBounds.width, $.geo.height( bbox, true ) / this._contentBounds.height ); } }, _getZoomCenterAndSize: function ( anchor, zoomDelta, full ) { var zoomFactor = ( full ? this._fullZoomFactor : this._partialZoomFactor ), scale = Math.pow( zoomFactor, -zoomDelta ), pixelSize = this._pixelSizeInteractive * scale, zoom = this._getZoom(this._centerInteractive, pixelSize); // clamp to zoom if ( full && this._options[ "tilingScheme" ] ) { pixelSize = this._getPixelSize( Math.min( Math.max( zoom, this._options[ "zoomMin" ] ), this._options[ "zoomMax" ] ) ); } else { if ( zoomDelta < 0 && zoom < this._options[ "zoomMin" ] ) { pixelSize = this._pixelSizeInteractive; } else if ( zoomDelta > 0 && zoom > this._options[ "zoomMax" ] ) { pixelSize = this._pixelSizeInteractive; } } var ratio = pixelSize / this._pixelSizeInteractive, anchorMapCoord = this._toMap( anchor, this._centerInteractive, this._pixelSizeInteractive ), centerDelta = [(this._centerInteractive[0] - anchorMapCoord[0]) * ratio, (this._centerInteractive[1] - anchorMapCoord[1]) * ratio], scaleCenter = [anchorMapCoord[0] + centerDelta[0], anchorMapCoord[1] + centerDelta[1]]; return { pixelSize: pixelSize, center: scaleCenter }; }, _mouseWheelFinish: function ( refresh ) { this._wheelTimeout = null; if (this._wheelLevel !== 0) { var wheelCenterAndSize = this._getZoomCenterAndSize( this._anchor, this._wheelLevel, this._options[ "tilingScheme" ] !== null ); this._wheelLevel = 0; } else if ( refresh ) { this._refresh(); } }, _panFinalize: function () { if (this._panning) { this._velocity = [0, 0]; var dx = this._current[0] - this._anchor[0], dy = this._current[1] - this._anchor[1], image = this._options[ "axisLayout" ] === "image", dxMap = -dx * this._pixelSize, dyMap = ( image ? -1 : 1 ) * dy * this._pixelSize; this._$eventTarget.css("cursor", this._options["cursors"][this._options["mode"]]); this._inOp = false; this._anchor = this._current; this._mouseDown = this._toolPan = this._panning = false; } }, _panMove: function () { if ( ! this._options[ "pannable" ] ) { return; } var dx = this._current[0] - this._lastDrag[0], dy = this._current[1] - this._lastDrag[1], i = 0, service, translateObj; if (this._toolPan || dx > 3 || dx < -3 || dy > 3 || dy < -3) { if (!this._toolPan) { this._toolPan = true; this._$eventTarget.css("cursor", this._options["cursors"]["pan"]); } if (this._mouseDown) { this._velocity = [dx, dy]; } if (dx !== 0 || dy !== 0) { this._panning = true; this._lastDrag = this._current; this._centerInteractive[ 0 ] -= ( dx * this._pixelSizeInteractive ); this._centerInteractive[ 1 ] += ( ( this._options[ "axisLayout" ] === "image" ? -1 : 1 ) * dy * this._pixelSizeInteractive ); this._setInteractiveCenterAndSize( this._centerInteractive, this._pixelSizeInteractive ); this._interactiveTransform( ); } } }, _clearInteractiveTimeout: function() { if ( this._timeoutInteractive ) { clearTimeout( this._timeoutInteractive ); this._timeoutInteractive = null; return true; } else { this._centerInteractive[ 0 ] = this._center[ 0 ]; this._centerInteractive[ 1 ] = this._center[ 1 ]; this._pixelSizeInteractive = this._pixelSize; return false; } }, _interactiveTransform: function( ) { if ( this._$shapesContainers ) { this._$shapesContainers.geographics("clear"); } for ( var i = 0; i < this._currentServices.length; i++ ) { service = this._currentServices[ i ]; $.geo[ "_serviceTypes" ][ service.type ].interactiveTransform( this, service, this._centerInteractive, this._pixelSizeInteractive ); } if (this._drawCoords.length > 0) { this._drawPixels = this._toPixel( this._drawCoords, this._centerInteractive, this._pixelSizeInteractive ); this._refreshDrawing(); } }, _setInteractiveTimeout: function( trigger ) { var geomap = this; function interactiveTimeoutCallback( ) { if ( geomap._isMultiTouch ) { geomap._timeoutInteractive = setTimeout( interactiveTimeoutCallback, 128 ); } else if ( geomap._created && geomap._timeoutInteractive ) { geomap._setCenterAndSize( geomap._centerInteractive, geomap._pixelSizeInteractive, geomap._triggerInteractive, true ); geomap._timeoutInteractive = null; geomap._triggerInteractive = false; } } this._timeoutInteractive = setTimeout( interactiveTimeoutCallback, 128 ); this._triggerInteractive |= trigger; }, _refresh: function ( force, _serviceContainer ) { var service, geoService, i = 0; for ( ; i < this._currentServices.length; i++ ) { service = this._currentServices[ i ]; if ( !_serviceContainer || service.serviceContainer[ 0 ] == _serviceContainer[ 0 ] ) { $.geo[ "_serviceTypes" ][ service.type ].refresh( this, service, force ); geoService = service.serviceContainer.data( "geoService" ); if ( geoService._createdGraphics ) { geoService._$shapesContainer.geographics( "clear" ); if ( geoService._graphicShapes.length > 0 ) { geoService._refreshShapes( geoService._$shapesContainer, geoService._graphicShapes, geoService._graphicShapes, geoService._graphicShapes ); } } } } if ( this._createdGraphics ) { this._$shapesContainer.geographics( "clear" ); if ( this._graphicShapes.length > 0 ) { this._refreshShapes( this._$shapesContainer, this._graphicShapes, this._graphicShapes, this._graphicShapes ); } } }, _setInteractiveCenterAndSize: function ( center, pixelSize ) { // set the temporary (interactive) center & size // also, update the public-facing options // this does not take zoomMin or zoomMax into account this._centerInteractive[ 0 ] = center[ 0 ]; this._centerInteractive[ 1 ] = center[ 1 ]; this._pixelSizeInteractive = pixelSize; if ( this._userGeodetic ) { this._options["bbox"] = $.geo.proj.toGeodetic( this._getBbox( center, pixelSize ) ); this._options["center"] = $.geo.proj.toGeodetic( center ); } else { this._options["bbox"] = this._getBbox( center, pixelSize ); this._options["center"][ 0 ] = center[ 0 ]; this._options["center"][ 1 ] = center[ 1 ]; } this._options["pixelSize"] = pixelSize; this._options["zoom"] = this._getZoom( center, pixelSize ); }, _setCenterAndSize: function (center, pixelSize, trigger, refresh) { if ( ! $.isArray( center ) || center.length != 2 || typeof center[ 0 ] !== "number" || typeof center[ 1 ] !== "number" ) { return; } // the final call during any extent change // only called by timeoutInteractive & resize // clamp to zoom var zoom = this._getZoom( center, pixelSize ); if ( this._options[ "tilingScheme" ] ) { this._pixelSizeInteractive = pixelSize = this._getPixelSize( Math.min( Math.max( zoom, this._options[ "zoomMin" ] ), this._options[ "zoomMax" ] ) ); } else { if ( zoom < this._options[ "zoomMin" ] ) { this._pixelSizeInteractive = pixelSize = this._getPixelSize( this._options[ "zoomMin" ] ); } else if ( zoom > this._options[ "zoomMax" ] ) { this._pixelSizeInteractive = pixelSize = this._getPixelSize( this._options[ "zoomMax" ] ); } } this._center[ 0 ] = center[ 0 ]; this._center[ 1 ] = center[ 1 ]; this._options["pixelSize"] = this._pixelSize = pixelSize; if ( this._userGeodetic ) { this._options["bbox"] = $.geo.proj.toGeodetic( this._getBbox() ); this._options["center"] = $.geo.proj.toGeodetic( this._center ); } else { this._options["bbox"] = this._getBbox(); this._options["center"] = $.merge( [ ], center ); } this._options["zoom"] = zoom; if (trigger) { this._trigger("bboxchange", window.event, { bbox: $.merge( [ ], this._options["bbox"] ) }); } if (refresh) { this._refresh(); this._refreshDrawing(); } }, _requestQueued: function ( ) { if ( this._loadCount === 0 ) { this._trigger( "loadstart", window.event ); } this._loadCount++; }, _requestComplete: function ( ) { this._loadCount--; if ( this._loadCount <= 0 ) { this._loadCount = 0; this._trigger( "loadend", window.event ); } }, _toMap: function (p, center, pixelSize) { // ignores $.geo.proj center = center || this._center; pixelSize = pixelSize || this._pixelSize; var isMultiPointOrLineString = $.isArray( p[ 0 ] ), isMultiLineStringOrPolygon = isMultiPointOrLineString && $.isArray( p[ 0 ][ 0 ] ), isMultiPolygon = isMultiLineStringOrPolygon && $.isArray( p[ 0 ][ 0 ][ 0 ] ), width = this._contentBounds["width"], height = this._contentBounds["height"], halfWidth = width / 2 * pixelSize, halfHeight = height / 2 * pixelSize, bbox = [center[0] - halfWidth, center[1] - halfHeight, center[0] + halfWidth, center[1] + halfHeight], xRatio = $.geo.width(bbox, true) / width, yRatio = $.geo.height(bbox, true) / height, yOffset, image = this._options[ "axisLayout" ] === "image", result = [], i, j, k; if ( !isMultiPolygon ) { if ( !isMultiLineStringOrPolygon ) { if ( !isMultiPointOrLineString ) { p = [ p ]; } p = [ p ]; } p = [ p ]; } for ( i = 0; i < p.length; i++ ) { result[ i ] = [ ]; for ( j = 0; j < p[ i ].length; j++ ) { result[ i ][ j ] = [ ]; for ( k = 0; k < p[ i ][ j ].length; k++ ) { yOffset = (p[ i ][ j ][ k ][1] * yRatio); result[ i ][ j ][ k ] = [ bbox[ 0 ] + ( p[ i ][ j ][ k ][ 0 ] * xRatio ), image ? bbox[ 1 ] + yOffset : bbox[ 3 ] - yOffset ]; } } } return isMultiPolygon ? result : isMultiLineStringOrPolygon ? result[ 0 ] : isMultiPointOrLineString ? result[ 0 ][ 0 ] : result[ 0 ][ 0 ][ 0 ]; }, _toPixel: function (p, center, pixelSize) { // ignores $.geo.proj center = center || this._center; pixelSize = pixelSize || this._pixelSize; var isMultiPointOrLineString = $.isArray( p[ 0 ] ), isMultiLineStringOrPolygon = isMultiPointOrLineString && $.isArray( p[ 0 ][ 0 ] ), isMultiPolygon = isMultiLineStringOrPolygon && $.isArray( p[ 0 ][ 0 ][ 0 ] ), width = this._contentBounds["width"], height = this._contentBounds["height"], halfWidth = width / 2 * pixelSize, halfHeight = height / 2 * pixelSize, bbox = [center[0] - halfWidth, center[1] - halfHeight, center[0] + halfWidth, center[1] + halfHeight], bboxWidth = $.geo.width(bbox, true), bboxHeight = $.geo.height(bbox, true), image = this._options[ "axisLayout" ] === "image", xRatio = width / bboxWidth, yRatio = height / bboxHeight, result = [ ], i, j, k; if ( !isMultiPolygon ) { if ( !isMultiLineStringOrPolygon ) { if ( !isMultiPointOrLineString ) { p = [ p ]; } p = [ p ]; } p = [ p ]; } for ( i = 0; i < p.length; i++ ) { result[ i ] = [ ]; for ( j = 0; j < p[ i ].length; j++ ) { result[ i ][ j ] = [ ]; for ( k = 0; k < p[ i ][ j ].length; k++ ) { result[ i ][ j ][ k ] = [ Math.round( ( p[ i ][ j ][ k ][ 0 ] - bbox[ 0 ] ) * xRatio ), Math.round( ( image ? p[ i ][ j ][ k ][ 1 ] - bbox[ 1 ] : bbox[ 3 ] - p[ i ][ j ][ k ][ 1 ] ) * yRatio ) ]; } } } return isMultiPolygon ? result : isMultiLineStringOrPolygon ? result[ 0 ] : isMultiPointOrLineString ? result[ 0 ][ 0 ] : result[ 0 ][ 0 ][ 0 ]; }, _document_keydown: function (e) { var len = this._drawCoords.length; if (len > 0 && e.which == 27) { if (len <= 2) { this._resetDrawing(); this._inOp = false; } else { this._drawCoords[len - 2] = $.merge( [], this._drawCoords[ len - 1 ] ); this._drawPixels[len - 2] = $.merge( [], this._drawPixels[ len - 1 ] ); this._drawCoords.length--; this._drawPixels.length--; this._refreshDrawing(); } } }, _eventTarget_dblclick_zoom: function(e) { var doInteractiveTimeout = this._clearInteractiveTimeout( ); this._trigger("dblclick", e, { type: "Point", coordinates: this._toMap(this._current, this._centerInteractive, this._pixelSizeInteractive ) }); if (!e.isDefaultPrevented()) { var centerAndSize = this._getZoomCenterAndSize(this._current, 1, true ); this._setInteractiveCenterAndSize( centerAndSize.center, centerAndSize.pixelSize ); this._interactiveTransform( ); doInteractiveTimeout = true; } if ( doInteractiveTimeout ) { this._setInteractiveTimeout( true ); } }, _eventTarget_dblclick: function (e) { if ( this._options[ "mode" ] === "static" ) { return; } if (this._drawTimeout) { window.clearTimeout(this._drawTimeout); this._drawTimeout = null; } var offset = $(e.currentTarget).offset(); switch (this._options["mode"]) { case "drawLineString": case "measureLength": if ( this._drawCoords.length > 1 && ! ( this._drawCoords[0][0] == this._drawCoords[1][0] && this._drawCoords[0][1] == this._drawCoords[1][1] ) ) { this._drawCoords.length--; this._trigger( "shape", e, { type: "LineString", coordinates: this._userGeodetic ? $.geo.proj.toGeodetic(this._drawCoords) : this._drawCoords } ); } else { this._eventTarget_dblclick_zoom(e); } this._resetDrawing(); break; case "drawPolygon": case "measureArea": if ( this._drawCoords.length > 1 && ! ( this._drawCoords[0][0] == this._drawCoords[1][0] && this._drawCoords[0][1] == this._drawCoords[1][1] ) ) { var endIndex = this._drawCoords.length - 1; if (endIndex > 2) { this._drawCoords[endIndex] = $.merge( [], this._drawCoords[0] ); this._trigger( "shape", e, { type: "Polygon", coordinates: [ this._userGeodetic ? $.geo.proj.toGeodetic(this._drawCoords) : this._drawCoords ] } ); } } else { this._eventTarget_dblclick_zoom(e); } this._resetDrawing(); break; default: this._eventTarget_dblclick_zoom(e); break; } this._inOp = false; }, _eventTarget_touchstart: function (e) { var mode = this._options[ "mode" ], shift = this._options[ "shift" ]; if ( mode === "static" ) { return; } if ( !this._supportTouch && e.which != 1 ) { return; } var doInteractiveTimeout = this._clearInteractiveTimeout( ); var offset = $(e.currentTarget).offset(), touches = e.originalEvent.changedTouches; if ( this._supportTouch ) { this._multiTouchAnchor = $.merge( [ ], touches ); this._isMultiTouch = this._multiTouchAnchor.length > 1; if ( this._isMultiTouch ) { this._multiTouchCurrentBbox = [ touches[0].pageX - offset.left, touches[0].pageY - offset.top, touches[1].pageX - offset.left, touches[1].pageY - offset.top ]; this._multiTouchAnchorBbox = $.merge( [ ], this._multiTouchCurrentBbox ); this._current = $.geo.center( this._multiTouchCurrentBbox, true ); } else { this._multiTouchCurrentBbox = [ touches[0].pageX - offset.left, touches[0].pageY - offset.top, NaN, NaN ]; this._current = [ touches[0].pageX - offset.left, touches[0].pageY - offset.top ]; } } else { this._current = [e.pageX - offset.left, e.pageY - offset.top]; } if (this._softDblClick) { var downDate = $.now(); if (downDate - this._downDate < 750) { if (this._isTap) { var dx = this._current[0] - this._anchor[0], dy = this._current[1] - this._anchor[1], distance = Math.sqrt((dx * dx) + (dy * dy)); if (distance > 8) { this._isTap = false; } else { this._current = $.merge( [ ], this._anchor ); } } if (this._isDbltap) { this._isDbltap = false; } else { this._isDbltap = this._isTap; } } else { this._isDbltap = false; } this._isTap = true; this._downDate = downDate; } this._mouseDown = true; this._anchor = $.merge( [ ], this._current ); if (!this._inOp && e.shiftKey && shift !== "off") { this._shiftDown = true; this._$eventTarget.css( "cursor", this._options[ "cursors" ][ shift === "default" ? "zoom" : shift ] ); } else if ( !this._isMultiTouch && ( this._options[ "pannable" ] || mode === "dragBox" || mode === "dragCircle" ) ) { this._inOp = true; if ( mode !== "zoom" && mode !== "dragBox" && mode !== "dragCircle" ) { this._lastDrag = this._current; if (e.currentTarget.setCapture) { e.currentTarget.setCapture(); } } } e.preventDefault(); if ( doInteractiveTimeout ) { this._setInteractiveTimeout( true ); } return false; }, _dragTarget_touchmove: function (e) { if ( this._options[ "mode" ] === "static" ) { return; } var doInteractiveTimeout = false; if ( this._mouseDown ) { doInteractiveTimeout = this._clearInteractiveTimeout( ); } var offset = this._$eventTarget.offset(), drawCoordsLen = this._drawCoords.length, touches = e.originalEvent.changedTouches, current, service, i = 0; if ( this._supportTouch ) { if ( !this._isMultiTouch && this._mouseDown && this._multiTouchAnchor.length > 0 && touches[ 0 ].identifier !== this._multiTouchAnchor[ 0 ].identifier ) { // switch to multitouch this._mouseDown = false; this._isMultiTouch = true; this._wheelLevel = 0; this._multiTouchAnchor.push( touches[ 0 ] ); this._multiTouchCurrentBbox = [ this._multiTouchCurrentBbox[ 0 ], this._multiTouchCurrentBbox[ 1 ], this._multiTouchAnchor[1].pageX - offset.left, this._multiTouchAnchor[1].pageY - offset.top ]; this._multiTouchAnchorBbox = $.merge( [ ], this._multiTouchCurrentBbox ); this._mouseDown = true; this._anchor = this._current = $.geo.center( this._multiTouchCurrentBbox, true ); if ( doInteractiveTimeout ) { this._setInteractiveTimeout( true ); } return false; } if ( this._isMultiTouch ) { for ( ; i < touches.length; i++ ) { if ( touches[ i ].identifier === this._multiTouchAnchor[ 0 ].identifier ) { this._multiTouchCurrentBbox[ 0 ] = touches[ i ].pageX - offset.left; this._multiTouchCurrentBbox[ 1 ] = touches[ i ].pageY - offset.top; } else if ( touches[ i ].identifier === this._multiTouchAnchor[ 1 ].identifier ) { this._multiTouchCurrentBbox[ 2 ] = touches[ i ].pageX - offset.left; this._multiTouchCurrentBbox[ 3 ] = touches[ i ].pageY - offset.top; } } var anchorDistance = $.geo._distancePointPoint( [ this._multiTouchAnchorBbox[ 0 ], this._multiTouchAnchorBbox[ 1 ] ], [ this._multiTouchAnchorBbox[ 2 ], this._multiTouchAnchorBbox[ 3 ] ] ), currentDistance = $.geo._distancePointPoint( [ this._multiTouchCurrentBbox[ 0 ], this._multiTouchCurrentBbox[ 1 ] ], [ this._multiTouchCurrentBbox[ 2 ], this._multiTouchCurrentBbox[ 3 ] ] ); current = $.geo.center( this._multiTouchCurrentBbox, true ); var wheelLevel = ( ( currentDistance - anchorDistance ) / anchorDistance ); if ( wheelLevel > 0 ) { wheelLevel *= 5; } else { wheelLevel *= 10; } var delta = wheelLevel - this._wheelLevel; this._wheelLevel = wheelLevel; var pinchCenterAndSize = this._getZoomCenterAndSize( this._anchor, delta, false ); this._setInteractiveCenterAndSize( pinchCenterAndSize.center, pinchCenterAndSize.pixelSize ); this._interactiveTransform( ); doInteractiveTimeout = true; current = $.geo.center( this._multiTouchCurrentBbox, true ); } else { current = [e.originalEvent.changedTouches[0].pageX - offset.left, e.originalEvent.changedTouches[0].pageY - offset.top]; } } else { current = [e.pageX - offset.left, e.pageY - offset.top]; } if (current[0] === this._lastMove[0] && current[1] === this._lastMove[1]) { if ( this._inOp ) { e.preventDefault(); if ( doInteractiveTimeout ) { this._setInteractiveTimeout( true ); } return false; } } if ( _ieVersion == 7 ) { this._isDbltap = this._isTap = false; } if (this._mouseDown) { this._current = current; this._moveDate = $.now(); } if ( this._isMultiTouch ) { e.preventDefault( ); this._isDbltap = this._isTap = false; if ( doInteractiveTimeout ) { this._setInteractiveTimeout( true ); } return false; } var shift = this._options[ "shift" ], mode = this._shiftDown ? ( shift === "default" ? "zoom" : shift ) : this._options["mode"], dx, dy, circleSize; switch (mode) { case "zoom": case "dragBox": if ( this._mouseDown ) { this._$drawContainer.geographics( "clear" ); this._$drawContainer.geographics( "drawBbox", [ this._anchor[ 0 ], this._anchor[ 1 ], current[ 0 ], current[ 1 ] ] ); } else { this._trigger("move", e, { type: "Point", coordinates: this.toMap(current) }); } break; case "dragCircle": if ( this._mouseDown ) { dx = current[ 0 ] - this._anchor[ 0 ]; dy = current[ 1 ] - this._anchor[ 1 ]; circleSize = Math.sqrt( ( dx * dx) + ( dy * dy ) ) * 2; //circleSize = Math.max( Math.abs( current[ 0 ] - this._anchor[ 0 ] ), Math.abs( current[ 1 ] - this._anchor[ 1 ] ) ) * 2; // not part of _refreshDrawing this._$drawContainer.geographics( "clear" ); this._$drawContainer.geographics( "drawArc", this._anchor, 0, 360, { width: circleSize, height: circleSize } ); } else { this._trigger("move", e, { type: "Point", coordinates: this.toMap(current) }); } break; case "drawLineString": case "drawPolygon": case "measureLength": case "measureArea": if (this._mouseDown || this._toolPan) { this._panMove(); doInteractiveTimeout = true; } else { if (drawCoordsLen > 0) { this._drawCoords[drawCoordsLen - 1] = this._toMap( current, this._centerInteractive, this._pixelSizeInteractive ); this._drawPixels[drawCoordsLen - 1] = current; this._refreshDrawing(); } this._trigger("move", e, { type: "Point", coordinates: this.toMap(current) }); } break; default: if (this._mouseDown || this._toolPan) { this._panMove(); doInteractiveTimeout = true; } else { this._trigger("move", e, { type: "Point", coordinates: this.toMap(current) }); } break; } this._lastMove = current; if ( doInteractiveTimeout ) { this._setInteractiveTimeout( true ); } if ( this._inOp ) { e.preventDefault(); return false; } }, _dragTarget_touchstop: function (e) { if ( this._options[ "mode" ] === "static" ) { return; } if ( !this._mouseDown ) { if ( _ieVersion == 7 ) { // ie7 doesn't appear to trigger dblclick on this._$eventTarget, // we fake regular click here to cause soft dblclick this._eventTarget_touchstart(e); } else { // Chrome & Firefox trigger a rogue mouseup event when doing a dblclick maximize in Windows(/Linux?) // ignore it return false; } } var doInteractiveTimeout = this._clearInteractiveTimeout( ); var mouseWasDown = this._mouseDown, wasToolPan = this._toolPan, offset = this._$eventTarget.offset(), shift = this._options[ "shift" ], mode = this._shiftDown ? ( shift === "default" ? "zoom" : shift ) : this._options["mode"], current, i, clickDate, dx, dy, coordBuffer, triggerShape; if (this._supportTouch) { current = [e.originalEvent.changedTouches[0].pageX - offset.left, e.originalEvent.changedTouches[0].pageY - offset.top]; this._multiTouchAnchor = []; this._inOp = false; } else { current = [e.pageX - offset.left, e.pageY - offset.top]; } if (this._softDblClick) { if (this._isTap) { dx = current[0] - this._anchor[0]; dy = current[1] - this._anchor[1]; if (Math.sqrt((dx * dx) + (dy * dy)) <= 8) { current = $.merge( [ ], this._anchor ); } } } dx = current[0] - this._anchor[0]; dy = current[1] - this._anchor[1]; this._$eventTarget.css("cursor", this._options["cursors"][this._options["mode"]]); this._shiftDown = this._mouseDown = this._toolPan = false; if ( this._isMultiTouch ) { e.preventDefault( ); this._isMultiTouch = false; this._wheelLevel = 0; if ( doInteractiveTimeout ) { this._setInteractiveTimeout( true ); } return; } if (document.releaseCapture) { document.releaseCapture(); } if (mouseWasDown) { clickDate = $.now(); this._current = current; switch ( mode ) { case "zoom": case "dragBox": if ( dx !== 0 || dy !== 0 ) { var minSize = this._pixelSize * 6, bboxCoords = this._toMap( [ [ Math.min( this._anchor[ 0 ], current[ 0 ] ), Math.max( this._anchor[ 1 ], current[ 1 ] ) ], [ Math.max( this._anchor[ 0 ], current[ 0 ] ), Math.min( this._anchor[ 1 ], current[ 1 ] ) ] ] ), bbox = [ bboxCoords[0][0], bboxCoords[0][1], bboxCoords[1][0], bboxCoords[1][1] ]; if ( mode === "zoom" ) { if ( ( bbox[2] - bbox[0] ) < minSize && ( bbox[3] - bbox[1] ) < minSize ) { bbox = $.geo.scaleBy( this._getBbox( $.geo.center( bbox, true ) ), 0.5, true ); } this._setBbox(bbox, true, true); doInteractiveTimeout = true; } else { triggerShape = $.geo.polygonize( bbox, true ); triggerShape.bbox = bbox; if ( this._userGeodetic ) { triggerShape.coordinates = $.geo.proj.toGeodetic( triggerShape.coordinates ); triggerShape.bbox = $.geo.proj.toGeodetic( triggerShape.bbox ); } this._trigger( "shape", e, triggerShape ); } } else { if ( mode === "dragBox" ) { coordBuffer = this._toMap( current ); triggerShape = { type: "Point", coordinates: [ coordBuffer[ 0 ], coordBuffer[ 1 ] ], bbox: [ coordBuffer[ 0 ], coordBuffer[ 1 ], coordBuffer[ 0 ], coordBuffer[ 1 ] ] }; if ( this._userGeodetic ) { triggerShape.coordinates = $.geo.proj.toGeodetic( triggerShape.coordinates ); triggerShape.bbox = $.geo.proj.toGeodetic( triggerShape.bbox ); } this._trigger( "shape", e, triggerShape ); } } this._resetDrawing(); break; case "dragCircle": if ( dx !== 0 || dy !== 0 ) { var image = this._options[ "axisLayout" ] === "image", d = Math.sqrt( ( dx * dx) + ( dy * dy ) ), n = 180, a; this._drawPixels.length = n + 1; for ( i = 0; i < n; i++ ) { a = ( i * 360 / n ) * ( Math.PI / 180 ); this._drawPixels[ i ] = [ this._anchor[ 0 ] + Math.cos( a ) * d, this._anchor[ 1 ] + Math.sin( a ) * d ]; } this._drawPixels[ n ] = [ this._drawPixels[ 0 ][ 0 ], this._drawPixels[ 0 ][ 1 ] ]; // using coordBuffer for bbox coords coordBuffer = this._toMap( [ [ this._anchor[ 0 ] - d, this._anchor[ 1 ] + ( image ? -d : d ) ], [ this._anchor[ 0 ] + d, this._anchor[ 1 ] + ( image ? d : -d ) ] ] ); triggerShape = { type: "Polygon", coordinates: [ this._toMap( this._drawPixels ) ], bbox: [ coordBuffer[ 0 ][ 0 ], coordBuffer[ 0 ][ 1 ], coordBuffer[ 1 ][ 0 ], coordBuffer[ 1 ][ 1 ] ] }; if ( this._userGeodetic ) { triggerShape.coordinates = $.geo.proj.toGeodetic( triggerShape.coordinates ); triggerShape.bbox = $.geo.proj.toGeodetic( triggerShape.bbox ); } this._trigger( "shape", e, triggerShape ); this._resetDrawing(); } else { coordBuffer = this._toMap( current ); triggerShape = { type: "Point", coordinates: [ coordBuffer[ 0 ], coordBuffer[ 1 ] ], bbox: [ coordBuffer[ 0 ], coordBuffer[ 1 ], coordBuffer[ 0 ], coordBuffer[ 1 ] ] }; if ( this._userGeodetic ) { triggerShape.coordinates = $.geo.proj.toGeodetic( triggerShape.coordinates ); triggerShape.bbox = $.geo.proj.toGeodetic( triggerShape.bbox ); } this._trigger( "shape", e, triggerShape ); } break; case "drawPoint": if (this._drawTimeout) { window.clearTimeout(this._drawTimeout); this._drawTimeout = null; } if (wasToolPan) { this._panFinalize(); } else { if (clickDate - this._clickDate > 100) { var geomap = this; this._drawTimeout = setTimeout(function () { if (geomap._drawTimeout) { geomap._trigger("shape", e, { type: "Point", coordinates: geomap.toMap(current) }); geomap._inOp = false; geomap._drawTimeout = null; } }, 250); } } break; case "drawLineString": case "drawPolygon": case "measureLength": case "measureArea": if (wasToolPan) { this._panFinalize(); } else { i = (this._drawCoords.length === 0 ? 0 : this._drawCoords.length - 1); this._drawCoords[i] = this._toMap(current); this._drawPixels[i] = current; if (i < 2 || !(this._drawCoords[i][0] == this._drawCoords[i-1][0] && this._drawCoords[i][1] == this._drawCoords[i-1][1])) { this._drawCoords[i + 1] = this._toMap( current, this._centerInteractive, this._pixelSizeInteractive ); this._drawPixels[i + 1] = current; } this._refreshDrawing(); } break; default: if (wasToolPan) { this._panFinalize(); } else { if (clickDate - this._clickDate > 100) { this._trigger("click", e, { type: "Point", coordinates: this.toMap(current) }); this._inOp = false; } } break; } this._clickDate = clickDate; if (this._softDblClick && this._isDbltap) { this._isDbltap = this._isTap = false; if ( doInteractiveTimeout ) { this._setInteractiveTimeout( true ); } this._$eventTarget.trigger("dblclick", e); return false; } } if ( doInteractiveTimeout ) { this._setInteractiveTimeout( true ); } if ( this._inOp ) { e.preventDefault(); return false; } }, _eventTarget_mousewheel: function (e, delta) { if ( this._options[ "mode" ] === "static" || this._options[ "scroll" ] === "off" ) { return; } e.preventDefault(); if ( this._mouseDown ) { return false; } if (delta !== 0) { this._clearInteractiveTimeout( ); if ( delta > 0 ) { delta = Math.ceil( delta ); } else { delta = Math.floor( delta ); } var offset = $(e.currentTarget).offset(); this._anchor = [e.pageX - offset.left, e.pageY - offset.top]; var wheelCenterAndSize = this._getZoomCenterAndSize( this._anchor, delta, this._options[ "tilingScheme" ] !== null ), service, i = 0; this._setInteractiveCenterAndSize( wheelCenterAndSize.center, wheelCenterAndSize.pixelSize ); this._interactiveTransform( ); this._setInteractiveTimeout( true ); } return false; } } ); }(jQuery)); AppGeo-geo-f763e47/js/jquery.geo.shingled.js0000664000175000017500000002201612005347446017612 0ustar daviddavid(function ($, undefined) { $.geo._serviceTypes.shingled = (function () { return { create: function (map, serviceContainer, service, index) { var serviceState = $.data(service, "geoServiceState"); if ( !serviceState ) { serviceState = { loadCount: 0 }; var scHtml = '
    '; serviceContainer.append(scHtml); serviceState.serviceContainer = serviceContainer.children(":last"); $.data(service, "geoServiceState", serviceState); } return serviceState.serviceContainer; }, destroy: function (map, serviceContainer, service) { var serviceState = $.data(service, "geoServiceState"); serviceState.serviceContainer.remove(); $.removeData(service, "geoServiceState"); }, interactiveTransform: function ( map, service, center, pixelSize ) { var serviceState = $.data( service, "geoServiceState" ), contentBounds = map._getContentBounds(), mapWidth = contentBounds[ "width" ], mapHeight = contentBounds[ "height" ], halfWidth = mapWidth / 2, halfHeight = mapHeight / 2, bbox = [ center[ 0 ] - halfWidth, center[ 1 ] - halfHeight, center[ 0 ] + halfWidth, center[ 1 ] + halfHeight ]; if ( serviceState ) { this._cancelUnloaded( map, service ); serviceState.serviceContainer.children( ).each( function ( i ) { var $scaleContainer = $(this), scalePixelSize = $scaleContainer.data( "pixelSize" ), scaleRatio = scalePixelSize / pixelSize; if ( scalePixelSize > 0 ) { scaleRatio = Math.round(scaleRatio * 1000) / 1000; var oldMapOrigin = $scaleContainer.data( "origin" ), newPixelPoint = map._toPixel( oldMapOrigin, center, pixelSize ); $scaleContainer.css( { left: Math.round( newPixelPoint[ 0 ] ), top: Math.round( newPixelPoint[ 1 ] ), width: mapWidth * scaleRatio, height: mapHeight * scaleRatio } ); // #newpanzoom /* .children("img").each(function (i) { var $img = $(this), imgCenter = $img.data("center"), x = (Math.round((imgCenter[0] - center[0]) / scalePixelSize) - halfWidth) * scaleRatio, y = (Math.round((center[1] - imgCenter[1]) / scalePixelSize) - halfHeight) * scaleRatio; $img.css({ left: x + "px", top: y + "px" }); }); */ } }); } }, refresh: function (map, service) { var serviceState = $.data(service, "geoServiceState"); this._cancelUnloaded(map, service); if ( serviceState && service && service.style.visibility === "visible" && !( serviceState.serviceContainer.is( ":hidden" ) ) ) { var bbox = map._getBbox(), pixelSize = map._pixelSize, serviceObj = this, serviceContainer = serviceState.serviceContainer, contentBounds = map._getContentBounds(), mapWidth = contentBounds["width"], mapHeight = contentBounds["height"], scaleContainer = serviceContainer.children('[data-pixel-size="' + pixelSize + '"]'), opacity = service.style.opacity, $img; if (opacity < 1) { serviceContainer.find("img").attr("data-keep-alive", "0"); } if ( !scaleContainer.size() ) { serviceContainer.append('
    '); scaleContainer = serviceContainer.children(":last"); } var urlProp = ( service.hasOwnProperty("src") ? "src" : "getUrl" ), urlArgs = { bbox: bbox, width: mapWidth, height: mapHeight, zoom: map._getZoom(), tile: null, index: 0 }, isFunc = $.isFunction( service[ urlProp ] ), imageUrl, imagePos = scaleContainer.position( ); imagePos.left = - ( imagePos.left ); imagePos.top = - ( imagePos.top ); if ( isFunc ) { imageUrl = service[ urlProp ]( urlArgs ); } else { $.templates( "geoSrc", service[ urlProp ] ); imageUrl = $.render[ "geoSrc" ]( urlArgs ); } serviceState.loadCount++; map._requestQueued(); scaleContainer.append(''); $img = scaleContainer.children(":last").data("center", map._center); if ( typeof imageUrl === "string" ) { serviceObj._loadImage( $img, imageUrl, pixelSize, map, serviceState, opacity ); } else { // assume Deferred imageUrl.done( function( url ) { serviceObj._loadImage( $img, url, pixelSize, map, serviceState, opacity ); } ).fail( function( ) { $img.remove( ); serviceState.loadCount--; map._requestComplete(); } ); } } }, resize: function (map, service) { var serviceState = $.data(service, "geoServiceState"); if ( serviceState && service && service.style.visibility === "visible" ) { this._cancelUnloaded(map, service); var serviceContainer = serviceState.serviceContainer, contentBounds = map._getContentBounds(), mapWidth = contentBounds["width"], mapHeight = contentBounds["height"], scaleContainers = serviceContainer.children(); scaleContainers.attr("data-pixel-size", "0"); scaleContainers.each( function ( i ) { var $scaleContainer = $(this), position = $scaleContainer.position( ); var oldMapOrigin = $scaleContainer.data( "origin" ), newPixelPoint = map._toPixel( oldMapOrigin ); $scaleContainer.css( { left: position.left + ( mapWidth - $scaleContainer.width( ) ) / 2, top: position.top + ( mapHeight - $scaleContainer.height( ) ) / 2 } ); } ); /* scaleContainer.css({ left: halfWidth + 'px', top: halfHeight + 'px' }); */ } }, opacity: function ( map, service ) { var serviceState = $.data( service, "geoServiceState" ); serviceState.serviceContainer.find( "img" ).stop( true ).fadeTo( "fast", service.style.opacity ); }, toggle: function (map, service) { var serviceState = $.data(service, "geoServiceState"); serviceState.serviceContainer.css("display", service.style.visibility === "visible" ? "block" : "none"); }, _cancelUnloaded: function (map, service) { var serviceState = $.data(service, "geoServiceState"); if (serviceState && serviceState.loadCount > 0) { serviceState.serviceContainer.find("img:hidden").remove(); while (serviceState.loadCount > 0) { serviceState.loadCount--; map._requestComplete(); } } }, _loadImage: function ( $img, url, pixelSize, map, serviceState, opacity ) { var serviceContainer = serviceState.serviceContainer; $img.load(function (e) { if (opacity < 1) { $(e.target).fadeTo(0, opacity); } else { $(e.target).show(); } serviceState.loadCount--; map._requestComplete(); if (serviceState.loadCount <= 0) { // #newpanzoom serviceContainer.children(':not([data-pixel-size="' + pixelSize + '"])').remove(); serviceContainer.find( "img[data-keep-alive]" ).remove( ); serviceState.loadCount = 0; } }).error(function (e) { $(e.target).remove(); serviceState.loadCount--; map._requestComplete(); if (serviceState.loadCount <= 0) { serviceContainer.children(":not([data-pixel-size='" + pixelSize + "'])").remove(); serviceState.loadCount = 0; } }).attr("src", url); } }; }()); }(jQuery)); AppGeo-geo-f763e47/js/jquery.geo.geographics.js0000664000175000017500000003465712005347446020326 0ustar daviddavid(function ($, undefined) { var _ieVersion = ( function () { var v = 5, div = document.createElement("div"), a = div.all || []; do { div.innerHTML = ""; } while ( a[0] ); return v > 6 ? v : !v; }() ); $.widget("geo.geographics", { _$elem: undefined, _options: {}, _trueCanvas: true, _width: 0, _height: 0, _$canvas: undefined, _context: undefined, _blitcanvas: undefined, _blitcontext: undefined, _$labelsContainer: undefined, options: { style: { borderRadius: "8px", color: "#7f0000", //fill: undefined, fillOpacity: 0.2, height: "8px", opacity: 1, //stroke: undefined, strokeOpacity: 1, strokeWidth: "2px", visibility: "visible", width: "8px" } }, _create: function () { this._$elem = this.element; this._options = this.options; this._$elem.css({ display: "inline-block", overflow: "hidden", textAlign: "left" }); if (this._$elem.css("position") == "static") { this._$elem.css("position", "relative"); } this._$elem.addClass( "geo-graphics" ); this._width = this._$elem.width(); this._height = this._$elem.height(); if (!(this._width && this._height)) { this._width = parseInt(this._$elem.css("width"), 10); this._height = parseInt(this._$elem.css("height"), 10); } var posCss = 'position:absolute;left:0;top:0;margin:0;padding:0;', sizeCss = 'width:' + this._width + 'px;height:' + this._height + 'px;', sizeAttr = 'width="' + this._width + '" height="' + this._height + '"'; if (document.createElement('canvas').getContext) { this._$elem.append(''); this._$canvas = this._$elem.children(':last'); this._context = this._$canvas[0].getContext("2d"); this._blitcanvas = document.createElement( "canvas" ); this._blitcanvas.width = this._width; this._blitcanvas.height = this._height; this._blitcontext = this._blitcanvas.getContext("2d"); } else if (_ieVersion <= 8) { this._trueCanvas = false; this._$elem.append( '
    '); this._$canvas = this._$elem.children(':last'); G_vmlCanvasManager.initElement(this._$canvas[0]); this._context = this._$canvas[0].getContext("2d"); this._$canvas.children().css({ backgroundColor: "transparent", width: this._width, height: this._height }); } this._$elem.append('
    '); this._$labelsContainer = this._$elem.children(':last'); }, _setOption: function (key, value) { if (key == "style") { value = $.extend({}, this._options.style, value); } $.Widget.prototype._setOption.apply(this, arguments); }, destroy: function () { $.Widget.prototype.destroy.apply(this, arguments); this._$elem.html(""); this._$elem.removeClass( "geo-graphics" ); }, clear: function () { this._context.clearRect(0, 0, this._width, this._height); this._$labelsContainer.html(""); }, drawArc: function (coordinates, startAngle, sweepAngle, style) { style = this._getGraphicStyle(style); if (style.visibility != "hidden" && style.opacity > 0 && style.widthValue > 0 && style.heightValue > 0) { var r = Math.min(style.widthValue, style.heightValue) / 2; startAngle = (startAngle * Math.PI / 180); sweepAngle = (sweepAngle * Math.PI / 180); this._context.save(); this._context.translate(coordinates[0], coordinates[1]); if (style.widthValue > style.heightValue) { this._context.scale(style.widthValue / style.heightValue, 1); } else { this._context.scale(1, style.heightValue / style.widthValue); } this._context.beginPath(); this._context.arc(0, 0, r, startAngle, sweepAngle, false); if (this._trueCanvas) { this._context.restore(); } if (style.doFill) { this._context.fillStyle = style.fill; this._context.globalAlpha = style.opacity * style.fillOpacity; this._context.fill(); } if (style.doStroke) { this._context.lineJoin = "round"; this._context.lineWidth = style.strokeWidthValue; this._context.strokeStyle = style.stroke; this._context.globalAlpha = style.opacity * style.strokeOpacity; this._context.stroke(); } if (!this._trueCanvas) { this._context.restore(); } } }, drawPoint: function (coordinates, style) { style = this._getGraphicStyle(style); if (style.widthValue == style.heightValue && style.heightValue == style.borderRadiusValue) { this.drawArc(coordinates, 0, 360, style); } else if (style.visibility != "hidden" && style.opacity > 0) { style.borderRadiusValue = Math.min(Math.min(style.widthValue, style.heightValue) / 2, style.borderRadiusValue); coordinates[0] -= style.widthValue / 2; coordinates[1] -= style.heightValue / 2; this._context.beginPath(); this._context.moveTo(coordinates[0] + style.borderRadiusValue, coordinates[1]); this._context.lineTo(coordinates[0] + style.widthValue - style.borderRadiusValue, coordinates[1]); this._context.quadraticCurveTo(coordinates[0] + style.widthValue, coordinates[1], coordinates[0] + style.widthValue, coordinates[1] + style.borderRadiusValue); this._context.lineTo(coordinates[0] + style.widthValue, coordinates[1] + style.heightValue - style.borderRadiusValue); this._context.quadraticCurveTo(coordinates[0] + style.widthValue, coordinates[1] + style.heightValue, coordinates[0] + style.widthValue - style.borderRadiusValue, coordinates[1] + style.heightValue); this._context.lineTo(coordinates[0] + style.borderRadiusValue, coordinates[1] + style.heightValue); this._context.quadraticCurveTo(coordinates[0], coordinates[1] + style.heightValue, coordinates[0], coordinates[1] + style.heightValue - style.borderRadiusValue); this._context.lineTo(coordinates[0], coordinates[1] + style.borderRadiusValue); this._context.quadraticCurveTo(coordinates[0], coordinates[1], coordinates[0] + style.borderRadiusValue, coordinates[1]); this._context.closePath(); if (style.doFill) { this._context.fillStyle = style.fill; this._context.globalAlpha = style.opacity * style.fillOpacity; this._context.fill(); } if (style.doStroke) { this._context.lineJoin = "round"; this._context.lineWidth = style.strokeWidthValue; this._context.strokeStyle = style.stroke; this._context.globalAlpha = style.opacity * style.strokeOpacity; this._context.stroke(); } } }, drawLineString: function (coordinates, style) { this._drawLines([coordinates], false, style); }, drawPolygon: function (coordinates, style) { if ( !this._trueCanvas || coordinates.length == 1 ) { // either we don't have fancy rendering or there's no need for it (no holes) this._drawLines( coordinates, true, style ); } else { if ( !coordinates || !coordinates.length || coordinates[ 0 ].length < 3 ) { // this is not a Polygon or it doesn't have a proper outer ring return; } style = this._getGraphicStyle(style); var pixelBbox, i, j; if ( style.visibility != "hidden" && style.opacity > 0 ) { this._blitcontext.clearRect(0, 0, this._width, this._height); if ( style.doFill ) { if ( coordinates.length > 1 ) { // stencil inner rings this._blitcontext.globalCompositeOperation = "source-out"; this._blitcontext.globalAlpha = 1; for ( i = 1; i < coordinates.length; i++ ) { this._blitcontext.beginPath(); this._blitcontext.moveTo( coordinates[ i ][ 0 ][ 0 ], coordinates[ i ][ 0 ][ 1 ] ); for ( j = 1; j < coordinates[ i ].length; j++ ) { this._blitcontext.lineTo( coordinates[ i ][ j ][ 0 ], coordinates[ i ][ j ][ 1 ] ); } this._blitcontext.closePath(); this._blitcontext.fill( ); } } } // path outer ring this._blitcontext.beginPath(); this._blitcontext.moveTo( coordinates[ 0 ][ 0 ][ 0 ], coordinates[ 0 ][ 0 ][ 1 ] ); pixelBbox = [ coordinates[ 0 ][ 0 ][ 0 ] - style.strokeWidthValue, coordinates[ 0 ][ 0 ][ 1 ] - style.strokeWidthValue, coordinates[ 0 ][ 0 ][ 0 ] + style.strokeWidthValue, coordinates[ 0 ][ 0 ][ 1 ] + style.strokeWidthValue ]; for ( i = 1; i < coordinates[ 0 ].length - 1; i++ ) { this._blitcontext.lineTo( coordinates[ 0 ][ i ][ 0 ], coordinates[ 0 ][ i ][ 1 ] ); pixelBbox[ 0 ] = Math.min( coordinates[ 0 ][ i ][ 0 ] - style.strokeWidthValue, pixelBbox[ 0 ] ); pixelBbox[ 1 ] = Math.min( coordinates[ 0 ][ i ][ 1 ] - style.strokeWidthValue, pixelBbox[ 1 ] ); pixelBbox[ 2 ] = Math.max( coordinates[ 0 ][ i ][ 0 ] + style.strokeWidthValue, pixelBbox[ 2 ] ); pixelBbox[ 3 ] = Math.max( coordinates[ 0 ][ i ][ 1 ] + style.strokeWidthValue, pixelBbox[ 3 ] ); } this._blitcontext.closePath(); this._blitcontext.globalCompositeOperation = "source-out"; if ( style.doFill ) { // fill outer ring this._blitcontext.fillStyle = style.fill; this._blitcontext.globalAlpha = style.opacity * style.fillOpacity; this._blitcontext.fill( ); } this._blitcontext.globalCompositeOperation = "source-over"; if ( style.doStroke ) { // stroke outer ring this._blitcontext.lineCap = this._blitcontext.lineJoin = "round"; this._blitcontext.lineWidth = style.strokeWidthValue; this._blitcontext.strokeStyle = style.stroke; this._blitcontext.globalAlpha = style.opacity * style.strokeOpacity; this._blitcontext.stroke( ); if ( coordinates.length > 1 ) { // stroke inner rings for ( i = 1; i < coordinates.length; i++ ) { this._blitcontext.beginPath(); this._blitcontext.moveTo( coordinates[ i ][ 0 ][ 0 ], coordinates[ i ][ 0 ][ 1 ] ); for ( j = 1; j < coordinates[ i ].length; j++ ) { this._blitcontext.lineTo( coordinates[ i ][ j ][ 0 ], coordinates[ i ][ j ][ 1 ] ); } this._blitcontext.closePath(); this._blitcontext.stroke( ); } } } // blit pixelBbox[ 0 ] = Math.max( pixelBbox[ 0 ], 0 ); pixelBbox[ 1 ] = Math.max( pixelBbox[ 1 ], 0 ); pixelBbox[ 2 ] = Math.min( pixelBbox[ 2 ], this._width ); pixelBbox[ 3 ] = Math.min( pixelBbox[ 3 ], this._height ); this._context.drawImage(this._blitcanvas, pixelBbox[ 0 ], pixelBbox[ 1 ], pixelBbox[ 2 ] - pixelBbox[ 0 ], pixelBbox[ 3 ] - pixelBbox[ 1 ], pixelBbox[ 0 ], pixelBbox[ 1 ], pixelBbox[ 2 ] - pixelBbox[ 0 ], pixelBbox[ 3 ] - pixelBbox[ 1 ] ); } } }, drawBbox: function (bbox, style) { this._drawLines([[ [bbox[0], bbox[1]], [bbox[0], bbox[3]], [bbox[2], bbox[3]], [bbox[2], bbox[1]], [bbox[0], bbox[1]] ]], true, style); }, drawLabel: function( coordinates, label ) { this._$labelsContainer.append( '
    ' + label + '
    '); }, resize: function( ) { this._width = this._$elem.width(); this._height = this._$elem.height(); if (!(this._width && this._height)) { this._width = parseInt(this._$elem.css("width"), 10); this._height = parseInt(this._$elem.css("height"), 10); } if ( this._trueCanvas ) { this._$canvas[0].width = this._width; this._$canvas[0].height = this._height; } else { } this._$labelsContainer.css( { width: this._width, height: this._height } ); }, _getGraphicStyle: function (style) { function safeParse(value) { value = parseInt(value, 10); return (+value + '') === value ? +value : value; } style = $.extend({}, this._options.style, style); style.borderRadiusValue = safeParse(style.borderRadius); style.fill = style.fill || style.color; style.doFill = style.fill && style.fillOpacity > 0; style.stroke = style.stroke || style.color; style.strokeWidthValue = safeParse(style.strokeWidth); style.doStroke = style.stroke && style.strokeOpacity > 0 && style.strokeWidthValue > 0; style.widthValue = safeParse(style.width); style.heightValue = safeParse(style.height); return style; }, _drawLines: function (coordinates, close, style) { if (!coordinates || !coordinates.length || coordinates[0].length < 2) { return; } var i, j; style = this._getGraphicStyle(style); if (style.visibility != "hidden" && style.opacity > 0) { this._context.beginPath(); for (i = 0; i < coordinates.length; i++) { this._context.moveTo(coordinates[i][0][0], coordinates[i][0][1]); for (j = 1; j < coordinates[i].length; j++) { this._context.lineTo(coordinates[i][j][0], coordinates[i][j][1]); } } if (close) { this._context.closePath(); } if (close && style.doFill) { this._context.fillStyle = style.fill; this._context.globalAlpha = style.opacity * style.fillOpacity; this._context.fill(); } if (style.doStroke) { this._context.lineCap = this._context.lineJoin = "round"; this._context.lineWidth = style.strokeWidthValue; this._context.strokeStyle = style.stroke; this._context.globalAlpha = style.opacity * style.strokeOpacity; this._context.stroke(); } } } }); }(jQuery)); AppGeo-geo-f763e47/.gitignore0000664000175000017500000000005012005347446014736 0ustar daviddavid /sandbox /web.config /update.bat *.swp AppGeo-geo-f763e47/docs/0000775000175000017500000000000012036234152013674 5ustar daviddavidAppGeo-geo-f763e47/docs/js/0000775000175000017500000000000012036234152014310 5ustar daviddavidAppGeo-geo-f763e47/docs/js/plugins.js0000664000175000017500000000066012005347446016340 0ustar daviddavid (function($){ })(this.jQuery); window.log = function(){ log.history = log.history || []; log.history.push(arguments); if(this.console){ console.log( Array.prototype.slice.call(arguments) ); } }; (function(doc){ var write = doc.write; doc.write = function(q){ log('document.write(): ',arguments); if (/docwriteregexwhitelist/.test(q)) write.apply(doc,arguments); }; })(document); AppGeo-geo-f763e47/docs/js/script.js0000664000175000017500000000064212005347446016163 0ustar daviddavid/* Author: Ryan Westphal */ $(function () { $("a[data-href]").live("click", function (e) { $("#" + $(this).data("href"))[0].scrollIntoView(); }); $(".ui-page").live("pageshow", function () { $(this).find(".geomap-indoc").geomap({ zoom: 2, scroll: "off" }); }); $(".ui-page").live("pagebeforehide", function () { $(this).find(".geomap-indoc").geomap("destroy"); }); }); AppGeo-geo-f763e47/docs/geo/0000775000175000017500000000000012005347446014455 5ustar daviddavidAppGeo-geo-f763e47/docs/geo/length.html0000664000175000017500000000412012005347446016621 0ustar daviddavid length | $.geo

    length

    return type Number
    syntax $.geo.length( Object shape ( GeoJSON object ) )
    usage
    var length = $.geo.length( {
          type: "LineString",
          coordinates: [[
            [-75, 39.7],
            [-74.8, 39.3],
            [-75.2, 39.3]
          ]]
    } )

    The length method calculates the length of a basic GeoJSON geometry object and returns it in non-geodetic units. The basic shapes are Point, LineString and Polygon. If you are using geomap with its default map service, the length is in meters because the default projection is web mercator meters.

    This function returns 0 for Point objects, the length of LineString objects and the perimeter of Polygon objects.

    If the argument is not a basic GeoJSON geometry object, this function returns undefined.

    This function is similar to Geometry.getLength in JTS.

    AppGeo-geo-f763e47/docs/geo/bbox.html0000664000175000017500000000547012005347446016303 0ustar daviddavid bbox | $.geo

    bbox

    return type Array ( GeoJSON bounding box )
    syntax $.geo.bbox( Object shape ( GeoJSON object ) )
    usage
    var bbox = $.geo.bbox( {
      type: "LineString", coordinates: [
        [ -71, 40 ], [ -70.5, 41 ]
      ]
    } )

    The bbox method calculates the smallest box that will contain all the positions in the passed-in shape. The shape can be any GeoJSON geometry object from Point to GeometryCollection.

    The GeoJSON spec allows for each geometry type to have a bbox property. The $.geo.bbox method will honor that property and assume it is accurate. It will return the value of that property before attempting to calculate the bbox itself. If you wish to force $.geo.bbox to calculate the bbox, you will have to manually delete the bbox property from the geometry object.

    var shape = {
      type: "LineString", coordinates: [
        [ -71, 40 ], [ -70.5, 41 ]
      ],
      bbox: [ -71, 40, -70.5, 41 ]
    };
    var bboxFromProperty = $.geo.bbox(shape);
    delete shape.bbox;
    var calculatedBbox = $.geo.bbox(shape);
    

    If the argument is not a basic GeoJSON geometry object, this function returns undefined.

    This function is similar to Geometry.getEnvelope in JTS.

    AppGeo-geo-f763e47/docs/geo/polygonize.html0000664000175000017500000000356312005347446017551 0ustar daviddavid polygonize | $.geo

    polygonize

    return type Array ( GeoJSON Polygon )
    syntax $.geo.polygonize( Array bbox ( GeoJSON bounding box ) )
    usage
    var polygon = $.geo.polygonize( bbox )

    The polygonize method creates a new Polygon with an outer ring that matches the rectangle covered by the bbox. The Polygon is closed and will have five coordinates.

    This function is a simplification/adaptation of the Polygonizer class in JTS. While the JTS object operates on the line work of geometry objects, this function operates on bounding boxes.

    AppGeo-geo-f763e47/docs/geo/proj.html0000664000175000017500000001736212005347446016326 0ustar daviddavid $.geo.proj object | jQuery Geo

    $.geo.proj object

    The $.geo namespace has a property named proj which is a JavaScript object having four functions: fromGeodetic, fromGeodeticPos, toGeodetic, and toGeodeticPos. These four functions allow all $.geo static bbox/geometry functions, geomap widget properties, geomap widget events & geomap widget methods (collectively referred to as plugin functions from now on) to work in geodetic (lon, lat) coordinates.

    Consider the following example:

    • assume you are using the default map service
    • you call $.geo.distance passing two geodetic Point objects, i.e., the GeoJSON position in each point is an array where coordinates[0] is the longitude and coordinates[1] is latitude

    jQuery Geo will first convert the points to map units, a process called projection. jQuery Geo needs projected coordinates to properly calculate some relationships between shapes. After converting the points, $.geo.distance can then calculate the distance between them. This distance will be in meters because the default map service is web mercator meters.

    In order to work directly in map units, you used to have to set $.geo.proj to null. While still valid, you no longer have to do this. You can leave $.geo.proj set to, e.g., web mercator meters and send either projected web mercator GeoJSON geometry objects or geodetic (lon, lat) objects to $.geo functions. The return value will depend on the type of arguments passed.

    The geomap widget keeps track of how you set options. For example, if you set the map's center using geodetic coordinates, geodetic coordinates will then be returned when you ask for the center later. They will also be used when the geomap widget triggers events such as bboxchange or shape.

    The default $.geo.proj object comes pre-built with functions that quickly convert between geodetic coordinates and web mercator meters so you can start using lon, lat right away with the default OpenStreetMap-based tiles. If your map service uses a different projection you can roll your own $.geo.proj object and continue to have the option to use geodetic coordinates. Read Other projections below for information on how to do that.

    Usage

    The two base functions, fromGeodetic and toGeodetic, can take and return: a single bounding box, a single GeoJSON position (Point.coordinates), an array of GeoJSON positions (MultiPoint.coordinates or LineString.coordinates), an array of arrays of positions (MultiLineString.coordinates or Polygon.coordinates) or an array of arrays of arrays of positions (MultiPolygon.coordinates). In other words, the $.geo.proj functions convert the coordinates property of any of the GeoJSON geometry types. For example, you can use the following to convert the position contained in a GeoJSON point object:

    var geodeticPoint = {
      type: "Point",
      coordinates: [ -73.5100, 41.3500 ]
    };
    
    var projectedCoords = $.geo.proj.fromGeodetic( geodeticPoint.coordinates );

    However, a LineString's coordinates property is an array of positions which you can also pass to the fromGeodetic method to get an array converted positions

    var projectedLineStringCoords = $.geo.proj.fromGeodetic( geodeticLineString.coordinates );

    To convert a set of projected GeoJSON positions back to web mercator, call toGeodetic.

    var geodeticLineString = {
      type: "LineString",
      coordinates: $.geo.proj.toGeodetic( projectedLineStringCoords  )
    };

    Other projections

    The $.geo.proj object allows you to use geodetic coordinates with whichever coordinate system or projection you want in any plugin function. If you pass a geodetic Polygon to $.geo.bbox, the returned bounding box will be in geodetic coordinates.

    If you are working in a projection other than the default web mercator meters but still wish to use geodetic coordinates, you will have to update the $.geo.proj object so that it can convert between geodetic coordinates and ones in your projection.

    However, if you don't need to work in longitude, latitude at all, you can ignore $.geo.proj and use projected coordinates throughout your project. You also still have the option to set $.geo.proj to null for completeness and remind yourself that you are limited to projected coordinates. If you are working in Massachusetts Mainland State Plane meters for example, you can pass a Polygon of that projection to any plugin function and you will get results in that projection. This includes all $.geo functions and geomap options & methods.

    $.geo.proj = null; // not required but reminds us that jQuery Geo can't use lon, lat in this project
    
    $('map').geomap( {
      tilingScheme: null,
      bboxMax: [ 31790, 790195, 337250, 961865 ],
      bbox: [ 235644, 894775, 237775, 898523 ],
      services: [ /* service object that supports MA State Plane */ ]
    } );

    jQuery Geo uses the four $.geo.proj functions throughout to convert between geodetic and projected coordinates. However, fromGeodeticPos and toGeodeticPos handle the conversion of individual GeoJSON positions and are used by fromGeodetic and toGeodetic. You can extend $.geo.proj with your own implementations of fromGeodeticPos and toGeodeticPos to change the internal projection used by all plugin functions and still use geodetic (lon, lat) coordinates as arguments and return values.

    Please note that you must extend $.geo.proj with new functionality instead of replacing it wholesale with a new object. You need to keep the original fromGeodetic and toGeodetic functions intact.

    $.extend($.geo.proj, {
      fromGeodeticPos: function( coordinate ) {
        var converted = [];
        // convert the GeoJSON lon/lat position to MA State Plane
        return converted;
      },
    
      toGeodeticPos: function( coordinate ) {
        var converted = [];
        // convert the GeoJSON MA State Plane position to lon/lat
        return converted;
      }
    });
    
    $('map').geomap( {
      tilingScheme: null,
    
      // notice that with a custom $.geo.proj object,
      // these properties can be in geodetic coordinates
      bboxMax: [ -73.5100, 41.3500, -69.8600, 42.8900 ],
      bbox: [ -71.098709, 42.330322, -71.072617, 42.351608 ],
    
      // the services option must still be in map coordinates
      // see geomap's services property docs for more info
      services: [ /* service object that supports MA State Plane */ ]
    } );

    Implementing custom from/to GeodeticPos functions is currently beyond the scope of this documentation but reading up on Proj4js is a good start.

    AppGeo-geo-f763e47/docs/geo/width.html0000664000175000017500000000325312005347446016465 0ustar daviddavid width | $.geo

    width

    return type Number
    syntax $.geo.width( Array bbox ( GeoJSON bounding box )
    usage
    var width = $.geo.width( [ -71.1, 42.3, -71.0, 42.4 ] )

    The width method returns the true width of a bbox in non-geodetic units. If you are using geomap with its default map service, the width is in meters because the default projection is web mercator meters.

    This function is similar to Envelope.getWidth in JTS.

    AppGeo-geo-f763e47/docs/geo/area.html0000664000175000017500000000414212005347446016254 0ustar daviddavid area | $.geo

    area

    return type Number
    syntax $.geo.area( Object shape ( GeoJSON object ) )
    usage
    var area = $.geo.area( {
          type: "Polygon",
          coordinates: [[
            [-75, 39.7],
            [-74.8, 39.3],
            [-75.2, 39.3],
            [-75, 39.7]
          ]]
    } )

    The area method calculates the area of a basic GeoJSON geometry object and returns it in non-geodetic units. The basic shapes are Point, LineString and Polygon. If you are using geomap with its default map service, the area is in square meters because the default projection is web mercator meters.

    While you can pass any basic geometry, this function returns the area of Polygon objects and 0 for objects of other shape types.

    If the argument is not a basic GeoJSON geometry object, this function returns undefined.

    This function is similar to Geometry.getArea in JTS.

    AppGeo-geo-f763e47/docs/geo/height.html0000664000175000017500000000327212005347446016617 0ustar daviddavid height | $.geo

    height

    return type Number
    syntax $.geo.height( Array bbox ( GeoJSON bounding box )
    usage
    var height = $.geo.height( [ -71.1, 42.3, -71.0, 42.4 ] )

    The height method returns the true height of a bbox in non-geodetic map units. If you are using geomap with its default map service, the height is in meters because the default projection is web mercator meters.

    This function is similar to Envelope.getHeight in JTS.

    AppGeo-geo-f763e47/docs/geo/recenter.html0000664000175000017500000000344712005347446017162 0ustar daviddavid recenter | $.geo

    recenter

    return type Array ( GeoJSON bounding box )
    syntax $.geo.recenter( Array bbox ( GeoJSON bounding box ), Array (GeoJSON position) )
    usage
    var moved = $.geo.recenter( bbox, [ -70, 42 ] )

    The recenter method creates a new bbox with the same width and height as the original but moving the center to a new location.

    This function is not defined in JTS.

    AppGeo-geo-f763e47/docs/geo/expandBy.html0000664000175000017500000000434512005347446017123 0ustar daviddavid expandBy | $.geo

    expandBy

    return type Array ( GeoJSON bounding box )
    syntax $.geo.expandBy( Array bbox ( GeoJSON bounding box ), Number dx, Number dy )
    usage
    var largerBbox = $.geo.expandBy( bbox, 20, 20 )

    The expandBy method creates a new bbox with the same center as the original but having a width and height that is modified by the dx and dy arguments respectively.

    The dx and dy arguments are non-geodetic map units. If you are using geomap with its default map service, these are in meters because the default projection is web mercator meters. If, for example, you are working in a different projection such as NAD83 / New Jersey feet, this function will expand or contract the bbox by feet.

    The dx and dy arguments can be positive, negative or zero and will modify the width or height of the bbox accordingly.

    This function is similar to Envelope.expandBy in JTS.

    AppGeo-geo-f763e47/docs/geo/centroid.html0000664000175000017500000000504712005347446017160 0ustar daviddavid centroid | $.geo

    centroid

    return type Object ( GeoJSON Point )
    syntax $.geo.centroid( Object shape ( GeoJSON object ) )
    usage
    var centroid = $.geo.centroid( {
          type: "Polygon",
          coordinates: [[
            [-75, 39.7],
            [-74.8, 39.3],
            [-75.2, 39.3],
            [-75, 39.7]
          ]]
    } )

    The centroid method calculates the center of mass for the passed-in basic GeoJSON geometry object. The basic geometry types are Point, LineString and Polygon.

    Technically, only Polygons can be considered to have mass. However, a centroid can be calculated for other geometry types. This method operates on LineStrings as if they were closed polygons and the centroid will likely not lie along the line. The centroid of a Point is a clone of the Point.

    If the argument is not a basic GeoJSON geometry object, this function returns undefined.

    This function is similar to Geometry.getCentroid in JTS.

    AppGeo-geo-f763e47/docs/geo/distance.html0000664000175000017500000000413512005347446017140 0ustar daviddavid distance | $.geo

    distance

    return type Number
    syntax $.geo.distance( Object shape1 ( GeoJSON object ), Object shape2 ( GeoJSON object ) )
    usage
    var distanceBetween = $.geo.distance(
      { type: "Point", "coordinates": [ -71, 40 ] },
      { type: "Point", "coordinates": [ -70.5, 41 ] }
    )

    The distance method calculates the distance between two basic GeoJSON geometry objects and returns it in non-geodetic units. The basic shapes are Point, LineString and Polygon. If you are using geomap with its default map service, the distance is in meters because the default projection is web mercator meters.

    If either argument is not a basic GeoJSON geometry object, this function returns undefined.

    This function is similar to Geometry.distance in JTS.

    AppGeo-geo-f763e47/docs/geo/reaspect.html0000664000175000017500000000413312005347446017152 0ustar daviddavid reaspect | $.geo

    reaspect

    return type Array ( GeoJSON bounding box )
    syntax $.geo.reaspect( Array bbox ( GeoJSON bounding box ), Number ratio )
    usage
    var widescreenBbox = $.geo.reaspect( bbox, 16 / 9 )

    The reaspect method creates a new bbox with the same center as the original but forcing the ratio of width to height to a specific value.

    If the original width is greater than the original height (think a landscape printout) then the width of the new bbox will be the same as the original but the new height will change to fit the ratio. If the original height is greater than the original width (think a portrait printout) then the new bbox height will remain unchanged but the width will to fit the ratio.

    This function is not defined in JTS.

    AppGeo-geo-f763e47/docs/geo/scaleBy.html0000664000175000017500000000405312005347446016727 0ustar daviddavid scaleBy | $.geo

    scaleBy

    return type Array ( GeoJSON bounding box )
    syntax $.geo.scaleBy( Array bbox ( GeoJSON bounding box ), Number scale )
    usage
    var twiceAsBig = $.geo.scaleBy( bbox, 2 )

    The scaleBy method creates a new bbox with the same center as the original but having a width and height that are both multiplied by the scale argument.

    The scale argument is a percentage increase or decrease. This means that supplying 2 will increase the size of the bbox by 200%, which if thinking in terms of a map's view, would zoom out. Supplying .5 will decrease the size of the bbox to half its original size.

    The scale argument must be greater than zero.

    This function is not defined in JTS.

    AppGeo-geo-f763e47/docs/geo/include.html0000664000175000017500000000473112005347446016773 0ustar daviddavid include | $.geo

    include

    return type Array ( GeoJSON bounding box )
    syntax $.geo.include( null | Array bbox ( GeoJSON bounding box ), Array position ( GeoJSON position ) | Array bbox ( GeoJSON bounding box ) )
    usage
    var bboxOfCoord = $.geo.include( null, [ -70, 42 ] );
    var sameAsSecondArgument = $.geo.include( null, [ -71, 41, -69, 43 ] );
    var includeCoord = $.geo.include( bbox, [ -70, 42 ] );
    var includeBbox = $.geo.include( bbox, [ -71, 41, -69, 43 ] );

    The include method expands a bbox to include either a coordinate or another bbox. The expanded bbox is returned.

    If the first argument is null or undefined, the result is a new bbox and will contain the second argument.

    For efficency, if the first argument is a valid bbox, it is modified in-place and a reference is returned.

    If the second argument is not a coordinate or bbox, this function returns the first argument.

    This function is similar to Envelope.expandToInclude in JTS.

    AppGeo-geo-f763e47/docs/geo/pointAlong.html0000664000175000017500000000474112005347446017463 0ustar daviddavid pointAlong | $.geo

    pointAlong

    return type Object ( GeoJSON Point )
    syntax $.geo.pointAlong( Object shape ( GeoJSON object ), Number percentage )
    usage
    var pointAlong = $.geo.pointAlong( {
          type: "LineString",
          coordinates: [[
            [-75, 39.7],
            [-74.8, 39.3],
            [-75.2, 39.3]
          ]]
    }, .5 )

    The pointAlong method calculates a Point that lies a given fraction along the passed-in basic GeoJSON geometry object. The basic geometry types are Point, LineString and Polygon. A percentage of 0.0 returns the first Point; a percentage of 1.0 returns the last.

    Technically, only LineStrings can be used properly in this calculation. However, pointAlong can be calculated for other geometry types. With Point objects, pointAlong will always return a copy of the original Point. For Polygon objects, pointAlong operates on the Polygon's perimeter (outer ring), i.e., myPolygon.coordinates[0]. For Polygons, percentage values of 0.0 and 1.0 will return the same Point.

    If the argument is not a basic GeoJSON geometry object, this function returns undefined.

    This function is similar to LineSegment.pointAlong in JTS.

    AppGeo-geo-f763e47/docs/geo/index.html0000664000175000017500000001123712005347446016456 0ustar daviddavid geo namespace | $.geo

    geo namespace

    The $.geo namespace contains all geometry functions implemented in the plugin and an object having the plugin's four projection functions.

    projection

    The $.geo namespace has a property named proj which is a JavaScript object having four functions: fromGeodetic, fromGeodeticPos, toGeodetic, and toGeodeticPos. These four functions allow all $.geo static bbox/geometry functions, geomap widget properties, geomap widget events & geomap widget methods (collectively referred to as plugin functions from now on) to work in geodetic (lon, lat) coordinates.

    geometry operations

    Geometry isn't much fun if you can't do anything with it. These functions help you analyze and manipulate bounding boxes and GeoJSON geometry objects. You call them directly from the $.geo namespace:

    $.geo.distance( point1, point2 )

    Except for a few name changes and switching from an object-oriented API to a function-based one, jQuery Geo attempts to follow the names and behavior of the Java Topology Suite (JTS), which is the de-facto standard for geometry library APIs. JTS itself is an implementation of the OGC Simple Features specification but has made design decisions that improve the API for developers. The most notable of which is having Envelope (called bbox in jQuery Geo and GeoJSON) be its own class type.

    bbox functions

    These functions operate on GeoJSON bounding box array, i.e., a JavaScript array having four values:

    • minimum x/longitude
    • minimum y/latitude
    • maximum x/longitude
    • maximum y/latitude

    geometry object functions

    These functions operate on GeoJSON geometry objects: Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, and GeometryCollection. They do not operate on Feature or FeatureCollection objects, you have to call these functions on the geometry properties of Feature objects.

    The geometry functions allow you to analyze relationships between geometries such as their distance apart as well as obtain information about them such as bounding box and center point, called the centroid. This section will eventually expand to cover all of the important spatial operations available in the Java Topology Suite.

    AppGeo-geo-f763e47/docs/geo/center.html0000664000175000017500000000351012005347446016622 0ustar daviddavid center | $.geo

    center

    return type Array ( GeoJSON position )
    syntax $.geo.center( Array bbox ( GeoJSON bounding box ) )
    usage
    var bboxCenter = $.geo.center( bbox )

    The center method calculates the center of a bbox and returns it as a GeoJSON position.

    It operates on bounding boxes and should not be confused with the centroid function, which operates on GeoJSON geometry objects.

    This function is called Envelope.centre in JTS (I assume because JTS is built in British Columbia).

    AppGeo-geo-f763e47/docs/geo/contains.html0000664000175000017500000000432112005347446017161 0ustar daviddavid contains | $.geo

    contains

    return type Boolean
    syntax $.geo.contains( Object shape1 ( GeoJSON object ), Object shape2 ( GeoJSON object ) )
    usage
    var contains = $.geo.contains(
      {
        type: "Polygon", coordinates: [[
          [-71.06, 42.3425],
          [-71.06, 42.3475],
          [-71.04, 42.3475],
          [-71.04, 42.3425],
          [-71.06, 42.3425]
        ]]
      },
      { type: "Point", "coordinates": [ -71, 40 ] }
    )

    The contains method determines if the first basic GeoJSON geometry completely contains a second one. The basic shapes are Point, LineString and Polygon however Point and LineString geometries cannot contain other geometries so the only situation that has a possibility of returning true is when the first argument is a Polygon.

    If either argument is not a basic GeoJSON geometry object, this function returns undefined.

    This function is similar to Geometry.contains in JTS.

    AppGeo-geo-f763e47/docs/internals/0000775000175000017500000000000012005347446015702 5ustar daviddavidAppGeo-geo-f763e47/docs/internals/index.html0000664000175000017500000001367512005347446017713 0ustar daviddavid internals | jQuery Geo

    internals

    We keep some plugin design decisions here.

    jQuery UI widget factory

    The geomap widget uses the same widget factory that all other jQuery UI and jQuery Mobile widgets use. Like jQuery Mobile, we include a copy of jquery.ui.widget.js in the project. While this adds 3k to the final compressed build it allows us to easilly follow the patterns designed by UI and better integrate into the jQuery plugin community.

    $.widget( "geo.geomap", { } );

    Virtual state

    The public properties bbox, bboxMax and center do not always match the internal state of the map widget. In fact internally, geomap only tracks center and pixelSize. The bbox and bboxMax properties are calculated based on the current or max center and pixelSize. In the code, you will see two properties each for each of these. One is public, the other is private. For center, the internal position (_center) is always in internal map units (web mercator meters by default) even if the developer sets the public bbox or center by longitude & latitude.

    Initialization options

    You may notice that we override jQuery UI's _createWidget function in order to capture the options passed in by the user. Let us know if there's a better way to do that. At the end of _create, we iterate over the passed options and set certain internal state values before creating services and refreshing the map. This insures that we handle supplied bbox or center properly. Since bbox and center can potentially conflict, only supply one. If both are supplied the behavior is technically undefined but currently center will override bbox.

    bbox cache

    When you append a shape to the map, the geomap widget will cache the shape's bounding box (in non-geodetic coordinates) for faster searches when you call find. When you remove a shape from the map, the cache will be cleared. When you use the $.geo.bbox method on a shape after it has been appended to the map, the cached bounding box will be returned.

    // the bbox of an appended shape is cached while it is on the map
    var calculatedBbox = $.geo.bbox(shape);
    $("#map").geomap("append", shape);
    var cachedBbox = $.geo.bbox(shape);
    $("#map").geomap("remove", shape);
    var calculatedAgain = $.geo.bbox(shape);

    jQuery Geo caches the bbox using jQuery's data function under the name geoBbox. Though I can't think of a reason to do so, you can remove this cache by calling removeData directly on the shape object:

    $.removeData(shape, "geoBbox");

    jQuery Geo's caching will not alter your geometry object so you don't have to worry about unintentionally storing or sending extra data to a server.

    External libraries

    Apart from the jQuery UI widget factory, geomap includes a couple external libraries.

    Mouse wheel extension 3.0.2

    http://plugins.jquery.com/node/7146

    We've found this to be a very stable mousewheel special event plugin and are using it to handle mouse wheel interaction. This plugin's license comment and source are included intact in the minified releases of jQuery Geo.

    Google excanvas

    We include parts of Google's excanvas library to support graphic drawing in IE6-8. Only functions required to support jQuery Geo's feature list are included. This library's license comment and source are included intact in the non-minified releases of jQuery Geo. The license comment and partial source are included intact in the minified releases of jQuery Geo.

    jsRender

    https://github.com/BorisMoore/jsrender

    jQuery Geo includes a snapshot of jsRender, the next-generation templating engine from the jQuery team. This is used for measure text templates and src string templates.

    Service types

    Developers can set the services array used by the geomap widget. When it comes time to draw map images, the geomap widget uses an internal _serviceTypes object. The object contains one property for each service type geomap supports, e.g., tiled and shingled. The type property on each service object determines which serviceType object geomap uses to refresh the service. The following code snippet is a simplification of the relationship.

    options: {
      services: [
        {
          "class": "osm",
          type: "tiled"
          /* ,... */
        }
      ]
    },
    
    _serviceTypes: {
      tiled: {
        refresh: function (map, service) {
        }
        /* ,... */
      }
    }

    In the future the _serviceTypes property will be public and developers can extend the service types geomap supports.

    AppGeo-geo-f763e47/docs/images/0000775000175000017500000000000012005347446015150 5ustar daviddavidAppGeo-geo-f763e47/docs/images/$.geo-logo.png0000664000175000017500000000441012005347446017507 0ustar daviddavidPNG  IHDR((msRGBgAMA a pHYsodtEXtSoftwarePaint.NET v3.5.87;]xIDATXGXyPwG  DAGzTDZvP;vKUr"$LQA+[JkwcκcKo$M/$n]f2{}fTC7~35ewKc67L#9|.9$Y;Q?mI\,_|Nb‘Gy0}?[2T`F$?wz{>mPf,E?ib}һ55Tz-c h8pH"yuLUPNJa ) |~қYNc?+cs^ [- ] жh( h\yӊDI$  㭭pέ_5_]pḻ2򂑴4Izjc`MwPB(lTbJ%e,)/8Y0i4J˻vQmt\.QY!"{]^o/2/j~̱?w?C  yAH`DL^)*rp0v/qSCi4|&1د r8`^ c~t}}aOв2QX/glG< J;xY5w׾aRYYpdV +>j*+Ć_y<َ2011чE[AlxJPwYxΘ&mpO \ t7z>nM|$A!~(-V&XXHN`RѥKԃ;bI(6X(EP.sU%jo)ITC xU,ՃV|؟**?p3ޠ\{:fn|,֞=@(G>ϿctE-III& v-r᭽{)-{%5ؙ%xϟ0 0MU*( xO1.ϗ3I>",AJq1۰z*v6ABNf "{';mLIwajh^T7EK7L]9֭\LݟHlCA_%J-DR\"ufg"C(0ZA;Q"ԹVP,⾂d׭ Eqs%1 .io" /̉3))}{0%m:WX\ԉ&Pz*m i}S[uJ:SؘV >8oLրm;(8(x(x(<{a^3o /@Z+$IENDB`AppGeo-geo-f763e47/docs/images/map.png0000664000175000017500000001161512005347446016437 0ustar daviddavidPNG  IHDR"sRGBgAMA aPLTE)()10)141941981989B<9BA9JIBRMBRQBRUJZQBZUJZYJZYRc]JcaRceZkaRkiRkiZsmZsqZcac{yc}ckskss{s{{s{s{{{ήsβsֶ{ֺ{{Ʈβζƶƾƾζκκֶֺ־־ξξƾƾǜDŽnj˄όÔÜϜÔǜ˜ǥýåíǭϥ˭ǥ˥ϭ˵ץ׵όϔϜӌהӜ۔۔ߜϭץӭۥ߭߭ӵ׽۵۽ߵI pHYsodtEXtSoftwarePaint.NET v3.5.6ЃZIDATx^흏[SʬVmmj[]1&d qD :uCeU BD :頤P^ sM IgS{s>==ߤI֠25mϰ Z Y.rJ84K8h"p2I׎ ])<4znLVAdgA zb>>::2r;eN IӘprʒP,+Lva6Qؒ+2{;xF&<[!SK4C Z.n\i$N֋[بb8r(6ؿ'% >P#D%%ˀCnQ!qځ ]]ϧtBvˊT_SXđuysƫ[ )ccbz;%ӅL=ʢe& M{1)^n~ܜ~~ -XXN Nvqv̋&='zNNA^܀9HYpzcdG)6C.=d8QЖPxEclM($~cl?TmL4 Sm"8C>8)ERA MA4$z3 `pG&.S9+L@ Ot$փJN,5ՃmT@g5$!jpa,c_n@%[t³R+ْd]Q#-/'C-Yv'A/pR/*rz 5[g0|ЪzăIV~,FfKA^'<^2x"A u}P{ْE "TނA02[_@]ْ8l?w & PbwxիW~"%zp2i&it2ْeh*mUgoG!`}N?Vk,B -[_Br J1'bMy_eKA=uvͦ)nL/ eȾ9]6#OeKv0 dٽ7 %]^B2`ܜl;Did`)`eKX^H7ɀ %[B2GQ5nI/ mnYA– x3d]tPp@RJ^)xpWPW^ٚgbڄpZHьu:nC ^*A|E K{#%@Z!oQ Ҳ% ^@Z!hBlKf Q YZ8#;KX2j)zpo^Hx8_ l ,-[!J+$Vf:JTɎ .-[_RQHBbb>F!:o%d9H+$Kn)ڒm#YtlI=+::U!ʱiÃ:+;hknsx@t>^yҞVm}'Ґ.H*`{UW=Є*1&zYZ$sp|zD!XWp\pU9sAZ!6s럯!D_a4~Iw"/oRAr',z@lY=8/%giؕ4(Zt̼e H+$/;=['av]Xpj@l(Ƕ{@43V&ɎJȑ^HfW)vAJpjndec@v$ql_ @h߷.ׁs-2aP _ك]V͖ =g@J!˗|.(Ƕ{! ݆v+prJ. RaUvz6wXȱ힣O+MM9be&c= DbeX6D ,7-rsy/9mK l!E3t,Jl>]DxuJx~{`@ = (6@ 9!dKz#D mgԈh,ym @pm<!PEw@<]K؈*3m[֧&ԭOϞլMϿ x}, ocӍճ}%z'ø^Q|%W8t$,Usm-AQNi Q❸߱6&X.\Zv4WL5bTU4EDS=7k,ߊ5[sXJ6hMVM.J>OQnLCހ=hD%Y-6HcJ]"DKI?z"4LVg?4d7**ގ"ZKԶq^v_iDq8hc*~''5ۛ!"?h |@'i!i/X:˗c߱<2:D%D>JDsp_tȀ7d*Ϟ}yH=, HqGP6!+0/<ݱa`WX9`xafD:fI_MnyB7$&;t8Q60[q@ _&̞9$N u:rLM΂_Ys5(:ߊKxݹًێ'`o@|lA! )= ?*=wqo~:/zˁb\;ٴYM'zNāu0 3ՑV 8݀,Spj5@1@o'PVNM^t 7f&;`c*~ {G)9PUwLG=Ӕ\+ue %We|'}$XoMQ=d~ZCTjލ:8E*.ŵ&^2q)'~*.P[4zܨ"󊕘A]zx=]2o?VoM!ZftsPjl S@x) W@ @櫲2T"ޔ94Y9/K98]cWTJSGC3q̚Ctj:g]ܲzKSƭ]dvPIENDB`AppGeo-geo-f763e47/docs/images/$.geo-logo-large.png0000664000175000017500000000431412005347446020602 0ustar daviddavidPNG  IHDR``F sRGBgAMA aPLTE~   ! #",+-,/.0/10KILJNLTRUSWUXVZW[X\ZLLMMUUigjhkiwtwtxuyvzwVVđđƕǖǗͣͤΥ犊½'`tRNSS% pHYsodtEXtSoftwarePaint.NET v3.5.87;]$IDAThCi_1 (xp(". C 3IҤtW~K>MT<G VEwy=v;1%Bq{/l_O& bQ*ooa|?<+$G]NL>DKg1&έn%}`L:{! ~AɃԴH*F$1`]#/#]# XO/# 1-:x͋ڈD0/#Q)FO96R $ظI,60) C:} Kopr.PW"}y*'#C])ؠdl"x|V_T;J})>n1v! mgBl*}$Sz2W?Cb~,R32&t!bklL=(pD~U v}&0U?}[|9%k$:v} 0QEB s!` vK΢-Z5ˀɐfd*#Q,!z+A(InsGXwd)?GlQFR CԜMPͨ>bC= C97@gL) ? jiP;C AA iHGne48/%$"qQH 텞e=ާʯo^afT w JENi+Q{7*dIENDB`AppGeo-geo-f763e47/docs/images/$.geo-logo-small.png0000664000175000017500000000270012005347446020615 0ustar daviddavidPNG  IHDRw=gAMA a pHYs(JtEXtSoftwarePaint.NET v3.5.87;]=IDATHKU}Pugl ]4Ľ(c `(4^̗T4ϫ`6TJ;Ê.4CRe\׵_}>/?{֬Qck}],z.~fZ:E.b ׷$ϸ?gY.63vΖؘ \Y UD[l̶NUyFTN:qc?~03B#Eܑy`SW߫ wv=s+Z9jyADCJbf S2vȮ]pMi,u {4gr^=QԴ:>=<|CE ˝ڠTBᅷҟj}+ ?k cR?? v7 Э,y`joAaa4Or;adɓčx"7 U}XNg,ߝ9_4aalRWm1o =i>>^Pf8l vfj^DPJdgSSHsZ- \0`%' ddd& *6{pcom@Rq.9ODQg֯6A@0Ԡy]YQa?ΕF98xE z4&ՌEo&ϖh!*sjmdbJ쏐;^3:zhl~8bfzu5"B.FfURQɾk lk2=ZҢ $*JVMbʁ{f;+LRU.aݻvݪB'gZĔVw&^:iwqAYod QHV_[Z \OQZM . YHvp l~|⎋21MlTG6Ǩt'E.whrWq\7](G8TSF df[l O~O|Xd_ݑ9&*)|ˍzk+|n xr(@Ph^Bmhhntb=1!Q"t˾t=۝GommpB\;Ȯ $܆QzJcT6lMXڰn=CV 8lޒ׮^ÇIm[ `9B˄ X ukR0:Wz 9j0Ӳp|ʠ<1! Lo,~XUA?#m߶:'xND0Efr m5ԲYsF7۬ISڶuF+yi p?Wy+\XLũ*[{kHߝ9e0U,W|-x7:)X+" @ݽ{TJ,4~XٽHbŨ{TVm3zWZ/\ eR2e_ ._>r* :==%tgv.~sf΢ ,1l7E*TXIa:Sθ'OÉ{.YW_uYnQ8l:uDŝ;N>EO>%\P:l[ovN'>.&TFiE giy4nܱ#լZ&D_l hV? ylR'$cܹy^_݄k¸2М=s&  ZΞ#|xYk?wnaCP>XI׮ycwuz򞁗NB,gϘ zAɧ}ڰQ|]Pa{H1U*f c+Ü޹#FNX1\ U6͛6%I;<| 83]1]HLpRi RH_S'}{U 0O-p}rml,Ƶ) MFIMB'wϞgiRO8~l""M[plژJII5լIiWD(r_M5]bFXosv7rЖM}b6,yɢEB!Q;OPa -ZPu=کL5~[.S2L$ qǖ$M]o՛ܿ/gڔC8l"otD[<7h`c.asf͖>cF1֭ZgO23k:i lczܘ(,HӐVy oڸQ;{ ;:wIw޼2Ā0?)brB@9l8m;*6CdCK p`|r%SeY 0n&)h$&$[YU8l5bd;w|݆?[D]³^:"o\!`_52UaüFZ3cH DlZF@6F) xlpwJ 9PAot^ԁ?\re';"؞ViPϛ#1.J)jEY\,1G1::Sk >=v`D0Ft {')R1oѻw@^~E?30uf < Twv.`&Tl;$df${ Z-;f̨Qb3XL߾}YAM߷B BGi#6ݶ-uaO6;g;8ĮisR?dH)۷k'J=dJ`18?Я$7!<\8j\CBFTk,&jNO1W;6Tl l2TZkl5x q߾}+~e8yj7ؽN X _~i0=~Osv8;<Ϻ2:hEn 8[l`ݡK>|J#jC!wSȕƼ%8Hhi1 pVQ+]&HAc`;yD*_:}_CRqb.+Wvb:]߽+HFt-n޴ɣr/-m.4@|/կcع67^$o. )6k܄%;`SRǍ޼yC/R&dbhSr%ItB(`Ϳk;$s{?Kwx<ø"5 뤈F݄6 #kXEaO$&kX:F޺f6f[a e7UØ0SSH`鍁 R ߻{cl0NHPs@fƣh7fY#Ք  0S%6#~'LW\-6$p]$ I蚱GU""d `976g?֮{-lk$u2v'x ϽC;؎>kT>8.?לYV da 홞?_ی"İ(QH8fL+CpA Mi2^Մwkc4狀& s ܡ|$WM̷Wn޸aftL3G%֪ p62JtKnxۡCR%!|"Lǎrf26Gsl%;.)K Ybh#Aky~?eKGidqu8z`RI&}Cn [aFAx|,xlhvNL I e-^W)rJA0vjASf&JtlЄ pL-I QE)h FzD10O7J$0@{hF^SP)kۢV^LT*PN eȨmDqTXE?M+j'\i#im/^16XqsV)zڱN,zD\ Eogxe0x+!>ҳgϸ>+L/,J2UղS& /_ܿuꥊrf<娔jBe`.#*kTH4\H pX^% <aTeDL ܪQ_  VǏCaI\UGx:;úQ_ ot;$ʼn'hϮ/8" 5@BOh R,ΆMi/#*p{;aS@M6 )\HM^kh<ޮ^86 u.oNz `& ~Ěp]rU Jkv/ ,^\ +]՜S<L0/_=ծ-RudaS6Mx W7Ebm XmDlڒE=$߀^f}$o6\${>acqy rh$Rz@jGöl/+ms=]u["{|u3ɪ.CQsSySy~ 7f vz7JO ]ba'UoXgHIAuS`j&P#UdfT zDB-8Xrcցl[Ay[{:/Wy1}i˓y~C:ܶTeHY6T?>i~ꨥ3ƪpt% ћPJ2(7ߋ! {nݳ"͗jC`N7 :]Ź1x E՞W%@:@J} t^4Xͥ"rMXX\P[Hɇj$?IFr6c#튰2h^@?$ "]'kVN5F)W@!۲"= Xj¸0D!P t`@WTGBD 3GbsV._ApdCޞ۹ˌaLcc2z$؁AoDSB@azXezfLe/gd\zK7MfJ"aǘܺSk0KӦg DSTV*}zs:(f x8vUًצa}oY waAB϶󰤅Çw䃛' dZƲ]sϰ#/q|os["a@; PbV$~ǦC*]LImq=L}u絪Uw_=40r:dNj%imGxic}oiz}iJ諅}LQ&\la B>xVm׿7Tmֵ&m~ g| fڠ13 $9A9Hn5{xyVwr sh 1(GezRE|LcJ%}vp5Gy bboxchange | geomap

    bboxchange

    type bboxchange
    init
    $( selector ).geomap( {
      bboxchange: function( e, geo ) { }
    } );
    bind
    $( selector ).bind( "geomapbboxchange", function( e, geo ) { } );
    } );

    The bboxchange event triggers any time user interaction causes a change in the current bbox of the map widget. This includes pan, wheel zoom, double-click zoom, etc. The geomap does not trigger this event when you update the bbox programmatically.

    The geo argument is an object containing a bbox property which the new bbox.

    AppGeo-geo-f763e47/docs/geomap/zoom.html0000664000175000017500000000476612005347446017042 0ustar daviddavid zoom | geomap

    zoom

    type Number
    default 0
    init
    $( selector ).geomap( { zoom: 0 } );
    get
    var zoom = $( selector ).geomap( "option", "zoom" );
    set
    $( selector ).geomap( "option", "zoom", 7 );

    The zoom option gets or sets the current zoom of the map view.

    For tiled maps, the zoom option's range starts at zero and goes to either the current geomap tilingScheme's levels property minus one or the length of the tilingScheme's pixelSize array (depending on how the tilingScheme option is declared).

    For non-tiled maps, i.e., tilingScheme is null and you're using all shingled services, the zoom option is based on the ratio between sizes of the bbox and bboxMax properties. If they are equal, the zoom option is 0. Smaller bbox areas will have larger zoom values.

    If you attempt to initialize both zoom and bbox at the same time when creating a geomap widget, bbox will be applied and zoom will modify the final bbox.

    Apart from setting the zoom option directly, you can use the zoom method to change the zoom by relative amounts.

    AppGeo-geo-f763e47/docs/geomap/zoomMax.html0000664000175000017500000000531612005347446017500 0ustar daviddavid zoomMax | geomap

    zoomMax

    type Number
    default Number.POSITIVE_INFINITY
    init
    $( selector ).geomap( { zoomMax: 17 } );
    get
    var zoomMax = $( selector ).geomap( "option", "zoomMax" );
    set
    $( selector ).geomap( "option", "zoomMax", 7 );

    The zoomMax option gets or sets the maximum value of the zoom option for the map.

    For tiled maps, this option overrides the tilingScheme option when it is smaller than what you've specified in the tilingScheme. For example, if the tilingScheme has a total of 18 levels but you set the zoomMax option to 7, the user will not be able to zoom in past level 7.

    For non-tiled maps, i.e., tilingScheme is null and you're using all shingled services, this option determines the maximum zoom (and therefore minimum pixelSize) a user can achieve. Without setting this option for non-tiled maps, users will be able to infinitely zoom in to fully dynamic maps which is likely not what you want. Non-tiled maps require the bboxMax option to determine what zoom level 0 means. This option represents the other side of the zoom range.

    This option also overrides programmatic changes. If zoomMax is 7 and you try to set the zoom option to 8 using JavaScript, it will be set to 7 instead.

    AppGeo-geo-f763e47/docs/geomap/find.html0000664000175000017500000001541312005347446016765 0ustar daviddavid find | geomap

    find

    return type Array<Object> ( GeoJSON objects )
    syntax .geomap( "find", Object point (GeoJSON Point), Number pixelTolerance )
    .geomap( "find", shape selector )
    usage
    var existingShape = $( map or service selector ).geomap( "find", { type: "Point", coordinates: [ -71.098709, 42.330322 ] }, 8 )
    
    var allShapes = $( map or service selector ).geomap( "find", "*" )

    The find method allows you to search for shapes appended to the map and/or services. There are two distinct ways to call this method.

    geometry search

    The find method can take a single GeoJSON map point and return all shapes within a pixel radius of the given location that have been added with append. If there are no shapes at the location, this method returns an empty array.

    The pixelTolerance argument is always in pixels. This allows for pixel-based searches regardless of the map's current zoom. A high-zoom search is finer than a low-zoom one because at lower zoom levels, i.e., the map is zoomed out more, the Earth-size of a pixel is greater causing this search to reach out farther from the supplied position.

    Duplicate shape references are included in the return value. For example, if you have appended the same GeoJSON object to both the map and a specific service, and then call find at that location, the returned array will contain two, identical shape references.

    selector search

    The find method can also take a single string. The string is in CSS selector syntax but currently only one selector is supported: *. Use the * selector to return an array of all shapes that have been appended to the map or service. If there are no shapes on the map or service, this method returns an empty array. Searching for all shapes at the map level will return all shapes that have been appended to the map or any service.

    Duplicate shape references are included in the return value. For example, if you have appended the same GeoJSON object to both the map and a specific service, and then call find( "*" ) at the map level, the returned array will contain two, identical shape references.

    The shape selector cannot include service ids or classes. To search for shapes within a specific service, see below.

    service-level shapes

    Similar to how you can append shapes to specific services, you can find shapes in specific services as well.

    You do this by targeting a service inside a map instead of the map itself for your call to geomap's find method. For example, the default map service has the CSS class: osm. We can find a shape from that service specifically by using jQuery to target the service:

    var osmShapes = $( "#map .osm" ).geomap( "find", [ -71, 42 ], 8 );

    However, unlike the other three shape methods, shapes appended to a specific service will be returned by calling find on the map itself. In this way, calling find on the map is a deep search for shapes on all services. For example, after this sequence the shapes variable will contain the shape even though it was appended to a service specifically:

    var point = {
          type: "Point",
          coordinates: [ -71, 42 ]
        };
    
    // add the shape to the osm service
    $( "#map .osm" ).geomap( "append", point );
    
    // use the original point to search for shapes on the map widget
    var shapes = $( "#map" ).geomap( "find", point, 3 );

    Another difference between the find method and the append, remove, and empty methods, is that the find method cannot currently be used on multiple targets simultaneously. For example, the return value of the following is undefined:

    // attempt to search the osm service and a second service at the same time
    var shapes = $( "#map .osm,#map .massgis" ).geomap( "find", point, 8 );

    To find shapes in two specific services without searching all services you should use two find calls:

    // find shapes on the default service and a second service
    var osmShapes = $( "#map .osm" ).geomap( "find", point, 8 ),
        massgisShapes = $( "#map .massgis" ).geomap( "find", point, 8 );

    The selector-based version also follows this requirement. You cannot target more than one element with the initial selector and you cannot use the shape selector to search services. A multi-service selector-based search would be the same as above but with "*" instead of: point, 8.

    // the following are invalid and their return value is undefined
    var multiTarget = $( "#map .massgis,#map .osm" ).geomap( "find", "*" );
    var shapeSubSelector = $( "#map" ).geomap( "find", ".massgis *" );
    
    // proper way to get all shapes from multiple services
    var osmShapes = $( "#map .osm" ).geomap( "find", "*" ),
        massgisShapes = $( "#map .massgis" ).geomap( "find", "*" );
    AppGeo-geo-f763e47/docs/geomap/zoommethod.html0000664000175000017500000000456112005347446020234 0ustar daviddavid zoom | geomap

    zoom

    return type undefined
    syntax .geomap( "zoom", Number numberOfLevels )
    usage
    $("#map").geomap( "zoom", 1 )
    $("#map").geomap( "zoom", -2 )

    The zoom method can zoom the map in or out by a given number of zoom levels. Positive values zoom the map in, negative values zoom the map out.

    This method will not zoom out beyond zoom level 0. If you are using a tiling scheme, this method will not zoom in past the maximum number of zoom levels defined in the tilingScheme property.

    This method accepts values relative to the map's current zoom level. This is different than the zoom property, which is the map's current zoom level. It might be useful to add an explicit plus sign when using this zoom method.

    // set the map to zoom level 2
    $("#map").geomap( "option", "zoom", 2 );
    
    // zoom the map in 2 levels from its current zoom
    $("#map").geomap( "zoom", +2 );

    This method does not trigger events, not even bboxchange.

    There is no default value. Passing null or undefined will not change the map's zoom.

    AppGeo-geo-f763e47/docs/geomap/drawStyle.html0000664000175000017500000000531612005347446020024 0ustar daviddavid drawStyle | geomap

    drawStyle

    type Object ( geomap style )
    default
    {
      borderRadius: "8px",
      color: "#7f0000",
      fillOpacity: .2,
      height: "8px",
      opacity: 1,
      strokeOpacity: 1,
      strokeWidth: "2px",
      visibility: "visible",
      width: "8px"
    }
    init
    $( map selector ).geomap( { drawStyle: { color: "green" } } );
    get
    var drawStyle = $( map selector ).geomap( "option", "drawStyle" );
    set
    $( map selector ).geomap( "option", "drawStyle", { strokeWidth: "4px" } );

    The drawStyle option retrieves or updates the style of incomplete lines and polygons as they are being drawn. This differs from the shapeStyle option which updates the style of shapes that you've appended to the map.

    This option affects both the draw modes (drawPoint, drawLineString, and drawPolygon) and the measure modes (measureLength, and measureArea).

    This option changes specific properties of the internal style object. If you init or set an incomplete style object, only the style properties you reference are updated.

    Please see the style section at the bottom of the geomap widget page for more information about the style object.

    AppGeo-geo-f763e47/docs/geomap/images/0000775000175000017500000000000012005347446016420 5ustar daviddavidAppGeo-geo-f763e47/docs/geomap/images/map.png0000664000175000017500000001161512005347446017707 0ustar daviddavidPNG  IHDR"sRGBgAMA aPLTE)()10)141941981989B<9BA9JIBRMBRQBRUJZQBZUJZYJZYRc]JcaRceZkaRkiRkiZsmZsqZcac{yc}ckskss{s{{s{s{{{ήsβsֶ{ֺ{{Ʈβζƶƾƾζκκֶֺ־־ξξƾƾǜDŽnj˄όÔÜϜÔǜ˜ǥýåíǭϥ˭ǥ˥ϭ˵ץ׵όϔϜӌהӜ۔۔ߜϭץӭۥ߭߭ӵ׽۵۽ߵI pHYsodtEXtSoftwarePaint.NET v3.5.6ЃZIDATx^흏[SʬVmmj[]1&d qD :uCeU BD :頤P^ sM IgS{s>==ߤI֠25mϰ Z Y.rJ84K8h"p2I׎ ])<4znLVAdgA zb>>::2r;eN IӘprʒP,+Lva6Qؒ+2{;xF&<[!SK4C Z.n\i$N֋[بb8r(6ؿ'% >P#D%%ˀCnQ!qځ ]]ϧtBvˊT_SXđuysƫ[ )ccbz;%ӅL=ʢe& M{1)^n~ܜ~~ -XXN Nvqv̋&='zNNA^܀9HYpzcdG)6C.=d8QЖPxEclM($~cl?TmL4 Sm"8C>8)ERA MA4$z3 `pG&.S9+L@ Ot$փJN,5ՃmT@g5$!jpa,c_n@%[t³R+ْd]Q#-/'C-Yv'A/pR/*rz 5[g0|ЪzăIV~,FfKA^'<^2x"A u}P{ْE "TނA02[_@]ْ8l?w & PbwxիW~"%zp2i&it2ْeh*mUgoG!`}N?Vk,B -[_Br J1'bMy_eKA=uvͦ)nL/ eȾ9]6#OeKv0 dٽ7 %]^B2`ܜl;Did`)`eKX^H7ɀ %[B2GQ5nI/ mnYA– x3d]tPp@RJ^)xpWPW^ٚgbڄpZHьu:nC ^*A|E K{#%@Z!oQ Ҳ% ^@Z!hBlKf Q YZ8#;KX2j)zpo^Hx8_ l ,-[!J+$Vf:JTɎ .-[_RQHBbb>F!:o%d9H+$Kn)ڒm#YtlI=+::U!ʱiÃ:+;hknsx@t>^yҞVm}'Ґ.H*`{UW=Є*1&zYZ$sp|zD!XWp\pU9sAZ!6s럯!D_a4~Iw"/oRAr',z@lY=8/%giؕ4(Zt̼e H+$/;=['av]Xpj@l(Ƕ{@43V&ɎJȑ^HfW)vAJpjndec@v$ql_ @h߷.ׁs-2aP _ك]V͖ =g@J!˗|.(Ƕ{! ݆v+prJ. RaUvz6wXȱ힣O+MM9be&c= DbeX6D ,7-rsy/9mK l!E3t,Jl>]DxuJx~{`@ = (6@ 9!dKz#D mgԈh,ym @pm<!PEw@<]K؈*3m[֧&ԭOϞլMϿ x}, ocӍճ}%z'ø^Q|%W8t$,Usm-AQNi Q❸߱6&X.\Zv4WL5bTU4EDS=7k,ߊ5[sXJ6hMVM.J>OQnLCހ=hD%Y-6HcJ]"DKI?z"4LVg?4d7**ގ"ZKԶq^v_iDq8hc*~''5ۛ!"?h |@'i!i/X:˗c߱<2:D%D>JDsp_tȀ7d*Ϟ}yH=, HqGP6!+0/<ݱa`WX9`xafD:fI_MnyB7$&;t8Q60[q@ _&̞9$N u:rLM΂_Ys5(:ߊKxݹًێ'`o@|lA! )= ?*=wqo~:/zˁb\;ٴYM'zNāu0 3ՑV 8݀,Spj5@1@o'PVNM^t 7f&;`c*~ {G)9PUwLG=Ӕ\+ue %We|'}$XoMQ=d~ZCTjލ:8E*.ŵ&^2q)'~*.P[4zܨ"󊕘A]zx=]2o?VoM!ZftsPjl S@x) W@ @櫲2T"ޔ94Y9/K98]cWTJSGC3q̚Ctj:g]ܲzKSƭ]dvPIENDB`AppGeo-geo-f763e47/docs/geomap/bbox.html0000664000175000017500000000676012005347446017004 0ustar daviddavid bbox | geomap

    bbox

    type Array ( GeoJSON bounding box )
    default [ -180, -85, 180, 85 ]
    init
    $( selector ).geomap( { bbox: [ -71, 40, -69, 44 ] } );
    get
    var bbox = $( selector ).geomap( "option", "bbox" );
    set
    $( selector ).geomap( "option", "bbox", [ -122, 42, -118, 46 ] );

    The bbox property calculates or modifies the bounding box of the map view the user currently sees. The geomap widget creates the bounding box based on the current center point, map zoom and size of the map view.

    When you set a new bbox, the center and zoom properties are set as close as they can be based on the services you've added and the size of the map view.

    For example, if you have a cached service with specific zoom levels, the map widget will have to pick a zoom level even though it may result in a bbox that is quite different from the one passed. When your services are fully dynamic, i.e., they allow arbitrary zoom levels, the final bbox will not likely match the one passed either due to ratio differences between the requested bbox and the map view's size. The map will attempt to pick a bounding box that best fits the one you request.

    This property is a JavaScript array consisting of four values which can be thought of as: minx, miny, maxx and maxy of the current map view in map units and in that order. By default the values are in geodetic coordinates, e.g., bbox[0] is the longitude of the left of the current map view, bbox[1] is the latitude of the bottom, bbox[2] is the longitude of the right and bbox[3] is the latitude of the top. You can change the default when you initialize the widget by passing projected coordinates as the bbox option.

    Setting a new bbox will refresh the map services.

    If you attempt to initialize both center and bbox at the same time when creating a geomap widget, center will override bbox.

    If you attempt to initialize both zoom and bbox at the same time when creating a geomap widget, bbox will be applied and zoom will modify the final bbox.

    AppGeo-geo-f763e47/docs/geomap/bboxMax.html0000664000175000017500000000517512005347446017451 0ustar daviddavid bboxMax | geomap

    bboxMax

    type Array ( GeoJSON bounding box )
    default [ -180, -85, 180, 85 ]
    init
    $( selector ).geomap( { bboxMax: [ -71, 40, -69, 44 ] } );
    get
    var bboxMax = $( selector ).geomap( "option", "bboxMax" );
    set
    $( selector ).geomap( "option", "bboxMax", [ -75.696, 38.804, -73.696, 41.287 ] );

    The bboxMax option defines a bounding box that surrounds all of the data you wish to show in non-tiled maps, i.e., you have set the tilingScheme option to null. Users can pan the map once they reach bboxMax but cannot zoom out further.

    This option is a JavaScript array consisting of four values which can be thought of as: minx, miny, maxx and maxy of the maximum map view you wish to allow in map units and in that order.

    A bboxMax option must be set properly for shingled (dynamic) services since the value of the map's zoom is based on a ratio between the current bbox and bboxMax.

    Setting a new bboxMax will refresh the map services and reset what zoom level 0 means.

    If you set tilingScheme to null, you must explicitly set bboxMax.

    AppGeo-geo-f763e47/docs/geomap/measureLabels.html0000664000175000017500000000500712005347446020627 0ustar daviddavid measureLabels | geomap

    measureLabels

    type Object
    default
    {
      length: "{{:length}} m",
      area: "{{:area}} sq m"
    }
    init
    $( selector ).geomap( { measureLabels: { length: "{{:length}} meters" } } );
    get
    var measureLabels = $( selector ).geomap( "option", "measureLabels" );
    set
    $( selector ).geomap( "option", "measureLabels", { area: "{{:area}} square meters" } );

    The measureLabels option controls how the length or area text is formatted when displayed on the map during measuring.

    In the label strings, the {{: }} syntax is used as a placeholder for the current length or area. All other text is displayed verbatim.

    Note: Alpha releases used a {{= }} syntax but there is a breaking change in the beta version due to changes in jsRender. Please use the new {{: }} syntax.

    The developer may change each measureLabels option separately during both initialization of the widget or any time after.

    AppGeo-geo-f763e47/docs/geomap/resize.html0000664000175000017500000000365612005347446017354 0ustar daviddavid resize | geomap

    resize

    return type undefined
    syntax .geomap( "resize" )
    usage
    $("#map").geomap( "resize" )

    This method tells the geomap widget to recalculate its frame and adjust its bbox to fit a new size. The map will maintain its center point and pixel size and expand or contract to fill the new surroundings.

    The geomap widget watches the browser window for you. If your map widget's div position is related to the window in some way, geomap will automatically resize to fit when the window size changes. If the map widget's div is not related to the window and you manually change its size, you need to call resize so that the map can adjust.

    This method refreshes the map.

    AppGeo-geo-f763e47/docs/geomap/pixelSize.html0000664000175000017500000000456712005347446020031 0ustar daviddavid pixelSize | geomap

    pixelSize

    type Number
    default 156543.03392799936
    init cannot be initialized
    get
    var pixelSize = $( selector ).geomap( "option", "pixelSize" );
    set read only

    The pixel size is the number of map units a single pixel occupies in the current view. A more interesting way to think of it is the Earth-size of the pixel.

    Because the default internal projection is web mercator meters, the default return value for pixelSize is in meters even if you set other map values in geodetic coordinates, e.g., lon/lat. The unit type will always match the type you set on tilingScheme for tiled maps or bboxMax for shingled (dynamic) maps. For more information on how the plugin handles projections, please read the geo section of this documentation.

    The map's pixel size is read-only. To change it you will need to use one of the mutable properties such as bbox, center or zoom.

    pixelSize is calculated based on tilingScheme & zoom for tiled maps. It is based on the bbox/bboxMax ratio for shingled maps.

    AppGeo-geo-f763e47/docs/geomap/refresh.html0000664000175000017500000001247112005347446017504 0ustar daviddavid refresh | geomap

    refresh

    return type undefined
    syntax $( map or service selector ).geomap( "refresh" [ , Boolean force ] )
    usage
    $("#map").geomap( "refresh" )
    
    $("#map").geomap( "refresh", true )
    
    $("#map .my-dynamic-service").geomap( "refresh", true )

    This method refreshes one or more services and shapes in the map. Usually, changing geomap options or calling methods automatically refreshes the map appropriately. However, you can call this after you have added or removed shapes to geomap by passing false as the refresh argument to the append, remove, or empty methods. This method is also useful in the case of dynamic server data.

    Without a service selector, all services on the map will be refreshed.

    The force option will re-request images for tiles already in the map view. Keep in mind, though, that this does not guarantee you will get updated images. See the Dynamic Data section below for tips.

    Dynamic Data

    There are three factors that can prevent jQuery Geo from getting a fresh image from a web server.

    • if the user does not interact with the map and you do not call refresh, jQuery Geo will not request new images
    • if the user does interact with the map, you call refresh with no arguments, or you call .geomap( "refresh", false ):
      • for tiled services: jQuery Geo will only request images for tiles that it does not already have
      • for shingeld services: a new image is always requested but the browser may supply a cached image
    • if you call .geomap( "refresh", true ), jQuery Geo will:
      • for tiled services: request a new image for existing tiles but the web browser is free to supply a cached image instead of retriving one from the web server
      • for shinged services: this is also true; if the final image URL is the same as a previous image URL the browser may supply a cached image

    A web browser will normally cache images that have already been loaded. On top of that, jQuery Geo will not, by default, request images for tiles that it has already placed. In the case of dynamic data, where you want to update what's on the map without requiring a pan or zoom or also update tiles that have already been placed, you have a couple options.

    use uncachable URLs

    The first option is to use a function for the src property of your service object. In that function, return a different URL every time even if all of the properties of the view object are the same as a previous call. If we were to use jQuery's implementation of the cache option in $.ajax as inspiration, our src function could look similar to:

    src: function( view ) {
      return "my.dynamic.tile.service/" + view.zoom + "/" + view.tile.column + "/" + view.tile.row + ".png?_=" + $.now( );
    }

    The _ input in the query string will be a different number on every request, regardless of the value of zoom, column, and row. Most services will ignore extraneous query string inputs and the web browser will not be able to cache the image.

    use the Cache-Control HTTP header

    Another way to achieve the same result without modifying your image URLs is to use the HTTP header: Cache-Control. By returning this header with the no-cache value, you can tell the web browser to not cache the image. Then, when you call .geomap( "refresh", true ), the web browser will re-request images for tiles even if it has done so one already. This option is only possible if you have some control over the web server that supplies map images. How to add the header is specific to your web server and beyond the scope of these docs. It can usually be done in the web server's configuration file or in the web service itself where you generate the images.

    AppGeo-geo-f763e47/docs/geomap/zoomMin.html0000664000175000017500000000522112005347446017471 0ustar daviddavid zoomMin | geomap

    zoomMin

    type Number
    default 0
    init
    $( selector ).geomap( { zoomMin: 5 } );
    get
    var zoomMin = $( selector ).geomap( "option", "zoomMin" );
    set
    $( selector ).geomap( "option", "zoomMin", 7 );

    The zoomMin option gets or sets the smallest allowed value of the zoom option for the map.

    For tiled maps, this option overrides the tilingScheme option when it is larger than zero. For example, a tilingScheme always defines what zoom level 0 is, but if you set the zoomMin option to 7, the user will not be able to zoom out past level 7.

    For non-tiled maps, i.e., tilingScheme is null and you're using all shingled services, this option determines the minimum zoom (and therefore maximum pixelSize) a user can achieve. Non-tiled maps require the bboxMax option to determine what zoom level 0 means. This option overrides the map's ability to get to zoom level 0. It is not so useful for non-tiled maps, as you can just set a smaller bboxMax and continue using 0 as the minimum zoom.

    This option also overrides programmatic changes. If zoomMin is 2 and you try to set the zoom option to 0 using JavaScript, it will be set to 2 instead.

    AppGeo-geo-f763e47/docs/geomap/shift.html0000664000175000017500000000651212005347446017162 0ustar daviddavid shift | geomap

    shift

    type String
    default "default"
    init
    $( map selector ).geomap( { shift: "default" } );
    get
    var shift = $( map selector ).geomap( "option", "shift" );
    set
    $( map selector ).geomap( "option", "shift", "off" );

    The shift option determines how the shift key affects the map during drag operations in different modes. There are currently four values: default, zoom, dragBox, and off. However, default is currently the same as zoom.

    default and zoom

    When shift is set to default or zoom and a user holds the shift key before holding the mouse button down, the map temporarilly switches to zoom mode. In this state the user can perform a marquee zoom by clicking and holding one point and dragging the mouse cursor. A box will form. When the user lets go of the mouse, the map will zoom to the closest approximation of the bbox of the drawn shape.

    When mode is dragBox, the shift key will still switch to zoom mode. Dragging will form a box either way but if the shift key was down when the user started, the map will zoom.

    dragBox

    When shift is set to dragBox and a user holds the shift key before holding the mouse button down, the map temporarilly switches to dragBox mode. In this state the user can click and hold one point and then drag the mouse cursor. A box will form. When the user lets go of the mouse, jQuery Geo will trigger a shape event passing a GeoJSON Polygon representation of the dragged bbox as the geo argument. The Polygon object also has the GeoJSON the bbox property.

    off

    When shift is set to off, the shift key is ignored. For example, if mode is pan and the user holds the shift key and begins to drag, the map will pan as normal.

    static maps

    When the map's mode option is set to static, the map ignores all user interaction so the shift key is also ignored.

    AppGeo-geo-f763e47/docs/geomap/geomaploadstart.html0000664000175000017500000000361312005347446021232 0ustar daviddavid loadstart | geomap

    loadstart

    type load
    init
    $( map selector ).geomap( {
      loadstart: function( e, geo ) { }
    } );
    bind
    $( map selector ).bind( "geomaploadstart", function( e, geo ) { } );
    } );

    The loadstart event triggers when the geomap widget begins to load new images. It only triggers once regardless of the number of images about to be loaded. It will not be triggered again until after all pending images have been loaded (the image queue returns to zero) and a change in the map requires more images.

    The geo argument is currently undefined for this event.

    You can use this event to show an indicator that your website is busy downloading images.

    AppGeo-geo-f763e47/docs/geomap/pannable.html0000664000175000017500000000430212005347446017620 0ustar daviddavid pannable | geomap

    pannable

    type Boolean
    default true
    init
    $( map selector ).geomap( { pannable: true } );
    get
    var pannable = $( map selector ).geomap( "option", "pannable" );
    set
    $( map selector ).geomap( "option", "pannable", false );

    The pannable option determines whether or not a user can pan the map.

    When true, the default, users can drag the map image or tiles to change the bbox in any mode except for "static". For example, they can pan the map in the middle of drawing a polygon with the drawPolygon mode.

    When false, a user's dragging of the map image will not cause it to move regardless of what mode the widget is in. Developers can still make programatic changes to the bbox, such as setting options and calling methods.

    AppGeo-geo-f763e47/docs/geomap/opacity.html0000664000175000017500000000574212005347446017521 0ustar daviddavid opacity | geomap

    opacity

    return type undefined
    syntax $( map or service selector ).geomap( "opacity", Number opacity )
    usage
    $("#map").geomap( "opacity", .5 )
    $("#map .osm").geomap( "opacity", .7 )

    This method sets the value of the opacity property of service objects in the services array.

    It will also update the opacity of all images already requested by the service.

    If you call opacity directly on geomap's div element, it will apply to all services. You can target individual services using a CSS selector based on the map div id and the class supplied for the service in its service object or just the id of the service if supplied in its service object.

    // for example, given the following as the map div
    <div id="map"></div>
    
    // and initializing geomap with the following services
    $("#map").geomap({
      services: [
        {
          id: "water",
          class: "mass-gis",
          type: "shingled",
          src: function ( view ) { return null; }
        },
        {
          id: "towns",
          class: "mass-gis",
          type: "shingled",
          src: function ( view ) { return null; }
        },
        {
          id: "harbor-cruise",
          type: "shingled",
          src: function ( view ) { return null; }
        }
      ]
    });
    
    // you can later change the opacity of all services
    $("#map").geomap("opacity", .8);
    
    // all mass-gis services
    $("#map .mass-gis").geomap("opacity", .5);
    
    // or a specific service
    $("#harbor-cruise").geomap("opacity", 1.0);

    This is much faster than changing a service object's opacity value yourself and updating geomap's services property.

    AppGeo-geo-f763e47/docs/geomap/tilingScheme.html0000664000175000017500000001107012005347446020453 0ustar daviddavid tilingScheme | geomap

    tilingScheme

    type Object
    default
    {
      tileWidth: 256,
      tileHeight: 256,
      levels: 18,
      basePixelSize: 156543.03392799936,
      pixelSizes: null,
      origin: [ -20037508.342787, 20037508.342787 ]
    }
    init
    $( selector ).geomap( { tilingScheme: {
      tileWidth: 256,
      tileHeight: 256,
      levels: 18,
      basePixelSize: 156543.03392799936,
      pixelSizes: null,
      origin: [ -20037508.342787, 20037508.342787 ]
    } } );
    get
    var tilingScheme = $( selector ).geomap( "option", "tilingScheme" );
    set
    $( selector ).geomap( "option", "tilingScheme", null );

    The tilingScheme property defines a grid that the geomap widget can use to build a map view as adjacent tiles instead of a single, full image each time.

    Only tiled services will get a non-null tile property as an argument to their src method or template. Shingled services, even when layered on top of a tiled map will only get bbox data.

    When a tilingScheme is set, the geomap widget will limit the user to specific zoom levels defined by the tiling scheme.

    If you set tilingScheme to null, you must explicitly set bboxMax.

    Also, if you are using only shingled services you must set tilingScheme to null, and therefore explicitly set bboxMax.

    You can set the map widget to be fully dynamic and allow any arbitrary zoom level by setting the tilingScheme to null. This is only useful if all of your services are backed by live spatial data and can produce map images at any scale.

    This is one of the few places where you must use non-geodetic (i.e., non-lon/lat) units even if you are using longitude & latitude for properties such as center or bbox. You must use projected units when defining a tiling scheme. The default map tiles use web mercator meters.

    All tilingScheme objects have the first three of the following properties. Apart from those, a tilingScheme object must have either just the pixelSizes property or both basePixelSize & levels.

    tileWidth (Number)the width in pixels of a single tile
    tileHeight (Number)the height in pixels of a single tile
    origin (Array<Number>)a GeoJSON position for the top-left corner of the map tiles in map units, this is used to correctly position tiles into the map view
    pixelSizes (Array<Number>)an array of all pixel sizes (called resolutions on Esri's products) hosted by the map service, each one represents a zoom level therefore the total number of zoom levels equals the length of the pixelSizes array
    basePixelSize (Number)the pixelSize represented by the tiles on zoom level 0, used when each pixelSize is a power of two smaller than the previous one
    levels (Number)the total number of pixelSizes allowed, used in conjuction with basePixelSize to determine how far a user is allowed to zoom
    AppGeo-geo-f763e47/docs/geomap/shapeStyle.html0000664000175000017500000001345712005347446020174 0ustar daviddavid shapeStyle | geomap

    shapeStyle

    type Object ( geomap style )
    default
    {
      borderRadius: "8px",
      color: "#7f0000",
      fillOpacity: .2,
      height: "8px",
      opacity: 1,
      strokeOpacity: 1,
      strokeWidth: "2px",
      visibility: "visible",
      width: "8px"
    }
    init
    $( map or service selector ).geomap( { shapeStyle: { color: "green" } } );
    get
    var shapeStyle = $( map or service selector ).geomap( "option", "shapeStyle" );
    set
    $( map or service selector ).geomap( "option", "shapeStyle", { strokeWidth: "4px" } );

    The shapeStyle option retrieves or updates the base style of shapes appended to the map.

    This differs from the drawStyle option which defines the style of incomplete lines and polygons as they are being drawn.

    Two extra color properties, stroke and fill, are not defined by default and use the value of the color property until they are defined individually.

    This option changes specific properties of the internal base style. If you send an incomplete style object, only the style properties you reference are updated.

    Similar to CSS, you can override this style on a per-shape basis by passing a different style to the append method.

    Changing this base style will update how geomap draws existing shapes that do not have their own style. For shapes that do have their own style, changing the base shapeStyle will update any style properties not referenced in the shape-specific style. For example, assume the following:

    1. the base shapeStyle starts with its initial style having a red stroke color and strokeWidth of 2px
      $( "#map" ).geomap( );
    2. you call append with a style that increases the stroke width to 4px but does not supply a stroke color
      $( "#map" ).geomap(
        "append",
        { type: "Point", coordinates: [ -71, 42 ] },
        { strokeWidth: "4px" }
      );
    3. you later change the base shapeStyle's stroke color to blue
      $( "#map" ).geomap( "option", "shapeStyle", { stroke: "#00f" } );

    The shape described in the above example will draw with a blue stroke color and a strokeWidth of 4px.

    You can also set a base style for a specific service. These are called service-level styles and apply only to service-level shapes. To do this, target a service inside a map instead of the map itself for your call to geomap's shapeStyle option. To expand upon the above example, consider the following additional steps:

    1. you change the shapeStyle option of the default service specifically so that points are twice as long as usual; the default service has the CSS class: osm
      $( "#map .osm" ).geomap( "option", "shapeStyle", { width: "16px" } )
    2. you append a second point directly to the default .osm service
      $( "#map .osm" ).geomap( 
        "append",
        { type: "Point", coordinates: [ -70.5, 42.5 ] }
      );

    This second point will:

    • have a blue stroke color because it cascades from the base shapeStyle for the map as a whole (which you set with your first call to shapeStyle)
    • have a strokeWidth of only 2px because it is unaffected by the style applied to the first shape during the first append call
    • have a width of 16px which it gets from the shapeStyle of the service where it was appended

    This is the only option that can be applied to services. All other options require a reference to the original map element.

    When called with a second argument to set the shapeStyle, the jQuery UI widget factory returns the original jQuery collection to maintain call chaining.

    Please see the style section at the bottom of the geomap widget page for more information about the style object.

    AppGeo-geo-f763e47/docs/geomap/toMap.html0000664000175000017500000000417212005347446017125 0ustar daviddavid toMap | geomap

    toMap

    return type Array (GeoJSON positions)
    syntax .geomap( "toMap", Array pixelPositions )
    usage
    var mapPos = $("#map").geomap( "toMap", [ 120, 240 ] )
    var mapPositions = $("#map").geomap( "toMap", [ [ 120, 240 ], [ 192, 48 ] ] )

    The toMap method takes a single pixel position (which is an array of two values: the left and top of the pixel), an array of pixel positions, an array of arrays of pixel positions, or an array of arrays of arrays of pixel positions. In other words, it accepts the pixel representation of the coordinates of any geometry up to MultiPolygon. It returns the map coordinates for all of the pixel positions.

    The return coordinates are in projected map units if you have previously set the bbox or center options using projected coordinates. Otherwise, they are in geodetic (lon, lat) coordinates.

    AppGeo-geo-f763e47/docs/geomap/cursors.html0000664000175000017500000000505112005347446017542 0ustar daviddavid cursors | geomap

    cursors

    type Object (map of geomap mode to CSS cursor)
    default
    {
      static: "default",
      pan: "move",
      zoom: "crosshair",
      drawPoint: "crosshair",
      drawLineString: "crosshair",
      drawPolygon: "crosshair",
      measureLength: "crosshair",
      measureArea: "crosshair"
    }
    init
    $( selector ).geomap( { cursors: { pan: "move" } } );
    get
    var cursors = $( selector ).geomap( "option", "cursors" );
    set
    $( selector ).geomap( "option", "cursors", { pan: "pointer" } );

    The cursors property controls which cursors appear when users move the mouse over the geomap div in any given mode.

    The developer may change each geomap mode's cursor separately during both initialization of the widget or any time after.

    Sometimes the geomap widget will override the selected mode's cursor, e.g., when a user starts panning in other modes the cursor will switch to the pan mode cursor temporarily.

    AppGeo-geo-f763e47/docs/geomap/geomapshape.html0000664000175000017500000000615412005347446020340 0ustar daviddavid shape | jQuery Geo

    shape

    type shape
    init
    $( selector ).geomap( {
      shape: function( e, geo ) { }
    } );
    bind
    $( selector ).bind( "geomapshape", function( e, geo ) { } );
    } );

    The shape event triggers when the user measures a length, or area, or draws a point, line or polygon. He or she does this by tapping the map in specific ways while the geomap mode property is set to: measureLength, measureArea, drawPoint, drawLineString or drawPolygon.

    When mode is drawPoint, a single tap of the map triggers this event passing a GeoJSON Point object of the tapped location in map coordinates.

    When mode is measureLength or drawLineString, the first single tap begins a line. Subsequent single taps add points to the line. A double-tap on the map adds a final point and triggers this event passing a GeoJSON LineString object of the measured length or sketched line in map coordinates.

    When mode is measureArea or drawPolygon, the first single tap begins a polygon. Subsequent single taps add points to the polygon. A double-tap on the map adds a final point and triggers this event passing a GeoJSON Polygon object of the measured area or sketched polygon in map coordinates.

    While measuring or drawing a shape, the user can pan the map by dragging or zoom the map with the mouse wheel. This will not interrupt their current measuring or drawing.

    If you allow users to both measure and draw in your app, be sure to check the mode option in your event handler to determine if this event was triggered by measuring or by drawing. For example, you may want to append the shape to the map during drawPolygon but not during measureArea.

    AppGeo-geo-f763e47/docs/geomap/geomaploadend.html0000664000175000017500000000347412005347446020650 0ustar daviddavid loadend | geomap

    loadend

    type load
    init
    $( map selector ).geomap( {
      loadend: function( e, geo ) { }
    } );
    bind
    $( map selector ).bind( "geomaploadend", function( e, geo ) { } );
    } );

    The loadend event triggers after a loadstart event when the geomap widget has finished loading all pending images. It only triggers once regardless of the number of images loaded. It will not be triggered again until after another loadstart event.

    The geo argument is currently undefined for this event.

    You can use this event to hide an indicator that your website is busy downloading images.

    AppGeo-geo-f763e47/docs/geomap/services.html0000664000175000017500000003403112005347446017665 0ustar daviddavid services | geomap

    services

    type Array
    default
    [ {
      "class": "osm",
      type: "tiled",
      src: function( view ) {
        return "http://otile" + ((view.index % 4) + 1) + ".mqcdn.com/tiles/1.0.0/osm/" + view.zoom + "/" + view.tile.column + "/" + view.tile.row + ".png";
      },
      attr: "<p>Tiles Courtesy of <a href='http://www.mapquest.com/' target='_blank'>MapQuest</a> <img src='http://developer.mapquest.com/content/osm/mq_logo.png'></p>"
    } ] );
    init
    $( selector ).geomap( { services: [ {
      "class": "osm",
      type: "tiled",
      src: function( view ) {
        return "http://tile.openstreetmap.org/" + view.zoom + "/" + view.tile.column + "/" + view.tile.row + ".png";
      },
      attr: "&copy; OpenStreetMap &amp; contributors, CC-BY-SA",
      style: {
        visibility: "visible",
        opacity: 1.0
      }
    } ] } );
    get
    var services = $( selector ).geomap( "option", "services" );
    set
    $( selector ).geomap( "option", "services", [ {
      id: "openstreetmap",
      type: "tiled",
      src: function( view ) {
        return "http://tile.openstreetmap.org/" + view.zoom + "/" + view.tile.column + "/" + view.tile.row + ".png";
      },
      attr: "&copy; OpenStreetMap &amp; contributors, CC-BY-SA"
    } ]

    The services option is an array of service objects. The service objects are JavaScript objects that control how the geomap widget displays map images.

    service object

    A service object has six properties, two of which are required. The id and class properties are optional but at least one is recommended so you can target specific services with the toggle and opacity methods.

    id

    Each service can have an id that distinguishes it from other service objects in the array. The id is a string and must be follow the HTML element id naming conditions. If present, the id must be unique across all services in all maps as well as unique from any other HTML element on the page. The default service object of a geomap widget does not have an id.

    class

    Each service can have a class as well. The class is a string and must be follow the CSS class naming conditions. You can consider this as the class of images the service will supply and usually name it after the service, such as osm, mass-gis, etc. The default service object of a geomap widget has the class: osm.

    All services also get the class geo-service whether you supply a class to the service object or not. Therefore, the default service is both .osm (as part of its service object) and .geo-service (as added by the widget).

    Unfortunately, class is a reserved word in JavaScript. When you specify class in your service object, you must quote the word class. This is exactly how it's done in jQuery itself when applying attributes to an element based on an object. To quote the jQuery API:

    The name "class" must be quoted since it is a JavaScript reserved word, and "className" cannot be used since it is not the correct attribute name.

    type

    A service object has a type property which is either "tiled" or "shingled". Tiled servies will get one image request per tile needed to fill a given view when the map refreshes. The tile request's bbox will only be the size of the given tile. Shingled services will get only one image request each time the map refreshes and the bbox will be the extent of the whole map view.

    src

    The src property of a service object can be one of the following three options:

    • a function that accepts an object specifying information about the current image request which returns a URL to an image or null to indicate that no image is available or required
    • a function that accepts an object specifying information about the current image request which returns a jQuery Promise object and, later, calls either resolve passing a URL to an image or reject to indicate that no image is available
    • a template string that the geomap widget can use to build a URL itself

    For tiled services, the image is placed at the tile location specified. For shingled services, the image will fill the whole map view.

    If the browser's request of the image results in a 404 status the map will not show that tile or image.

    When src is a function, the argument to that function has the following properties:

    bbox (Array)A GeoJSON bounding box of the current tile or image in map units. The map unit type (projected or geodetic) depends on how you last set the bbox or center options on the geomap widget.
    width (Number)The width of the tile or image in pixels.
    height (Number)The height of the tile or image in pixels.
    zoom (Number)The current zoom level of the map during this request.
    tile (Object)If the service is tiled, this object has column and row properties specifying the location of the tile of this request in the current zoom, otherwise it is null.
    index (Number)A whole number which is usually incremented between requests that you can use to cycle image URLs to different index, e.g., if there are four servers hosting the same tile images named tile0, tile1, tile2 and tile3 you can target them in your src function with the string: "tile" + (view.index % 4).

    You can use the properties of this argument to build and return a URL (or initiate an AJAX request and return a Promise).

    For more infomration about returning a jQuery Promise, please read the section on Deferred Objects in the jQuery API documentation. It might useful to know that, as of jQuery 1.5, the $.ajax method returns a Promise object. If your ajax call returns a URL to an image, your src function can look something like this:

    src: function ( view ) { return $.ajax( { ... } ); }

    When src is a string, those same properties can be used in the template by surrounding each property with: {{:propertyName}}.

    The default value for src is a function because it is slightly faster than rendering a template and we have better control of the view.index property. However, as an example, we can rewrite the default src function as a template string:

    Note: Alpha releases used a {{= }} syntax but there is a breaking change in the beta version due to changes in jsRender. Please use the new {{: }} syntax.

    src: "http://otile1.mqcdn.com/tiles/1.0.0/osm/{{:zoom}}/{{:tile.column}}/{{:tile.row}}.png"

    A couple advantages of using a string are that it is more concise and, unlike a function, can be stored as JSON.

    You do not have to have template parameters in the string, so if you want a static map image, you can set src to a static URL.

    attr

    The attr property is optional. It stands for attribution and is a way to give credit to the source of your map imagery. It defaults to an empty string if not specified in a service object. When present, the map widget displays the HTML provided on the bottom-left corner of the map when the service is visible. Users can click links but cannot interact with all other text or images.

    style

    The style property is optional. It contains presentation options for the service.

    The visibility property defaults to "visible". It determines whether or not the map will show images from this service while refreshing. You can change the visibility of a service either by changing the visibility property of the service object to "visible" or "hidden" and then setting geomap's services option or by using the toggle method of the geomap widget. The latter is recommended because it is a lot faster and does not cause services to be recreated.

    The opacity defaults to 1.0. It determines how transparent a service is when it is visible. Valid values are floating point numbers between 0 and 1 inclusive. Services with an opacity of 0 will not show on the map even if visible is true. You can change the opacity of a service either by changing the opacity property of the service object and then setting geomap's services option or by using the opacity method of the geomap widget. The latter is recommended because it is a lot faster and does not cause services to be recreated.

    modifying services

    By default, the geomap widget starts with one service object in the services array. The default service object will display OpenStreetMap data via mapquest open tiles. Setting the services option will replace all existing services with a new set that you specify. You can set a specific part of of a specific service by getting the current array, modifying, adding, or deleting one of the service objects and then re-setting the services option with the modified array.

    Note: It is always better to set the services option once, during init, rather than adding or modifying services after the map has been created. Some of the following samples show that it is possible to modify the services option after map initialization through the services option even though it's not recommended.

    // create a map
    var map = $( "#map" ).geomap( );
    
    // get the current services array
    var services = map.geomap( "option", "services" );
    
    // add a service
    services.push( {
      id: "Ortho_MapQuest",
      type: "tiled",
      src: function (view) {
        return "http://oatile" + ((view.index % 4) + 1) + ".mqcdn.com/naip/" + view.zoom + "/" + view.tile.column + "/" + view.tile.row + ".png";
      },
      attr: "<p>Tiles Courtesy of <a href='http://www.mapquest.com/' target='_blank'>MapQuest<a> <img src='http://developer.mapquest.com/content/osm/mq_logo.png'><p>"
    } );
    
    // hide the first service in the services array
    services[ 0 ].style.visibility = "hidden";
    
    // re-set the services option
    map.geomap( "option", "services", services );

    The following code is more efficient than the last sample:

    // build an array of service objects ahead of time
    var services = [ {
      id: "OSM",
      type: "tiled",
      src: "http://tile.openstreetmap.org/{{:zoom}}/{{:tile.column}}/{{:tile.row}}.png",
      attr: "&copy; OpenStreetMap &amp; contributors, CC-BY-SA"
      style: { visibility: "hidden" } // default to hidden
    }, {
      id: "Ortho_MapQuest",
      type: "tiled",
      src: function (view) {
        return "http://oatile" + ((view.index % 4) + 1) + ".mqcdn.com/naip/" + view.zoom + "/" + view.tile.column + "/" + view.tile.row + ".png";
      },
      attr: "<p>Tiles Courtesy of <a href='http://www.mapquest.com/' target='_blank'>MapQuest<a> <img src='http://developer.mapquest.com/content/osm/mq_logo.png'><p>"
    } ];
    
    // create a map with all services in place
    var map = $( "#map" ).geomap( { services: services } );

    To change visibility or opacity of a service after you have created the map, you should use the toggle or opacity methods.

    AppGeo-geo-f763e47/docs/geomap/geomapdblclick.html0000664000175000017500000000412212005347446021000 0ustar daviddavid dblclick | geomap

    dblclick

    type position
    init
    $( selector ).geomap( {
      dblclick: function( e, geo ) { }
    } );
    bind
    $( selector ).bind( "geomapdblclick", function( e, geo ) { } );
    } );

    The dblclick event triggers when the user double-clicks or double-taps a point on the map. However, it only triggers if the user is not currently performing some other action which might be handled internally by the widget.

    The geo argument is a GeoJSON Point object of the clicked location in map coordinates.

    The default action for a double-click/tap is to zoom the map in one level. However, as a developer you can override this by calling e.preventDefault() in your callback.

    $( "#map" ).geomap( {
      dblclick: function( e, geo ) { e.preventDefault(); }
    } );
    AppGeo-geo-f763e47/docs/geomap/toggle.html0000664000175000017500000000610412005347446017323 0ustar daviddavid toggle | geomap

    toggle

    return type undefined
    syntax $( map or service selector ).geomap( "toggle" [ , Boolean show_or_hide ] )
    usage
    $("#map").geomap( "toggle" )
    $("#map .osm").geomap( "toggle", false )

    This method toggles or sets the visibility property of service objects in the services array.

    If you call toggle directly on geomap's div element, it will apply to all services. You can target individual services using a CSS selector based on the map div id and the class supplied for the service in its service object or just the id of the service if supplied in its service object.

    // for example, given the following as the map div
    <div id="map"></div>
    
    // and initializing geomap with the following services
    $("#map").geomap({
      services: [
        {
          id: "water",
          class: "mass-gis",
          type: "shingled",
          src: function ( view ) { return null; }
        },
        {
          id: "towns",
          class: "mass-gis",
          type: "shingled",
          src: function ( view ) { return null; }
        },
        {
          id: "harbor-cruise",
          type: "shingled",
          src: function ( view ) { return null; }
        }
      ]
    });
    
    // you can later hide all services
    $("#map").geomap("toggle", false);
    
    // all mass-gis services
    $("#map .mass-gis").geomap("toggle", false);
    
    // or a specific service
    $("#harbor-cruise").geomap("toggle", false);

    If the optional boolean value is not supplied, the visibility of the services will be toggled.

    The change will happen immediately and you do not need to call refresh. This is recommended over manually changing the visibility property of the service object as it does not cause other services to refresh.

    AppGeo-geo-f763e47/docs/geomap/destroy.html0000664000175000017500000000300212005347446017525 0ustar daviddavid destroy | geomap

    destroy

    return type undefined
    syntax .geomap( "destroy" )
    usage
    $("#map").geomap( "destroy" )

    Every good widget will clean up after itself. Call destroy to turn your interactive map back to a boring old div. Any content inside the div before you initialized geomap will remain intact.

    AppGeo-geo-f763e47/docs/geomap/axisLayout.html0000664000175000017500000000502212005347446020202 0ustar daviddavid axisLayout | geomap

    axisLayout

    type String
    default "map"
    init
    $( selector ).geomap( { axisLayout: "map" } );
    get
    var axisLayout = $( selector ).geomap( "option", "axisLayout" );
    set
    $( selector ).geomap( "option", "axisLayout", "image" );

    The axisLayout option determines direction of the coordinate system axes. It can be "map" or "image".

    Maps have a traditional mathematical coordinate system where the ordinate-axis (y-axis) points up. However, graphical images flip the y-axis so that moving down increases in value, which is appropriate in graphic contexts. This is important when you are connecting to a service supplying non-georeferenced (computer graphic) images and want your map control to match that coordinate system layout.

    You will rarely have to change this unless you are using an graphic image server such as LizardTech Image Server or you just want to use the geomap widget to draw pixel-oriented graphics.

    This option will affect pixel-to-map coordinate calculation for all service types, i.e., tiled & shingled services.

    AppGeo-geo-f763e47/docs/geomap/geomapclick.html0000664000175000017500000000350112005347446020316 0ustar daviddavid click | geomap

    click

    type position
    init
    $( selector ).geomap( {
      click: function( e, geo ) { }
    } );
    bind
    $( selector ).bind( "geomapclick", function( e, geo ) { } );
    } );

    The click event triggers when the user clicks or taps a point on the map and then lets go at the same point within a short time threashold. However, it only triggers if the user is not currently performing some other action which might be handled internally by the widget.

    The geo argument is a GeoJSON Point object of the clicked location in map coordinates.

    AppGeo-geo-f763e47/docs/geomap/index.html0000664000175000017500000003705412005347446017161 0ustar daviddavid geomap | jQuery Geo

    geomap widget

    Once you have an HTML element to target, you can call the geographic map widget's function.

    .geomap( options )

    overview

    The widget creates an interactive map. Users can pan and zoom on desktop and mobile browsers against many different cached tile sets or dynamic map servers. Developers can handle events triggered by user action.

    options

    The options argument is a JavaScript object that configures the map widget during the first instantiation on a div. No options are required. By default the map will show the whole world using the mapquest open tile set.

    After initializing a map with your first geomap call, you can get or set most of these options using the following syntax:

    // get the current value of a single option
    var optionValue = $( map selector ).geomap( "option", optionName );
    
    // set a new value for a single option
    $( map selector ).geomap( "option", optionName, newValue );
    
    // set new values for multiple options at the same time
    $( map selector ).geomap( "option", {
      optionName: newValue,
      optionName: newValue
    } );

    One exception is pixelSize, which is read-only.

    The map view refreshes when you change these options: bbox, center, services, tilingScheme, bboxMax, & zoom.

    projection

    The geomap widget will match how you use projection with map units. The map unit type (projected or geodetic) you used when you last set the bbox, bboxMax, or the center option will be used as output for options and as values for arguments. If you never set the bbox or center options, the geomap widget will return geodetic coordinates.

    For example, if you set the map's center option using geodetic coordinates (a longitude, latitude array), future requests for the value of the map's center or bbox options will be returned in geodetic coordinates. However, if you later set the bbox option using web mercator, future requests for the center or bbox options will be returned in that projection.

    Changing bbox or center will affect all options and arguments that use map units. The options and arguments involved are:

    • bbox option
    • bboxMax option
    • center option
    • bbox property of the services object's src argument
    • GeoJSON objects passed as the geo argument in all events
    • return value of the toMap method

    To avoid confusion, it is recommended to stick to one map unit type for any single map widget.

    The geomap widget will use the $.geo.proj object when needed to convert between geodetic and projected coordinates.

    events

    All event callbacks receive two arguments: the original browser event and an object specific to the map action.

    The map unit type (projected or geodetic) of the map event arguments depends on the way you initialize the map widget. If you have set the center or bbox option using geodetic coordinates, the event arguments will also be in geodetic coordinates.

    Like jQuery UI widgets, geomap triggers events directly on the original map div.

    Programatic changes to options do not trigger events.

    The dblclick event is special in that you can prevent the default action, zoom-in one level, by calling e.preventDefault() in your callback. This is currently the only geomap event that you can prevent the default action. Calling preventDefault in the callback of any other geomap event has undefined results.

    There are four geomap event types. The type of event determines what is sent to your event handler as the second argument, geo.

    position events

    With position events the geo argument to your callback is a GeoJSON Point object having two properties: type & coordinates. The coordinates property is a single GeoJSON position, i.e., an array containing the x/longitude and y/latitude value.

    The geo argument to your callback is a true GeoJSON object and you can pass this object directly to the append method. You can also send it directly to a database for storage knowing that there are no non-GeoJSON properties wasting space.

    bbox events

    With bbox events the geo argument to your callback is an object with single property, bbox, which is a GeoJSON bounding box.

    shape events

    With shape events, the geo argument to your callback is a GeoJSON geometry object having two properties: type & coordinates. The object type will be either Point, LineString or Polygon depending on the current geomap mode: measureLength, measureArea, drawPoint, drawLineString, and drawPolygon.

    The geo argument to your callback is a true GeoJSON object and you can pass this object directly to the append method. You can also send it directly to a database for storage knowing that there are no non-GeoJSON properties wasting space.

    load events

    With load events, the geo argument is currently undefined. You can add the argument to your handler's argument list if you wish but attempting to access any property on it will cause a JavaScript error.

    methods

    The geomap widget provides some methods to help make interacting map data a little easier.

    unit conversion

    Convert positions between pixel and map coordinates.

    map methods

    These methods update the map widget as a whole.

    service modification

    Methods that help update objects in the services array.

    shapes

    These methods manage geometry or features drawn on the geomap widget itself or on individual servies within the map.

    The find method allows you to search for shapes appended to the map. Its syntax and service-level operation is slightly different than the other three shape methods so the link is visually broken out from the rest.

    style

    A geomap style is an object whose properties follow a subset of SVG styling properties. The specific styles that geomap recognizes and to which geometry they apply are listed below.

    Use the drawStyle option of the geomap widget to define the style used on incomplete lines and polygons as they are being drawn when mode is drawLineString or drawPolygon.

    Use the shapeStyle option to define the style of shapes drawn after being appended to the map via the append method.

    Please note that in drawPoint mode, the shape event is triggered immediately and so no shape will appear until you append a point to the map at which time the shapeStyle will be used.

    geomap style properties

    property default description
    borderRadius "8px" The radii of a quarter ellipse that defines the shape of the corner of the outer border of a box drawn around Point shapes, which means it turns your boxes into curved rectangles. If the width, height and borderRadius properties of a style are the same (the default), the point is drawn as a circle.
    color #7f0000 An indirect, fallback value for the fill and stroke properties if they are not set.
    fill undefined Color to use when drawing the interior of a shape. The area to be drawn consists of any areas inside the outline of the shape. By default, fill will use the value of the color property.
    fillOpacity .2 Specifies the opacity of the drawing operation used to draw the interior of a shape. The final fill opacity also depends on the value of the opacity property.
    height "8px" The height of a box drawn around Point shapes. Currently only pixel values are allowed. If either width or height are zero, no shape is drawn for the Point.
    opacity 1 The object opacity of the entire shape. This is a multiplicative operation when determining the final fillOpacity and strokeOpacity where any fill or stroke operation is made even more translucent if this value is below 1.0.
    stroke undefined Color to use when drawing along the outline of a shape. By default, stroke will use the value of the color property.
    strokeOpacity 1 Specifies the opacity of the drawing operation used to draw the outline of a shape. The final stroke opacity also depends on the value of the opacity property.
    strokeWidth "2px" The width of the stroke of a shape. A zero value causes no stroke to be drawn. Currently only pixel values are allowed.
    visibility "visible" Determines if the shape is drawn ("visible") or not drawn ("hidden") on the map. Shapes that are hidden can still be returned by the find method.
    width "8px" The width of a rounded rectangle drawn around Point shapes. Currently only pixel values are allowed. If either width or height are zero, no shape is drawn for the Point.

    All properties apply to Point shapes which means that you can adjust the stroke and fill of the box surrounding the point location.

    AppGeo-geo-f763e47/docs/geomap/remove.html0000664000175000017500000000741712005347446017347 0ustar daviddavid remove | geomap

    remove

    return type jQuery collection
    syntax .geomap( "remove", Object shape ( GeoJSON object ) | Array<Object> shapes [ , Boolean refresh ] )
    usage
    $( map or service selector ).geomap( "remove", existingShape )
    $( map or service selector ).geomap( "remove", existingShape, false )
    $( map or service selector ).geomap( "remove", [ existingShape1, existingShape2 ] )

    The remove method removes a shape (or array of shapes) that you have previously added with the append method. The existing shapes can be an object references used in a call to append which you have held on to or ones that you retrieved by using the find method.

    The jQuery UI widget factory returns the original jQuery collection to maintain call chaining.

    delaying refresh

    The optional refresh argument determines if geomap refreshes the map graphics after this call to remove. It defaults to true. If you pass false, geomap will remove the shape internally but not immediately redraw the graphics. The changes will display if the user moves the map or you call geomap's refresh method.

    If the shape is not found on the specified service, the map is not changed and will not be refreshed even if you pass true for the refresh argument.

    service-level shapes

    Similar to how you can append shapes to specific services, you can remove shapes from specific services as well.

    You do this by targeting a service inside a map instead of the map itself for your call to geomap's remove method. For example, the default map service has the CSS class: osm. We can remove a shape from that service specifically by using jQuery to target the service:

    $( "#map .osm" ).geomap( "remove", shape );

    Shapes appended to a specific service will not be removed by calling remove on the map itself. For example, the shape will remain after this sequence:

    $( "#map .osm" ).geomap( "append", shape );
    $( "#map" ).geomap( "remove", shape );

    To remove all references to a shape from the map and all services, you can use the comma selector and the built-in geo-service CSS class:

    // remove the shape from both the map widget and any services
    $( "#map,#map .geo-service" ).geomap( "remove", shape );
    AppGeo-geo-f763e47/docs/geomap/scroll.html0000664000175000017500000000502112005347446017335 0ustar daviddavid scroll | geomap

    scroll

    type String
    default "default"
    init
    $( map selector ).geomap( { scroll: "default" } );
    get
    var scroll = $( map selector ).geomap( "option", "scroll" );
    set
    $( map selector ).geomap( "option", "scroll", "off" );

    The scroll option determines what the map widget does when the user rotates a mouse wheel. There are currently three values: default, zoom, and off. However, default is currently the same as zoom.

    When scroll is default or zoom, users can use a mouse wheel to zoom the map in or out.

    When set to off, mouse wheel scrolling is ignored. This is useful when the document itself or a section that contains the map requires scrolling due to content. A desktop user will expect to be able to use the mouse wheel to scroll the document and you don't want the map to interfere. For example, if the user's mouse cursor is over a map that's part of a long document, there's a greater chance they will want the mouse wheel to scroll document instead of zooming the map. Set the scroll property to "off" to ensure the wheel will work as expected.

    AppGeo-geo-f763e47/docs/geomap/center.html0000664000175000017500000000426512005347446017330 0ustar daviddavid center | geomap

    center

    type Array (GeoJSON position)
    default [ 0, 0 ]
    init
    $( selector ).geomap( { center: [ 0, 0 ] } );
    get
    var center = $( selector ).geomap( "option", "center" );
    set
    $( selector ).geomap( "option", "center", [ -71.037598, 42.363281 ] );

    The center property gets or sets the center point of the map. By default the value is in geodetic coordinates, e.g., longitude, latitude. You can change the default when you initialize the widget by passing projected coordinates as the center option.

    Setting a new center point will refresh the map services.

    If you attempt to initialize both center and bbox at the same time when creating a geomap widget, center will override bbox.

    AppGeo-geo-f763e47/docs/geomap/append.html0000664000175000017500000003317212005347446017316 0ustar daviddavid append | geomap

    append

    return type jQuery collection
    syntax .geomap( "append", Object shape ( GeoJSON object ) | Array<Object> shapes [ , Object style ( geomap style ) ] [ , String label ] [ , Boolean refresh ] )
    usage
    // a single point, no style, no label, refresh immediately
    $(map or service selector).geomap( "append", { type: "Point", coordinates: [ -71, 40 ] } )
    
    // a single line, don't refresh yet
    $(map or service selector).geomap( "append", {
      type: "LineString",
      coordinates: [ [ -71, 40 ], [ -71.5, 41 ] ]
    }, false )
    
    // a polygon with a style
    $(map or service selector).geomap( "append", {
      type: "Polygon",
      coordinates: [ [ 
        [-75, 39.7],
        [-74.8, 39.3],
        [-75.2, 39.3],
        [-75, 39.7]
      ] ]
    }, { stroke: "#11117f", strokeWidth: "3px" } )
    
    // an array of geometry objects with a style, don't refresh yet
    $(map or service selector).geomap( "append", [ 
      { type: "Point", coordinates: [ -71, 40 ] },
      { type: "Point", coordinates: [ -70, 39.5 ] },
    ], { color: "green", strokeWidth: "3px" }, false )
    
    // a point feature with a label
    $(map or service selector).geomap( "append", {
      type: "Feature",
      geometry: {
        type: "Point",
        coordinates: [ -71, 40 ]
      }
    }, "My Point" )
    
    // a point with a label, don't refresh yet
    $(map or service selector).geomap( "append", { type: "Point", coordinates: [ -71, 40 ] }, "My Point (don't refresh yet)", false )
    
    // a point with a style & label
    $(map or service selector).geomap( "append", { type: "Point", coordinates: [ -71, 40 ] }, { color: "#00f" }, "Blue Point" )
    
    // a collection of features with a style, each point will get a separate label, don't refresh yet
    $(map or service selector).geomap( "append", {
        type: "FeatureCollection"
        features: [ {
          type: "Feature",
          geometry: {
            type: "Point",
            coordinates: [ -71, 40 ]
          }
        }, {
          type: "Feature",
          geometry: {
            type: "Point",
            coordinates: [ -71.2, 40.3 ]
          }
        } ]
      },
      { color: "#00f" },
      '<span style="color: #44f;">Blue Point</span>',
      false
    )

    The append method adds one shape or an array of shapes to the map. In this documentation, the word shape means a GeoJSON geometry object or a GeoJSON Feature. A FeatureCollection is treated as an array of shapes.

    When you append more than one shape by using an array or a FeatureCollection, each shape in the array or FeatureCollection's features property is added as a separate shape whereas the other collection geometry types, e.g., MultiPoint, are added as a single shape. This is an important distinction when considering the find method and labels. The find method can potentially return only one shape from an array or one feature of a FeatureCollection but will return all shapes in a MultiPoint (as a reference to the original MultiPoint object supplied to append) even if only one of the coordinates in the MultiPoint intersects the find position. For labeling, each shape in an array and each feature in a FeatureCollection get their own label, however all polygons in a MultiPolygon will share the same label.

    The geomap widget maintains a reference to your shape. You can use the same object in calls to remove in order to remove the shape from the map at any time.

    The jQuery UI widget factory returns the original jQuery collection to maintain call chaining.

    styling

    The optional style argument modifies how geomap draws the specific geometry or feature you are adding. Properties supplied in this style will override ones of the same name in geomap's base shapeStyle. Properties not referenced are inheritied from the base style and can change with future changes to the shapeStyle option. Please see the shapeStyle method documentation for information about what properties are valid for this object.

    labeling

    The optional label argument will display a label near the shape. Labels are a powerful way to add text, pixel-based graphics, or other HTML and CSS effects to the map. The label string can be any text or HTML. For example, consider the following:

    • you append a Point shape setting its style to have zero for width and height:
      { width: "0px", height: "0px" }
    • you also supply a label of nothing more than a div element with a class:
      '<div class="marker"></div>'
    • in a CSS style sheet, you give the marker class a width, height, background image and negative relative position:
      .marker
      {
        width: 8px;
        height: 8px;
        background: url(../img/marker.png);
        position: relative;
        left: -4px;
        top: -4px;
      }

    In the above example, marker.png will be centered on every point added with a similar label. The regular shape style will not show because the point style has no size.

    For Point shapes, the top-left of the label is positioned at the Point's only coordinate. For LineString shapes, the label is usually positioned 50% along the shape but will be forced into view if its usual position is out of the map's current bbox. For Polygon shapes, the label is usually positioned at the centroid but will be forced into view if its usual position is out of the map's current bbox. All other non-basic shape types use the shape's centroid.

    The geomap widget uses a div to position the labels. The div exists inside a container for the service. The div has the CSS class: geo-label. You can use this design to apply regular CSS style to all labels or all labels within a service. The following snippets show examples of using this, assuming the main map div has the id "map" and the default map service (which has the CSS class "osm") has not been changed.

    JavaScript

    /* add a point to the map itself */
    $( "#map" ).geomap( "append", { type: "Point", coordinates: [ -71, 40 ] }, "map point" );
    
    /* add a point to the default map service */
    $( "#map .osm" ).geomap( "append", { type: "Point", coordinates: [ -70, 40 ] }, "service point" );
    

    CSS

    /* turn the color of all labels blue */
    #map .geo-label { color: blue; }
    
    /* make labels on the default basemap service bold */
    #map .osm .geo-label { font-weight: bold; }

    One caveat is that, to keep performance high, jQuery Geo will not create the .geo-label container if you do not at least pass an empty string as the label. So, if you want to do something similar to the marker example above, but using the already provided .geo-label div, you will need to pass an empty string as the label.

    Each .geo-label div is absolutely positioned to the correct location in the map view. Please keep that in mind because changing the position, left or top CSS properties on the .geo-label class may affect your labels drastically.

    delaying refresh

    The optional refresh argument determines if geomap refreshes the map graphics after this call to append. It defaults to true. If you pass false, geomap will add the shape internally but not immediately redraw the graphics. The changes will display if the user moves the map or you call geomap's refresh method.

    service-level shapes

    The geomap widget allows you to append a shape to a specific service. You do this by targeting a service inside a map instead of the map itself for your call to geomap's append method. For example, the default map service has the CSS class: osm. We can append a shape to that service specifically by using jQuery to target the service:

    $( "#map .osm" ).geomap( "append", shape );

    Some of the important advantages with this syntax are:

    • you can show or hide shapes as you toggle a service because shapes attached to a service are only visible if the service is visible
    • service-level shapes draw in the order of their service in the services option which gives you finer control over how they look
    • shapes on the map itself always draw above service-level shapes
    • you can style shapes differently depending on their service using a service-level shapeStyle option

    duplicate shapes

    You can add the same GeoJSON object to more than one service, which allows you to give the same object two different styles at the same time. To do this, call append twice with the same object. Once on one service (or the map itself) and a second time on a different service.

    You can also do this at the same time by using the comma selector in one call to append:

    // set the basemap service's shapeStyle option to a white halo effect
    $( "#map .osm" ).geomap( "option", "shapeStyle", { strokeWidth: "8px", color: "#dedede" } );
    
    // append the shape to both the map widget and basemap service
    $( "#map,#map .osm" ).geomap( "append", shape );

    updating

    If you attempt to add a shape to the map or a service where it already exists, the shape will remain but you will update (or remove) the shape's style or label.

    // add the shape with a green color
    $( "#map" ).append( shape, { color: "green" } );
    
    // change the color to blue (shape is the same object as before in this case)
    $( "#map" ).append( shape, { color: "blue" } );

    Changing the type of geometry, e.g., from Point to LineString, or coordinates of a shape you have appended is not recommended and geomap's behavior is currently undefined. If you wish to do either of these, you should first call remove on the original object and append on a new one.

    AppGeo-geo-f763e47/docs/geomap/mode.html0000664000175000017500000006373412005347446017002 0ustar daviddavid mode | geomap

    mode

    type String
    default "pan"
    init
    $( selector ).geomap( { mode: "pan" } );
    get
    var mode = $( selector ).geomap( "option", "mode" );
    set
    $( selector ).geomap( "option", "mode", "drawPoint" );

    The mode option determines how the map responds to user interaction and which events jQuery Geo triggers for the developer.

    jQuery Geo puts these modes into four small groups:

    modes

    basic

    Basic modes are most common to what people expect to be able to do with a map: drag it around, zoom it in and out, or just have it sit there an look pretty.

    • static
    • pan
    • zoom

    drag

    Drag modes disable panning and turn single swipes into shape events.

    • dragBox

    draw

    Draw modes turn user clicks into shape events, panning is allowed.

    • drawPoint
    • drawLineString
    • drawPolygon

    measure

    Measure modes display length and area based on clicks and drags.

    • measureLength
    • measureArea

    You are free to set mode to any other string, this is called custom modes in jQuery Geo and described at the end of this page.

    related options

    Each mode has a matching property on the cursors option. For example, to change the cursor for drawPoint mode to an I-beam, you can initialize the geomap widget like this:

    $( selector ).geomap( { cursors: { drawPoint: "text" } } )

    The drawStyle option determines how shapes look while being drawn in all of the draw, drag, and measure modes.

    The measureLabels option determines how the text is formatted while using the measure modes.

    You can remove a user's ability to pan the map by setting the panning option to false. Yes, you can disable panning even when mode is set to "pan".

    You can shut off mouse wheel scroll in any mode by setting the scroll option to "off".

    However, when mode is static, setting panning to true or scroll to "zoom" will not enable panning or mouse wheel zoom. In static mode, the geomap widget ignores the panning and scroll options.

    style

    The label containing the measure length or area text has the geo-measure-label CSS class. To change how the measure text looks, you can update properties in that rule:

    .geo-measure-label { font-size: 1.5em; }

    static

    user experience

    The default cursor is the default arrow pointer.

    The map widget displays tiles and map images as normal but the user cannot interact with them, e.g., the user can't pan or zoom in any way, even if the pannable option is set to true.

    As a developer, you can still call geomap methods and set options in order to change the static map's appearance. Events are not triggered when you change the map programmatically.

    events

    All regular browser events bubble up to parent elements and eventually the document. No widget-specific events trigger. You are free to handle events on the map div as normal events, e.g., click, but you won't get the geo argument. You can ask the map widget for information such as map locations based on the pixel arguments in the event. See the Inset example for help with this.

    pan

    user experience

    The default cursor is an open hand in browsers that support data URIs and a four point arrow otherwise.

    The user can drag the map to pan. The map will continue panning a little after the user lets go. They can zoom in or out with the scroll wheel. They can also double-click or double-tap to zoom in one level. On some multitouch devices, users can use two fingers to "pinch zoom" (currently not available on Android).

    The user can hold the shift key to temporarily switch to zoom mode.

    events

    In pan mode, the geomap widget triggers the following events on the original map div.

    • move – when the user moves the mouse above the map but is not actively panning
    • click – when the user clicks or taps a point on the map without initiating a pan, i.e., they let go of the map at the same point and within a short time threshold
    • dblclick – when the user double-clicks or double-taps a point on the map
    • bboxchange – when the user changes the bbox by panning or zooming

    zoom

    user experience

    The default cursor is a crosshair.

    In this mode the user can perform a marquee zoom by clicking and holding one point and dragging the mouse cursor. A box will form. When the user lets go of the mouse, the map will zoom to the closest approximation of the bbox of the drawn shape.

    Shingled (dynamic) services are only limited by the ratio between the size of the drawn shape and the map div's current size. Cached services are limited to those as well but also specific map zoom levels so the final bbox will not be as close.

    The user can also zoom in or out with the scroll wheel as well as double-click or double-tap to zoom in one level. On some multitouch devices, users can use two fingers to "pinch zoom" (currently not available on Android).

    This is not a very useful mode for mobile applications but provides a more exact method of zooming into an area for desktop users who want it.

    events

    In zoom mode the geomap widget triggers the following events on the original map div.

    • move – when the user moves the mouse above the map but is not actively performing a marquee zoom
    • click – when the user clicks or taps a point on the map without initiating a marquee zoom, i.e., they let go of the map at the same point and within a short time threshold
    • dblclick – when the user double-clicks or double-taps a point on the map
    • bboxchange – when the user changes the bbox by zooming

    dragBox

    user experience

    The default cursor is a crosshair.

    Similar to zoom, in this mode the user can click and hold one point and then drag the mouse cursor. A box will form. When the user lets go of the mouse, jQuery Geo will trigger a shape event passing a GeoJSON Polygon representation of the dragged bbox as the geo argument. The Polygon object also has the GeoJSON the bbox property.

    The user can also click the map instead of dragging a box. In this case, jQuery Geo will still trigger a shape event, but this time it will pass a GeoJSON Point representing the clicked location. The Point object will also have the bbox property with the min and max values matching each other, i.e., bbox[0] (minx) = bbox[2] (maxx) and bbox[1] (miny) = bbox[3] (maxy).

    The user cannot pan the map while in dragBox mode. The user can zoom in or out with the scroll wheel as well as double-click or double-tap to zoom in one level. On some multitouch devices, users can use two fingers to "pinch zoom" (currently not available on Android).

    The user can hold the shift key to temporarily switch to zoom mode.

    events

    In dragBox mode the geomap widget triggers the following events on the original map div.

    • move – when the user moves the mouse above the map but is not actively dragging a bbox
    • dblclick – when the user double-clicks or double-taps a point on the map
    • bboxchange – when the user changes the bbox by zooming
    • shape – when the user lets go of the mouse after dragging to make a bbox, jQuery Geo will send a GeoJSON Polygon object to the developer; this Polygon object has a bbox property which is set to the bbox of the rectangle drawn

    dragCircle

    user experience

    The default cursor is a crosshair.

    In this mode the user can click and hold one point and then drag the mouse cursor. A circle will form from the center outward. When the user lets go of the mouse, jQuery Geo will trigger a shape event passing a GeoJSON Polygon representation of the dragged circle as the geo argument. The Polygon object also has the GeoJSON the bbox property.

    The user can also click the map instead of dragging a circle. In this case, jQuery Geo will still trigger a shape event, but this time it will pass a GeoJSON Point representing the clicked location. The Point object will also have the bbox property with the min and max values matching each other, i.e., bbox[0] (minx) = bbox[2] (maxx) and bbox[1] (miny) = bbox[3] (maxy).

    The user cannot pan the map while in dragCircle mode. The user can zoom in or out with the scroll wheel as well as double-click or double-tap to zoom in one level. On some multitouch devices, users can use two fingers to "pinch zoom" (currently not available on Android).

    The user can hold the shift key to temporarily switch to zoom mode.

    events

    In dragCircle mode the geomap widget triggers the following events on the original map div.

    • move – when the user moves the mouse above the map but is not actively dragging a circle
    • dblclick – when the user double-clicks or double-taps a point on the map
    • bboxchange – when the user changes the bbox by zooming
    • shape – when the user lets go of the mouse after dragging to make a circle, jQuery Geo will send a GeoJSON Polygon object to the developer; this Polygon object has a bbox property which is set to the bbox of the circle drawn

    drawPoint

    user experience

    The default cursor is a crosshair.

    In this mode the user can digitize a Point shape by single-clicking or tapping the map. Apart from the default cursor, this mode is similar to pan in that the user can drag the map to pan. However, to allow a user more accuracy during digitization, the map will not continue panning a little after the user lets go. They can zoom in or out with the scroll wheel. They can also double-click or double-tap to zoom in one level.

    A visual point will appear temporarily until they either let go to draw the point or begin panning.

    Similar to pan mode, the user can drag the map to pan. However, to allow a user more accuracy during digitization, the map will not continue panning a little after the user lets go. They can zoom in or out with the scroll wheel. They can also double-click or double-tap to zoom in one level. On some multitouch devices, users can use two fingers to "pinch zoom" (currently not available on Android).

    The user can hold the shift key to temporarily switch to zoom mode.

    events

    In drawPoint mode, the geomap widget triggers the following events on the original map div. Note that the shape event replaces the click event.

    • move – when the user moves the mouse above the map but is not actively panning
    • dblclick – when the user double-clicks or double-taps a point on the map
    • bboxchange – when the user changes the bbox by panning or zooming
    • shape – when the user clicks or taps a point on the map, this action will send a GeoJSON Point object to the developer

    drawLineString

    user experience

    The default cursor is a crosshair.

    In this mode the user can digitize a LineString shape. The first single-click or tap on the map will begin the shape drawing. Once initialized, subsequent single-clicks will add points to the LineString. Finally, a double-click or tap will end the digitization and trigger the shape event.

    On a non-touch device a visual line will follow the mouse cursor from the last point to show the user the next segment of the line they will draw. On all devices, the next segment becomes visible when the user confirms the next point location by clicking or tapping. At any point, the user can hit the escape key to remove one point or, if there is only one point, stop drawing the shape alltogether.

    Similar to pan mode, the user can drag the map to pan, even while drawing a shape. However, to allow a user more accuracy during digitization, the map will not continue panning a little after the user lets go. They can zoom in or out with the scroll wheel. While not drawing, they can also double-click or double-tap to zoom in one level. On some multitouch devices, users can use two fingers to "pinch zoom" (currently not available on Android).

    The user can hold the shift key to temporarily switch to zoom mode.

    events

    In drawLineString mode, the geomap widget triggers the following events on the original map div.

    • move – when the user moves the mouse above the map but is not actively panning, this event triggers even while drawing a shape
    • click – when the user clicks or taps a point on the map without initiating a pan, this event triggers even while drawing a shape
    • dblclick – when the user double-clicks or double-taps a point on the map but is not actively drawing
    • bboxchange – when the user changes the bbox by panning or zooming
    • shape – when the user double-clicks or taps a point on the map after beginning a drawing operation with a single click, this action will send a GeoJSON LineString object to the developer

    drawPolygon

    user experience

    The default cursor is a crosshair.

    In this mode the user can digitize a Polygon shape. The first single-click or tap on the map will begin the shape drawing. Once initialized, subsequent single-clicks will add points to the Polygon. Finally, a double-click or tap will end the digitization and trigger the shape event.

    On a non-touch device two visual lines will follow the mouse cursor. One from the last point to show the user the next segment of the Polygon they will draw, the other from the first point to show the user an extra segment that will complete the Polygon. On all devices, the next segment becomes visible when the user confirms the next point location by clicking or tapping. At any point, the user can hit the escape key to remove one point or, if there is only one point, stop drawing the shape alltogether.

    Similar to pan mode, the user can drag the map to pan, even while drawing a shape. However, to allow a user more accuracy during digitization, the map will not continue panning a little after the user lets go. They can zoom in or out with the scroll wheel. While not drawing, they can also double-click or double-tap to zoom in one level. On some multitouch devices, users can use two fingers to "pinch zoom" (currently not available on Android).

    The user can hold the shift key to temporarily switch to zoom mode.

    events

    In drawPolygon mode, the geomap widget triggers the following events on the original map div.

    • move – when the user moves the mouse above the map but is not actively panning, this event triggers even while drawing a shape
    • click – when the user clicks or taps a point on the map without initiating a pan, this event triggers even while drawing a shape
    • dblclick – when the user double-clicks or double-taps a point on the map but is not actively drawing
    • bboxchange – when the user changes the bbox by panning or zooming
    • shape – when the user double-clicks or taps a point on the map after beginning a drawing operation with a single click, this action will send a GeoJSON Polygon object to the developer

    measureLength

    user experience

    The default cursor is a crosshair.

    In this mode the user can visually measure the length of lines on the map. The first single-click or tap on the map will begin the measurement. Once initialized, subsequent single-clicks or taps will add points to a LineString being measured. Whenever the mouse moves, a label follows the cursor which displays the total length so far. Touch devices will only see an updated measurment when they add a new point. A double-click or tap will end the measurement and remove all graphics and labels.

    On a non-touch device a visual line will follow the mouse cursor from the last point to show the user the next segment of the line they are measuring and update the measurement. On all devices, the next segment becomes visible when the user confirms the next point location by clicking or tapping. At any point, the user can hit the escape key to remove one point or, if there is only one point, stop measuring alltogether.

    Similar to pan mode, the user can drag the map to pan, even while measuring. The map will continue panning a little after the user lets go. They can zoom in or out with the scroll wheel. While not measuring, they can also double-click or double-tap to zoom in one level. On some multitouch devices, users can use two fingers to "pinch zoom" (currently not available on Android).

    The user can hold the shift key to temporarily switch to zoom mode.

    By default the unit of measurment is meters because the default projection is web mercator meters. If you change the tilingScheme (on tiled services) or switch to a shingled service, the unit of measurment will be based on your new service's units.

    events

    In measureLength mode, the geomap widget triggers the following events on the original map div.

    • move – when the user moves the mouse above the map but is not actively panning, this event triggers even while measuring
    • click – when the user clicks or taps a point on the map without initiating a pan, this event triggers even while measuring
    • dblclick – when the user double-clicks or double-taps a point on the map but is not actively measuring
    • bboxchange – when the user changes the bbox by panning or zooming
    • shape – when the user double-clicks or taps a point on the map after beginning a measure operation with a single click, this action will send a GeoJSON LineString object to the developer

    measureArea

    user experience

    The default cursor is a crosshair.

    In this mode the user can visually measure an area on the map. The first single-click or tap on the map will begin the measurement. Once initialized, subsequent single-clicks or taps will add points to a Polygon being measured. Whenever the mouse moves, a label follows the center of the polygon that displays the total area so far. Touch devices will only see an updated measurment when they add a new point. A double-click or tap will end the measurement and remove all graphics and labels.

    On a non-touch device two visual lines will follow the mouse cursor. One from the last point to show the user the next segment of the Polygon they will draw, the other from the first point to show the user an extra segment that will complete the Polygon we need to calculate area. On all devices, the next segment becomes visible when the user confirms the next point location by clicking or tapping. At any point, the user can hit the escape key to remove one point or, if there is only one point, stop measuring alltogether.

    Similar to pan mode, the user can drag the map to pan, even while measuring. The map will continue panning a little after the user lets go. They can zoom in or out with the scroll wheel. While not measuring, they can also double-click or double-tap to zoom in one level. On some multitouch devices, users can use two fingers to "pinch zoom" (currently not available on Android).

    The user can hold the shift key to temporarily switch to zoom mode.

    By default the unit of measurment is meters because the default projection is web mercator meters. If you change the tilingScheme (on tiled services) or switch to a shingled service, the unit of measurment will be based on your new service's units.

    events

    In measureArea mode, the geomap widget triggers the following events on the original map div.

    • move – when the user moves the mouse above the map but is not actively panning, this event triggers even while measuring
    • click – when the user clicks or taps a point on the map without initiating a pan, this event triggers even while measuring
    • dblclick – when the user double-clicks or double-taps a point on the map but is not actively measuring
    • bboxchange – when the user changes the bbox by panning or zooming
    • shape – when the user double-clicks or taps a point on the map after beginning a measure operation with a single click, this action will send a GeoJSON Polygon object to the developer

    custom modes

    As mentioned above, you can also set mode to any other string. It will behave exactly like pan mode. However, you can set a different cursor:

    var map = $( "#map" ).geomap( {
      mode: "click",
      cursors: { click: "crosshair" }
    } );

    The above example creates a new custom mode, click, and sets the geomap widget to that mode during initialization. When the widget is in this mode, it will behave exactly like pan, but have a crosshair. This means you will get all the same events as pan: move, click, dblclick & bboxchange. A mode like this is useful if you want to give users more accuracy when clicking the map.

    Custom modes will still allow panning. While panning, the cursor will temporarily switch to the pan cursor. You can disable panning for your mode by setting the widget's panning option to false whenever you change the mode option.

    function setMode( mode ) {
      map.geomap( "option", {
        mode: mode,
        panning: mode !== "click"
      } );
    }

    In this last example, we create a new map with two modes, find and remove. They both trigger the click event so we can check our current mode and behave differently depending on which one is set, or do nothing if we're not in find or remove mode.

    var map = $( "#map" ).geomap( {
      mode: "drawPoint",
      cursors: {
        find: "crosshair",
        remove: "crosshair"
      },
      shape: function( e, geo ) {
        // only the draw modes trigger this event
        map.geomap( "append", geo );
      },
      click: function( e, geo ) {
        switch( map.geomap( "option", "mode" ) ) {
          case "find":
            // search for shapes but just alert the user
            var shapes = map.geomap( "find", geo, 3 );
            if ( shapes.length > 0 ) {
              alert( "Found " + shapes.length + " shape(s) !" );
            }
            break;
    
          case "remove":
            // search for shapes and remove one of them
            var shapes = map.geomap( "find", geo, 3 );
            if ( shapes.length > 0 ) {
              map.geomap( "remove", shapes[ 0 ] );
            }
            break;
    
          default:
            // ignore the click event for all other modes: pan, zoom, etc.
            break;
        }
      }
    } );
    AppGeo-geo-f763e47/docs/geomap/geomapmove.html0000664000175000017500000000337512005347446020210 0ustar daviddavid move | geomap

    move

    type position
    init
    $( selector ).geomap( {
      move: function( e, geo ) { }
    } );
    bind
    $( selector ).bind( "geomapmove", function( e, geo ) { } );
    } );

    The move event triggers when the user moves the mouse cursor while the cursor is over the map. However, it only triggers if the user is not currently performing some other action such as panning.

    The geo argument is a GeoJSON Point object of the location under the mouse cursor in map coordinates.

    AppGeo-geo-f763e47/docs/geomap/toPixel.html0000664000175000017500000000411612005347446017467 0ustar daviddavid toPixel | geomap

    toPixel

    return type Array (GeoJSON positions)
    syntax .geomap( "toPixel", Array mapPositions )
    usage
    var pixelPos = $("#map").geomap( "toPixel", [ -71.098709, 42.330322 ] )
    var pixelPositions = $("#map").geomap( "toPixel", [ [ -71.098709, 42.330322 ], [ -71.072617, 42.351608 ] ] )

    The toPixel method takes a single GeoJSON position (Point.coordinates), an array of GeoJSON positions (MultiPoint.coordinates or LineString.coordinates), an array of arrays of positions (MultiLineString.coordinates or Polygon.coordinates) or an array of arrays of arrays of positions (MultiPolygon.coordinates). It returns the pixel coordinates for all of the map positions.

    You can pass geodetic (lon, lat) or projected coordinates regardless of how you last set the bbox or center options.

    AppGeo-geo-f763e47/docs/geomap/empty.html0000664000175000017500000000556312005347446017210 0ustar daviddavid empty | geomap

    empty

    return type jQuery collection
    syntax .geomap( "empty" [ , Boolean refresh ] )
    usage
    $( map or service selector ).geomap( "empty" )
    $( map or service selector ).geomap( "empty", false )

    The empty method removes all shapes previously added with the append method.

    The jQuery UI widget factory returns the original jQuery collection to maintain call chaining.

    delaying refresh

    The optional refresh argument determines if geomap refreshes the map graphics after this call to empty. It defaults to true. If you pass false, geomap will remove all shapes internally but not immediately redraw the graphics. The changes will display if the user moves the map or you call geomap's refresh method.

    service-level shapes

    Similar to how you can remove shapes from specific services, you can empty specific services of all shapes as well.

    You do this by targeting a service inside a map instead of the map itself for your call to geomap's empty method. For example, the default map service has the CSS class: osm. We can remove all shapes from that service specifically by using jQuery to target the service:

    $( "#map .osm" ).geomap( "empty" );

    Calling empty on the map widget will not remove shapes that have been appended to services.

    To remove all shapes from the map and all services, you can use the comma selector and the built-in geo-service CSS class:

    // empty the map widget and any services
    $( "#map,#map .geo-service" ).geomap( "empty" );
    AppGeo-geo-f763e47/docs/quickstart/0000775000175000017500000000000012005347446016075 5ustar daviddavidAppGeo-geo-f763e47/docs/quickstart/index.html0000664000175000017500000000605012005347446020073 0ustar daviddavid quickstart | jQuery Geo

    quickstart

    The jQuery Geo plugin has one widget, geomap, that you can instantiate on any div with a computable width and height.

    html

    <div id="map" style="width: 640px; height: 480px;"></div>
    <script src="//code.jquery.com/jquery-1.7.2.min.js"></script>
    <script src="//code.jquerygeo.com/jquery.geo-1.0b1.min.js"></script>

    javascript

    $("#map").geomap();

    By default, this one line of code will create a fully functional map on your page showing the whole world and using OpenStreetMap data via the mapquest open tile set.

    The default units are longitude & latitude degrees which is the most common format for GPS and other online spatial data. You can set the center and zoom of the map at the same time you initialize it by passing a JavaScript object of options.

    $("#map").geomap({
      center: [ -71.037598, 42.363281 ],
      zoom: 10
    });

    Please note that longitude is the first value, x, even though it is commonly spoken second. This plugin does not distinguish between lon/lat and any other x/y coordinate system.

    The above example will show the City of Boston. The value passed to the center property is a GeoJSON position, which is an array with an x value followed by a y value.

    If you need help determining the center point values the events example can help. Pan and zoom the map to an area and click the location you want. Then copy the coordinates value displayed under the geo argument heading of the click event and paste it into you code.

    AppGeo-geo-f763e47/docs/geographics/0000775000175000017500000000000012005347446016176 5ustar daviddavidAppGeo-geo-f763e47/docs/geographics/index.html0000664000175000017500000000362612005347446020202 0ustar daviddavid geographics | $.geo

    geographics widget

    The geographics widget in $.geo handles all shape drawing. The geomap widget uses it internally and you can use it outside of geomap to draw GeoJSON geometry that has already been converted to pixel coordinates onto any element.

    .geographics( options )

    options

    The options argument is a JavaScript object that configures the graphics widget during the first instantiation on a div. No options are required. By default the graphics widget will draw all shapes with a dark red outline and mostly transparent red fill.

    methods

    The geographics widget provides methods to draw various GeoJSON geometries on the canvas. Remember that the geometries must have either already been converted to pixel coordinates or created initially with a pixel coordinate system in mind.

    AppGeo-geo-f763e47/docs/html/0000775000175000017500000000000012005347446014647 5ustar daviddavidAppGeo-geo-f763e47/docs/html/index.html0000664000175000017500000001401412005347446016644 0ustar daviddavid html | jQuery Geo

    html

    Our geospatial plugin's only widget is a geographic map that you can create on any div with a computable width and height.

    <div style="width: 640px; height: 480px;"></div>

    If the div is not already in relative, absolute or fixed position, the widget will force relative positioning.

    fullscreen

    The div size does not have to be so specific.

    <div style="position: fixed; top: 0; right: 0; bottom: 0; left: 0;"></div>

    As in the above example, you can have the map fill the window by setting position to either absolute or fixed and the top, right, bottom and left properties to all zero. The map will follow the size of the window and recenter when the size of the window changes.

    Fixed position is preferred because it will not create scroll bars when making the window smaller. However, keep in mind that fixed position is not supported by IE6 and can be odd on some mobile browsers. If you do use absolute position, you can set the overflow style property on the body element to hidden and avoid scroll bars.

    <body style="overflow: hidden;">
      <div style="position: absolute; top: 0; right: 0; bottom: 0; left: 0;"></div>
    </body>

    box model

    The map supports divs that have padding, borders and margins. The plugin will create the map where text would normally go in such a situation, i.e., the map content will be inset from the border by the padding amount.

    <style>
      #map {
        width: 90%;
        max-width: 640px;
        height: 480px;
        padding: 8px;
        border: solid 3px #444;
        margin: .5em;
        background: #ddf;
      }
    </style>
    <div id="map">O HAI</div>
    O HAI

    inner elements

    Any elements inside the map div can be absolutely positioned and will not interfere with map operation. Map images will appear beneath them. This is useful if you want to layout a scale bar for example.

    <style>
      #bar {
        position: absolute;
        top: 10px;
        right: 10px;
        padding: 16px;
        background: red;
        opacity: .8;
        border-radius: 8px;
        text-align: center;
        font-size: 10px;
      }
      #bar div {
        width: 96px;
        height: 2px;
        margin-bottom: 8px;
        background: #444;
        color: #444;
      }
    </style>
    <div id="map"><div id="bar"><div></div><span>1134 meters</span></div></div>
    1134 meters

    This rather large scale bar will not interfere with a user trying to pan the map. Ignore the scale bar value in this example, it's static text.

    mobile

    The geomap widget works on modern mobile browsers without any additional JavaScript. However, some web design is necessary. For starters, as with any mobile development you should add a viewport meta tag into your head element. This should appear above most other tags so the mobile browser can get ready for a mobile page before doing any other work.

    <meta name="viewport" content="width=device-width, minimum-scale=1">

    For a fullscreen map, you can also add a maximum-scale attribute.

    <meta name="viewport" content="width=device-width, minimum-scale=1, maximum-scale=1">

    If you have done any other mobile web developement, you're probably frowning at my decision to disable the default zoom capability of the device's web browser. If you haven't done much with mobile, I am disabling double-tap to zoom a page by setting the min and max scale to 1.

    In almost all other cases, I would agree that disabling browser zoom is a bad user experience, however for a full-screen mapping application, double-tap has a whole new meaning and users expect it to zoom the map itself, not the page. It is in this case only that I suggest you disable browser page zoom. If you are targeting modern mobile browsers such as iOS, Android, Windows Phone 7 or Opera Mobile, you can used fixed positioning and the HTML for the full screen mobile app would look like the first fullscreen example:

    <div style="position: fixed; top: 0; right: 0; bottom: 0; left: 0;"></div>

    Other mobile browsers are currently untested.

    AppGeo-geo-f763e47/docs/examples/0000775000175000017500000000000012005347446015521 5ustar daviddavidAppGeo-geo-f763e47/docs/examples/wkt.html0000664000175000017500000000464012005347446017220 0ustar daviddavid WKT parse/stringify example
    < docs

    WKT parse & stringify

    This example uses $.geo.WKT.stringify to turn your drawn GeoJSON objects into WKT. The Parse button uses $.geo.WKT.parse to read valid WKT from the text box and add shapes to the map.

    AppGeo-geo-f763e47/docs/examples/js/0000775000175000017500000000000012036234152016126 5ustar daviddavidAppGeo-geo-f763e47/docs/examples/js/all-shingled.js0000664000175000017500000002436612005347446021051 0ustar daviddavid$(function () { // Firefox likes to cache form values during refresh $( "form" )[ 0 ].reset( ); $( "form" ).submit( function( ) { // also, we don't want the form to actually submit return false; } ); // set proj to null because we don't have the code for this projection // and are working entirely in map units $.geo.proj = null; // define two shingled services var services = [ // define a basemap service { id: "massgis_basemap", type: "shingled", src: "http://giswebservices.massgis.state.ma.us/geoserver/wms?LAYERS=massgis_basemap&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&FORMAT=image%2Fpng&SRS=EPSG%3A26986&BBOX={{:bbox}}&WIDTH={{:width}}&HEIGHT={{:height}}", attr: "© 2011 Commonwealth of Massachusetts" }, // define a second service as a layer on top of the basemap // we use this service as the target when "target" is set to service in this demo { id: "massgis_hydrography", type: "shingled", src: "http://giswebservices.massgis.state.ma.us/geoserver/wms?LAYERS=massgis%3AGISDATA.MAJPOND_POLY,massgis%3AGISDATA.MAJSTRM_ARC&TRANSPARENT=true&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&FORMAT=image%2Fpng&SRS=EPSG%3A26986&BBOX={{:bbox}}&WIDTH={{:width}}&HEIGHT={{:height}}", style: { opacity: .8 } } ]; // create a map without a tilingScheme & with the two shingled services var map = $( "#map" ).geomap( { // add a cursor for our custom mode: remove cursors: { remove: "crosshair" }, // use the services array defined above services: services, // you must set bboxMax for shingled services for the zoom property to mean anything bboxMax: [ 31789.1658, 790194.4183, 337250.8970, 961865.1338 ], // shingled services do not have a tilingScheme tilingScheme: null, // center & zoom values that fit MassGIS's projection center: [ 235670.21967, 900771.290247 ], zoom: 4, // the Charles River is too large after zoom level 8 zoomMax: 8, loadstart: function( ) { // we can show an indicator when the map widget is loading images via the loadstart event $("#indicator").show( ); }, loadend: function( ) { // we can hide the indicator when the map widget is done loading images via the loadend event $("#indicator").hide( ); }, bboxchange: function( e, geo ) { // when the bbox changes, update the info section with new option values updateInfo( ); }, shape: function( e, geo ) { // both the measure and draw/drag modes trigger the shape event // but we only want to append for the draw & drag if ( map.geomap( "option", "mode" ).substr( 0, 3 ) == "dra" ) { // when the user draws or drags a shape, show it on the map // the shape event triggers when the user finishes drawing a shape // the geo argument is a GeoJSON object representing the shape // for this example, we'll append it to the map forcing an // individual style that matches the current drawStyle // make a copy of the current drawStyle var drawStyle = $.extend( { }, map.geomap( "option", "drawStyle" ) ); // grab the label (if any) from the input var label = $( "#shapeLabels input" ).val( ); // append the shape using that style // however, depending on which target is checked, we will append the shape to either the map widget itself or a specific map service if ( $( "#clickTargetWidget" ).is( ":checked" ) ) { // if the map is our target, just append the shape to the map // if there's a label entered, used it map.geomap( "append", geo, drawStyle, label ); } else { // otherwise, grab a reference to a service // ( by id in this case ) and append the shape to that // the value of the remaining radio buttons matches the id of a service // if there's a label entered, used it var serviceToAppend = $( "#" + $( "input[name='clickTarget']:checked" ).val( ) ); $( serviceToAppend ).geomap( "append", geo, drawStyle, label ); // also note, that the label is controlled seperately from the shape, by CSS, rather than by jQuery Geo shapeStyle objects // if you look at the CSS, you will notice: // // #massgis_hydrography { color: blue; } // // which makes all labels on the hydro service blue text } } }, click: function( e, geo ) { if ( map.geomap( "option", "mode" ) == "remove" ) { // when the user clicks the map while in our custom mode, remove, // we will search for shapes on either the map widget itself // ( and, by design, all map services) or a single, specific map service // we'll use a nice, fat 5px radius for the searches here, that's what the (, 5) is below // however, in this demo, we remove any shapes found from either the map or service // if the map is our target, grab the map reference // otherwise, grab a reference to a service, in this case, by id var target = $( "#clickTargetWidget" ).is( ":checked" ) ? map : $( "#" + $( "input[name='clickTarget']:checked" ).val( ) ); // by design, calling find on the map itself returns all shapes at that location // even if they have been appended to a service // when target is the service, find is limited to shapes that have been appended there var shapes = target.geomap( "find", geo, 3 ); // even though we potentially found service-level shapes with the find method, // calling remove on the map does not remove from all services // however, here we're calling remove on the same target where we found the shapes // (note: remove can take an array of shapes, which the find method returns) target.geomap( "remove", shapes ); } } } ); // jQuery UI for pretty button // (except iOS 5, for some reason) // (also, don't use user agent sniffing like this, will have to figure out the issue) if (!navigator.userAgent.match(/OS [4-5](_\d)+ like Mac OS X/i)) { $( "button, #togglePannable" ).button( ); } $( ".modes, .scrollOptions, .clickTargets, .toggleTargets" ).buttonset( ); $( "#toggle-info" ).click( function( ) { // show or hide some map info such as bbox, center and zoom $( "#mapInfo" ).toggle( ); } ); $( "#togglePannable" ).click( function( ) { // change the pannable option to allow users to pan or not pan your map map.geomap( "option", "pannable", $( this ).is( ":checked" ) ); } ); $( ".scrollOptions input" ).click( function( ) { // set the map's scroll option based on value of the input clicked // currently, default and scroll are the same; the only other option is off var scrollValue = $( this ).val( ); map.geomap( "option", "scroll", scrollValue ); } ); $( "#change-mode").click( function( ) { // show or hide the mode options $( "#modeOptions" ).toggle( ); } ); $( ".modes input" ).click( function () { // set the map's mode option based on value of the input clicked var modeValue = $( this ).val( ); map.geomap( "option", "mode", modeValue ); // if mode is one of the draw/drag modes (or remove), show the target section, otherwise hide it $( "#clickTarget" ).toggle( modeValue.substr( 0, 3 ) === "dra" || modeValue === "remove" ); // if mode is one of the draw/drag modes, // show the label inputs & shape style as well $( "#shapeLabels, #drawStyle" ).toggle( modeValue.substr( 0, 3 ) === "dra" ); // also display the current mode on the button $( "#change-mode .ui-button-text" ).text( modeValue ); // hide the mode options $( "#modeOptions" ).hide( ); } ); $( "#drawStyle input" ).change( function( ) { // when an input of the drawStyle area changes, // immediately set the property of geomap's drawStyle option // keep in mind that the three point-only styles (width, height & borderRadius) // cannot be seen because with drawPoint, the shape event triggers immediately // without drawing a shape // this example, however, does use them when appending the shape after a click // first, we can grab a jQuery reference to the input that changed var $this = $( this ); // next, we can create an object that represents this change // this example doesn't, but you can set more than one property // on geomap's drawStyle option at a time var styleOption = { }; styleOption[ $this.attr( "name" ) ] = $this.val(); map.geomap( "option", "drawStyle", styleOption ); } ); $( ".toggleTargets input" ).click( function( ) { // when a service is toggled, we tell the geomap widget to toggle it // the value of each checkbox input equals the id of a service var checkboxClicked = $( this ); var serviceToToggle = $( "#" + checkboxClicked.val( ) ); // toggle the service, shapes on the service will also be toggled serviceToToggle.geomap( "toggle" ); } ); $( "#zoomOut" ).button( "option", { // just icons for the zoom buttons icons: { primary: "ui-icon-minus" }, text: false } ).click( function( ) { // use the zoom method to zoom out map.geomap( "zoom", -1 ); } ); $( "#zoomIn" ).button( "option", { // just icons for the zoom buttons icons: { primary: "ui-icon-plus" }, text: false } ).click( function( ) { // also use the zoom method to zoom in map.geomap( "zoom", +1 ); } ); // update the info section with initial option values updateInfo( ); function updateInfo( ) { // update the info section with option values $( "#mapInfo td" ).each( function( ) { // a reference to the current option td element var optionCell = $( this ); // since each td has a data-option attribute, // jQuery can extract the option value via the data function var optionValue = map.geomap( "option", optionCell.data( "option" ) ); if ( $.isArray( optionValue ) ) { // display array values a little nicer $.each( optionValue, function( i ) { optionValue[ i ] = this.toFixed( 2 ); } ); optionCell.text( "[ " + optionValue.join( ", " ) + " ]" ); } else { optionCell.text( optionValue ); } } ); } }); AppGeo-geo-f763e47/docs/examples/js/all-tiled.js0000664000175000017500000002463412005347446020353 0ustar daviddavid$(function () { // Firefox likes to cache form values during refresh $( "form" )[ 0 ].reset( ); $( "form" ).submit( function( ) { // also, we don't want the form to actually submit return false; } ); // define two tiled services var services = [ // a free basemap tile set from MapQuest { id: "mapquest-open", type: "tiled", src: function( view ) { return "http://otile" + ((view.index % 4) + 1) + ".mqcdn.com/tiles/1.0.0/osm/" + view.zoom + "/" + view.tile.column + "/" + view.tile.row + ".png"; }, attr: 'Tiles Courtesy of MapQuest ' }, // define a second service as a layer on top of the basemap // we use this service as the target when "target" is set to service in this demo { id: "broadband-speedtest", type: "tiled", src: "http://www.broadbandmap.gov/StamenTiles/speedtest/speedtest/download/{{:zoom}}/{{:tile.column}}/{{:tile.row}}.png", attr: "Speed Test data maintained by the NTIA, in collaboration with the FCC" } ]; // create a map with a tilingScheme & with the two tiled services var map = $( "#map" ).geomap( { // add a cursor for our custom mode: remove cursors: { remove: "crosshair" }, // use the services array defined above services: services, // these tiled services are in jQuery Geo's default tilingScheme, web mercator // we don't need to change it but will write it here in comments, for this demo /* tilingScheme: { tileWidth: 256, tileHeight: 256, levels: 18, basePixelSize: 156543.03392799936, pixelSizes: null, origin: [ -20037508.342787, 20037508.342787 ] }, */ // center & zoom values that default to showing the contenental United States of America center: [ -89.34, 38.84 ], zoom: 5, // the speedtest service only supports zooming out to level 3, lock the map to that min zoom zoomMin: 3, // the speedtest service only zooming in to level 10, lock the map to that max zoom zoomMax: 10, loadstart: function( ) { // we can show an indicator when the map widget is loading images via the loadstart event $("#indicator").show( ); }, loadend: function( ) { // we can hide the indicator when the map widget is done loading images via the loadend event $("#indicator").hide( ); }, bboxchange: function( e, geo ) { // when the bbox changes, update the info section with new option values updateInfo( ); }, shape: function( e, geo ) { // both the measure and draw/drag modes trigger the shape event // but we only want to append for the draw & drag if ( map.geomap( "option", "mode" ).substr( 0, 3 ) == "dra" ) { // when the user draws or drags a shape, show it on the map // the shape event triggers when the user finishes drawing a shape // the geo argument is a GeoJSON object representing the shape // for this example, we'll append it to the map forcing an // individual style that matches the current drawStyle // make a copy of the current drawStyle var drawStyle = $.extend( { }, map.geomap( "option", "drawStyle" ) ); // grab the label (if any) from the input var label = $( "#shapeLabels input" ).val( ); // append the shape using that style // however, depending on which target is checked, we will append the shape to either the map widget itself or a specific map service if ( $( "#clickTargetWidget" ).is( ":checked" ) ) { // if the map is our target, just append the shape to the map // if there's a label entered, used it map.geomap( "append", geo, drawStyle, label ); } else { // otherwise, grab a reference to a service // ( by id in this case ) and append the shape to that // the value of the remaining radio buttons matches the id of a service // if there's a label entered, used it var serviceToAppend = $( "#" + $( "input[name='clickTarget']:checked" ).val( ) ); $( serviceToAppend ).geomap( "append", geo, drawStyle, label ); // also note, that the label is controlled seperately from the shape, by CSS, rather than by jQuery Geo shapeStyle objects // if you look at the CSS, you will notice: // // #broadband-speedtest { color: purple; font-weight: bold; } // // which makes all labels on the speedtest service blue text } } }, click: function( e, geo ) { if ( map.geomap( "option", "mode" ) == "remove" ) { // when the user clicks the map while in our custom mode, remove, // we will search for shapes on either the map widget itself // (and, by design, all map services) or a single, specific map service // we'll use a nice, fat 5px radius for the searches here, that's what the (, 5) is below // however, in this demo, we remove any shapes found from either the map or service // if the map is our target, grab the map reference // otherwise, grab a reference to a service, in this case, by id var target = $( "#clickTargetWidget" ).is( ":checked" ) ? map : $( "#" + $( "input[name='clickTarget']:checked" ).val( ) ); // by design, calling find on the map itself returns all shapes at that location // even if they have been appended to a service // when target is the service, find is limited to shapes that have been appended there var shapes = target.geomap( "find", geo, 3 ); // even though we potentially found service-level shapes with the find method, // calling remove on the map does not remove from all services // however, here we're calling remove on the same target where we found the shapes // (note: remove can take an array of shapes, which the find method returns) target.geomap( "remove", shapes ); } } } ); // jQuery UI for pretty button // (except iOS 5, for some reason) // (also, don't use user agent sniffing like this, will have to figure out the issue) if (!navigator.userAgent.match(/OS [4-5](_\d)+ like Mac OS X/i)) { $( "button, #togglePannable" ).button( ); } $( ".modes, .scrollOptions, .clickTargets, .toggleTargets" ).buttonset( ); $( "#toggle-info" ).click( function( ) { // show or hide some map info such as bbox, center and zoom $( "#mapInfo" ).toggle( ); } ); $( "#togglePannable" ).click( function( ) { // change the pannable option to allow users to pan or not pan your map map.geomap( "option", "pannable", $( this ).is( ":checked" ) ); } ); $( ".scrollOptions input" ).click( function( ) { // set the map's scroll option based on value of the input clicked // currently, default and scroll are the same; the only other option is off var scrollValue = $( this ).val( ); map.geomap( "option", "scroll", scrollValue ); } ); $( "#change-mode").click( function( ) { // show or hide the mode options $( "#modeOptions" ).toggle( ); } ); $( ".modes input" ).click( function () { // set the map's mode option based on value of the input clicked var modeValue = $( this ).val( ); map.geomap( "option", "mode", modeValue ); // if mode is one of the draw/drag modes (or remove), show the target section, otherwise hide it $( "#clickTarget" ).toggle( modeValue.substr( 0, 3 ) === "dra" || modeValue === "remove" ); // if mode is one of the draw/drag modes, // show the label inputs & shape style as well $( "#shapeLabels, #drawStyle" ).toggle( modeValue.substr( 0, 3 ) === "dra" ); // also display the current mode on the button $( "#change-mode .ui-button-text" ).text( modeValue ); // hide the mode options $( "#modeOptions" ).hide( ); } ); $( "#drawStyle input" ).change( function( ) { // when an input of the drawStyle area changes, // immediately set the property of geomap's drawStyle option // keep in mind that the three point-only styles (width, height & borderRadius) // cannot be seen because with drawPoint, the shape event triggers immediately // without drawing a shape // this example, however, does use them when appending the shape after a click // first, we can grab a jQuery reference to the input that changed var $this = $( this ); // next, we can create an object that represents this change // this example doesn't, but you can set more than one property // on geomap's drawStyle option at a time var styleOption = { }; styleOption[ $this.attr( "name" ) ] = $this.val(); map.geomap( "option", "drawStyle", styleOption ); } ); $( ".toggleTargets input" ).click( function( ) { // when a service is toggled, we tell the geomap widget to toggle it // the value of each checkbox input equals the id of a service var checkboxClicked = $( this ); var serviceToToggle = $( "#" + checkboxClicked.val( ) ); // toggle the service, shapes on the service will also be toggled serviceToToggle.geomap( "toggle" ); } ); $( "#zoomOut" ).button( "option", { // just icons for the zoom buttons icons: { primary: "ui-icon-minus" }, text: false } ).click( function( ) { // use the zoom method to zoom out map.geomap( "zoom", -1 ); } ); $( "#zoomIn" ).button( "option", { // just icons for the zoom buttons icons: { primary: "ui-icon-plus" }, text: false } ).click( function( ) { // also use the zoom method to zoom in map.geomap( "zoom", +1 ); } ); // update the info section with initial option values updateInfo( ); function updateInfo( ) { // update the info section with option values $( "#mapInfo td" ).each( function( ) { // a reference to the current option td element var optionCell = $( this ); // since each td has a data-option attribute, // jQuery can extract the option value via the data function var optionValue = map.geomap( "option", optionCell.data( "option" ) ); if ( $.isArray( optionValue ) ) { // display array values a little nicer $.each( optionValue, function( i ) { optionValue[ i ] = this.toFixed( 2 ); } ); optionCell.text( "[ " + optionValue.join( ", " ) + " ]" ); } else { optionCell.text( optionValue ); } } ); } }); AppGeo-geo-f763e47/docs/examples/js/iecors.js0000664000175000017500000000322312005347446017757 0ustar daviddavid$.ajaxTransport( function( options, originalOptions, jqXHR ) { var xdr; return { send: function( _, completeCallback ) { xdr = new XDomainRequest(); xdr.onload = function() { var responses = { text: xdr.responseText }; // force status code to 200, XDomainRequest rejects all other successful status codes if (xdr.contentType.match(/\/xml/)){ // there is no responseXML in XDomainRequest, so we have to create it manually var dom = new ActiveXObject('Microsoft.XMLDOM'); dom.async = false; dom.loadXML(xdr.responseText); responses.xml = dom; if($(dom).children('error').length != 0) { var $error = $(dom).find('error'); completeCallback(parseInt($error.attr('response_code')), $error.attr('message_key'), responses); } else { completeCallback(200, 'success', responses); } } else if (xdr.contentType.match(/\/json/)) { options.dataTypes.push("json"); completeCallback(200, 'success', responses); } else { completeCallback(200, 'success', responses); // see bug https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=334804 } }; xdr.onprogress = function() { }; xdr.onerror = xdr.ontimeout = function() { var responses = { text: xdr.responseText }; completeCallback(400, 'failed', responses); }; xdr.open(options.type, options.url); xdr.send(options.data); }, abort: function() { if(xdr) { xdr.abort(); } } }; }); AppGeo-geo-f763e47/docs/examples/zoom.html0000664000175000017500000000403512005347446017375 0ustar daviddavid zoom example
    < docs

    zoom

    This example uses the zoom method (as opposed to the zoom option) to change the zoom by relative amounts. Input a number of levels by which to change and click zoom. Negative values zoom out.

    AppGeo-geo-f763e47/docs/examples/simplest.html0000664000175000017500000000156712005347446020260 0ustar daviddavid simplest
    < docs

    simplest

    A 256x256 pixel div...geomap called with no arguments.

    AppGeo-geo-f763e47/docs/examples/emptyservice.html0000664000175000017500000000245612005347446021135 0ustar daviddavid geomap empty service test
    < docs

    geomap empty service test

    This page is similar to the regular empty example but tests removing all shapes from a specific service instead of the map itself.

    AppGeo-geo-f763e47/docs/examples/find.html0000664000175000017500000000447412005347446017340 0ustar daviddavid geomap find test < docs

    geomap find test

    Click the geometry!

      AppGeo-geo-f763e47/docs/examples/drawStyle.html0000664000175000017500000001341612005347446020372 0ustar daviddavid drawStyle test

      drawStyle

      This page tests various style properties using the drawStyle option to change the style displayed when a user is drawing shapes in drawLineString and drawPolygon modes.

      geomap drawStyle option
      AppGeo-geo-f763e47/docs/examples/findservice.html0000664000175000017500000000522312005347446020712 0ustar daviddavid geomap find service test < docs

      geomap find service test

      Click the geometry!

        AppGeo-geo-f763e47/docs/examples/stringsrc.html0000664000175000017500000000453312005347446020432 0ustar daviddavid string src example

        string service src

        This example shows how you can set a service's src property to a jsRender template string.

        The src property of the service object for this map is set to:

        "http://tile.openstreetmap.org/{{:zoom}}/{{:tile.column}}/{{:tile.row}}.png"

        AppGeo-geo-f763e47/docs/examples/twheat/0000775000175000017500000000000012005347446017015 5ustar daviddavidAppGeo-geo-f763e47/docs/examples/twheat/js/0000775000175000017500000000000012005347446017431 5ustar daviddavidAppGeo-geo-f763e47/docs/examples/twheat/js/twheat.js0000664000175000017500000002206512005347446021270 0ustar daviddavid$(function () { var map = null, checkedIds = [], //< list of tweet ids we've checked appendedCount = 0, //< number of tweets we successfully appended searchTerm = "", //< last search term searching = false, currentXhr = null, //< an ajax request reference if we need to cancel twitterButtonHtml = ' AppGeo-geo-f763e47/docs/examples/bbox.html0000664000175000017500000002175012005347446017346 0ustar daviddavid bbox examples

        bbox

        This example tests getting and setting the bbox property on the geomap widget as well as calling various $.geo bbox functions.

        )
        .geomap( "option", "bbox" )
        $.geo.proj.fromGeodetic( bbox )
        $.geo.proj.toGeodetic( bbox )
        $.geo.center( bbox )
        $.geo.width( bbox )
        $.geo.height( bbox )

        For this example, the functions below operate on the above text input only. After using them, you can click set to update the map and other info.

        $.geo.expandBy( bbox, , )
        $.geo.scaleBy( bbox, )

        This last function, reaspect, forces an aspect ratio (calculation of width divided height) onto the bbox. You can run this but it will be difficult to visually see the effects because the geomap widget will automatically reaspect again to fit the bbox back into the viewport.

        Common aspect ratio values: 16:9 = 16/9 ~ 1.78:1 & 4:3 = 4/3 ~ 1.33:1

        $.geo.reaspect( bbox, )
        AppGeo-geo-f763e47/docs/examples/removeservice.html0000664000175000017500000000334112005347446021266 0ustar daviddavid geomap remove service test < docs

        geomap remove service test

        Similar to the regular remove example but tests removing shapes from a specific service instead of the map itself.

        AppGeo-geo-f763e47/docs/examples/all-tiled.html0000664000175000017500000002204212005347446020256 0ustar daviddavid everything tiled

        tiled

        The everything demo, tiled edition!

        info

        basics

        scroll

        mode

        toggle

        zoom

        AppGeo-geo-f763e47/docs/examples/proj.html0000664000175000017500000001061412005347446017363 0ustar daviddavid proj test
        < docs

        proj test

        This page has a couple basic interactive tests of the default $.geo.proj object.

        direct conversion

        Enter a lon/lat in the top inputs (remember, longitude is first here and throughout jQuery Geo but usually spoken second) & click fromGeodetic to convert it to web mercator and store the new values in the bottom two inputs. Click toGeodetic to reverse.

        osm nominatim

        Enter a search term in the input and click search. If successful, geodetic & web mercator coordinates are written to the inputs above. This example uses MapQuest's OSM API: http://open.mapquestapi.com/nominatim.

        status

        Status result for any test.

        ready
        AppGeo-geo-f763e47/docs/examples/appendservice.html0000664000175000017500000000564512005347446021251 0ustar daviddavid append to service test

        append to service

        This page is similar to the regular append example but tests appending shapes to a specific service instead of the map itself. The result, however, should look exactly the same.

        AppGeo-geo-f763e47/docs/examples/shingled.html0000664000175000017500000001352712005347446020214 0ustar daviddavid shingled example

        shingled

        This page tests geomap with shingled services, i.e., fully dynamic services that to not use a tilingScheme. Dynamic services can be set to any scale.

        If all shingled services are in the same projection, they can be layered and turned on and off at any time by updating and re-setting the services option of the geomap widget or by using the toggle convenience method.

        The toggle method is preferred because it is faster and you can use it on specific services, e.g., $("#massgis_interiorforest").geomap("toggle").

        These services are hosted by MassGIS.

        AppGeo-geo-f763e47/docs/examples/labelservice.html0000664000175000017500000000644412005347446021057 0ustar daviddavid label service examples

        label service

        This page is similar to the regular label example but tests appending labeled shapes to a specific service instead of the map itself.

        AppGeo-geo-f763e47/docs/examples/logo.html0000664000175000017500000000772612005347446017363 0ustar daviddavid jQuery Geo logo
        < docs

        jQuery Geo logos!

        This demo uses jQuery Geo to draw its own logo at the top left of the map. Single-click the map to make more logos! The shapes created for the logo are based on the pixelSize of the current scale so your map's current zoom determines the Earth-size of the logo. When you zoom in, the points of the individual logos will spread out.

        AppGeo-geo-f763e47/docs/examples/voting.html0000664000175000017500000002142612005347446017722 0ustar daviddavid Voting districts example
        basemap transparency
        demographic color

        Voting Districts by %

        Once the data has loaded (which may take a while, even on broadband connections), you can dynamically change the demographic display color. You can also click a voting district to zoom in and see details.

        AppGeo-geo-f763e47/docs/examples/panscroll.html0000664000175000017500000000654512005347446020416 0ustar daviddavid panning & scroll example

        panning & scroll

        The panning option can remove a user's ability to pan the map. The scroll option can remove a user's ability to use the mouse wheel to zoom.

        scroll options default and zoom work the same.

        pannable (click to toggle)
        scroll
        AppGeo-geo-f763e47/docs/examples/img/0000775000175000017500000000000012005347446016275 5ustar daviddavidAppGeo-geo-f763e47/docs/examples/img/jsfiddle.png0000664000175000017500000000071312005347446020570 0ustar daviddavidPNG  IHDRasRGBgAMA a pHYsodtEXtSoftwarePaint.NET v3.5.9@<;IDAT8OJQy **Pa/RIFI> I7X.AؠRD!,ʢ_3pB-p~윙9B=o, &Ω)g֩m$ӓ-Ÿ[ҥQoJj^]47l pIENDB`AppGeo-geo-f763e47/docs/examples/img/ajax-loader.gif0000664000175000017500000000124112005347446021151 0ustar daviddavidGIF89a BBbbȒ! NETSCAPE2.0!Created with ajaxload.info! ,30Ikc:Nf E1º.`q-[9ݦ9 JkH! ,4N!  DqBQT`1 `LE[|ua C%$*! ,62#+AȐ̔V/cNIBap ̳ƨ+Y2d! ,3b%+2V_ ! 1DaFbR]=08,Ȥr9L! ,2r'+JdL &v`\bThYB)@<&,ȤR! ,3 9tڞ0!.BW1  sa50 m)J! ,2 ٜU]qp`a4AF0` @1Α! ,20IeBԜ) q10ʰPaVڥ ub[;AppGeo-geo-f763e47/docs/examples/bostock.html0000664000175000017500000000524212005347446020056 0ustar daviddavid Bostock demo

        Bostock demo

        Inspired by: D3 + Leaflet

        AppGeo-geo-f763e47/docs/examples/static.html0000664000175000017500000000367612005347446017712 0ustar daviddavid static mode example

        static mode

        When the mode option is set to "static" a developer can create a map that the user can see but cannot change.

        AppGeo-geo-f763e47/docs/examples/shapeStyleservice.html0000664000175000017500000001510412005347446022112 0ustar daviddavid shapeStyle service test

        shapeStyle service

        This page is similar to the regular shapeStyle example but tests changing the style of a specific service instead of the map itself.

        base geomap shapeStyle option
        specific append style argument
        AppGeo-geo-f763e47/docs/examples/all-shingled.html0000664000175000017500000002176312005347446020763 0ustar daviddavid everything shingled

        shingled

        The everything demo, shingled edition!

        info

        basics

        scroll

        mode

        toggle

        zoom

        AppGeo-geo-f763e47/docs/examples/jqm.html0000664000175000017500000001030712005347446017177 0ustar daviddavid TEMPLATE example

        Amherst

        Which map would you like?

        Parcel App

        Select Tab

         

        AppGeo-geo-f763e47/docs/examples/inset.html0000664000175000017500000001327712005347446017543 0ustar daviddavid Inset map example

        Inset map example

        Add an inset map to display the current bbox against a larger area. The inset map, in this example, is a pre-rendered image drawn a shingled service. You can click the inset map to recenter the main map.

        Inspired by MapGeo
        AppGeo-geo-f763e47/docs/examples/tiledservices.html0000664000175000017500000002017012005347446021254 0ustar daviddavid tiled services test
        < docs

        tiled services test

        This page tests initializing geomap with different services that support the same tilingScheme.

        So long as all services support the current tiling scheme, they are interchangeabe without worrying about the tilingScheme property.

        Dynamic services can be layered on top of tiled services as they don't require a tilingScheme at all, however you have to make sure the map units match, e.g., the dynamic service accepts a geodetic (lon/lat) bounding box or you set $.proj to null and work entirely in a specific projection's map units.

        service examples

        Choose a services array and click set via init to refresh the page and re-initialize the map (including center & zoom properties) or set via property to change only the services property at runtime.

        [
          {
            id: "OSM",
            type: "tiled",
            src: function (view) {
              return "http://tile.openstreetmap.org/"
               + view.zoom + "/"
               + view.tile.column + "/"
               + view.tile.row
               + ".png";
            },
            attr: "© OpenStreetMap & contributors, CC-BY-SA"
          }
        ]
        [
          {
            id: "OSM_MapQuest",
            type: "tiled",
            src: function (view) {
              return "http://otile" + ((view.index % 4) + 1) + ".mqcdn.com/tiles/1.0.0/osm/"
               + view.zoom + "/"
               + view.tile.column + "/"
               + view.tile.row
               + ".png";
            },
            attr: "Tiles Courtesy of <a href='http://www.mapquest.com/' target='_blank'>MapQuest</a> <img src='http://developer.mapquest.com/content/osm/mq_logo.png'>"
          }
        ]
        [
          {
            id: "Ortho_MapQuest",
            type: "tiled",
            src: function (view) {
              return "http://oatile" + ((view.index % 4) + 1) + ".mqcdn.com/naip/"
               + view.zoom + "/"
               + view.tile.column + "/"
               + view.tile.row
               + ".png";
            },
            attr: "Tiles Courtesy of <a href='http://www.mapquest.com/' target='_blank'>MapQuest</a> <img src='http://developer.mapquest.com/content/osm/mq_logo.png'>"
          }
        ]
        [
          {
            id: "Ortho_MapQuest",
            type: "tiled",
            src: function (view) {
              return "http://oatile" + ((view.index % 4) + 1) + ".mqcdn.com/naip/"
               + view.zoom + "/"
               + view.tile.column + "/"
               + view.tile.row
               + ".png";
            },
            attr: "Tiles Courtesy of <a href='http://www.mapquest.com/' target='_blank'>MapQuest</a> <img src='http://developer.mapquest.com/content/osm/mq_logo.png'>"
          },
          {
            id: "OSM_MapQuest",
            type: "tiled",
            src: function (view) {
              return "http://otile" + ((view.index % 4) + 1) + ".mqcdn.com/tiles/1.0.0/osm/"
               + view.zoom + "/"
               + view.tile.column + "/"
               + view.tile.row
               + ".png";
            },
            style: { opacity: .3 }
          }
        ]
        AppGeo-geo-f763e47/docs/examples/draw.html0000664000175000017500000000636312005347446017354 0ustar daviddavid drawing examples

        drawing

        This example tests the three shape drawing modes: drawPoint, drawLineString and drawPolygon. Choose a tool below and start tapping!

        Double-tap to add the last point and end lines & polygons.

        You can remove individual points while drawing lines & polygons with the escape key.

        AppGeo-geo-f763e47/docs/examples/refresh.html0000664000175000017500000001067712005347446020060 0ustar daviddavid refresh example

        refresh

        The refresh method can:

        All versions redraw appended shapes. Calling refresh on individual services will redraw only shapes on that service

        AppGeo-geo-f763e47/docs/examples/image.html0000664000175000017500000000532212005347446017473 0ustar daviddavid image example

        image

        AppGeo-geo-f763e47/docs/examples/geometry.html0000664000175000017500000001061412005347446020244 0ustar daviddavid proj test
        < docs

        proj test

        This page has a couple basic interactive tests of the default $.geo.proj object.

        direct conversion

        Enter a lon/lat in the top inputs (remember, longitude is first here and throughout jQuery Geo but usually spoken second) & click fromGeodetic to convert it to web mercator and store the new values in the bottom two inputs. Click toGeodetic to reverse.

        osm nominatim

        Enter a search term in the input and click search. If successful, geodetic & web mercator coordinates are written to the inputs above. This example uses MapQuest's OSM API: http://open.mapquestapi.com/nominatim.

        status

        Status result for any test.

        ready
        AppGeo-geo-f763e47/docs/examples/defer.html0000664000175000017500000001344312005347446017501 0ustar daviddavid defer example

        defer

        The src function in this demo returns a jQuery Defer object so it can download the tile ahead of time and draw the bbox on it before passing the final image to the map widget as a data URL.

        This demo does not work in IE8.

        AppGeo-geo-f763e47/docs/examples/measure.html0000664000175000017500000000537712005347446020064 0ustar daviddavid measure example

        measure

        This example tests the two measure modes: measureLength, and measureArea. Choose a tool below and start measuring!

        AppGeo-geo-f763e47/docs/examples/opacity.html0000664000175000017500000000565412005347446020071 0ustar daviddavid opacity

        opacity & toggle

        The slider calls geomap's opacity method targeting the OSM service. The default service object doesn't have an id but it does have a class, osm, that we can reference using $(".osm"). The button calls the toggle method. I've matched the map div's background color to OSM's water color for effect.

        AppGeo-geo-f763e47/docs/examples/mobile.html0000664000175000017500000000221712005347446017660 0ustar daviddavid mobile
        < docs

        mobile

        A full window div...geomap called, zoomed in to level 6.

        Add a meta viewport tag to your head element and you're good to go.

        AppGeo-geo-f763e47/docs/examples/tilingScheme.html0000664000175000017500000001460512005347446021030 0ustar daviddavid tilingScheme test
        < docs

        tilingScheme test

        This page tests initializing geomap with services requiring different tilingSchemes.

        Dynamic services are not yet implemented but will be able to be layered on top of tiled services as they don't require a tilingScheme at all.

        For this example, I have set $.geo.proj to null and am setting the center in real map units. This is because the second service, New Jersey, is not in web mercator and geomap does not provide a built-in conversion from lon/lat.

        The New Jersey service is a tiled service with an ArcGIS Server REST endpoint. The level stops of an ArcGIS Server tile cache are often not a power of two and therefore cannot be calculated. We list them all out by using the pixelSizes property of the tilingScheme instead of specifying basePixelSize and levels properties.

        examples

        Choose a service/tilingScheme combo and click set to refresh the page and re-initialize the map.

        services: [
          {
            id: "OSM",
            type: "tiled",
            src: function (view) {
              return "http://tile.openstreetmap.org/"
               + view.zoom + "/"
               + view.tile.column + "/"
               + view.tile.row
               + ".png";
            },
            attr: "© OpenStreetMap & contributors, CC-BY-SA"
          }
        ],
        tilingScheme: {
          tileWidth: 256,
          tileHeight: 256,
          levels: 18,
          basePixelSize: 156543.03392799936,
          origin: [-20037508.342787, 20037508.342787]
        }
        services: [
          {
            id: "NewJersey",
            type: "tiled",
            src: function (view) {
              return "http://njgin.state.nj.us/ArcGIS/rest/services/Basemap/basemap/MapServer/tile/"
               + view.zoom + "/"
               + view.tile.row + "/"
               + view.tile.column;
            }
          }
        ],
        tilingScheme: {
          tileWidth: 512,
          tileHeight: 512,
          pixelSizes: [
            3472.22222222222,
            2604.16666666667,
            2170.13888888889,
            1562.5,
            976.5625,
            494.791666666667,
            260.416666666667,
            130.208333333333,
            65.1041666666667,
            32.5520833333333,
            21.7013888888889,
            10.8506944444444,
            5.20833333333333,
            2.08333333333333,
            1.04166666666667
          ],
          origin: [-842000, 1440000]
        }
        AppGeo-geo-f763e47/docs/examples/shapeStyle.html0000664000175000017500000001470012005347446020532 0ustar daviddavid shapeStyle test

        shapeStyle

        This page tests various style properties using the shapeStyle option to change the default style or and passing a shape-specific style to the append method.

        base geomap shapeStyle option
        specific append style argument
        AppGeo-geo-f763e47/docs/examples/mode-zoom.html0000664000175000017500000000554112005347446020322 0ustar daviddavid zoom mode example

        zoom mode

        When a geomap widget's mode option is "zoom", you can your your mouse to draw a rectangle. jQuery Geo will change the bbox of the map to match the rectangle as closely as possible based on the tiling scheme and viewport size.

        This mode is more useful for dynamic map services and may be more familiar to GIS professionals.

        Hint: in pan or any of the draw modes, you can hold the shift key to temporarily switch to zoom mode.

        AppGeo-geo-f763e47/docs/examples/services.html0000664000175000017500000000360312005347446020234 0ustar daviddavid services example

        services

        This example tests setting the service object array, i.e., the geomap services option, in different ways.

        AppGeo-geo-f763e47/docs/examples/template.html0000664000175000017500000000440612005347446020226 0ustar daviddavid TEMPLATE example AppGeo-geo-f763e47/docs/examples/destroy.html0000664000175000017500000000367612005347446020114 0ustar daviddavid destroy example
        < docs

        destroy

        This example allows you to create and destroy the geomap widget and test that everything is returned to normal.

        AppGeo-geo-f763e47/docs/examples/twitter-heat.html0000664000175000017500000002314512005347446021035 0ustar daviddavid Twitter Heat Map

        Twitter Heat Map

        This demo continually searches Twitter based on location & query and draws the results as a heat map.

        You can hover over data to read the tweets.

        AppGeo-geo-f763e47/docs/examples/css/0000775000175000017500000000000012005347446016311 5ustar daviddavidAppGeo-geo-f763e47/docs/examples/css/style.css0000664000175000017500000000202212005347446020157 0ustar daviddavid.links { float: right; } .docLink { background: url(../../images/$.geo-logo-small.png) right no-repeat; color: #7f0000; display: block; font-size: 24px; font-weight: bold; padding-right: 24px; text-decoration: none; text-transform: uppercase; } .fiddleLink { display: block; font-weight: bold; margin: 4px; text-align: right; text-decoration: none; } .fiddleLink img { border: none; vertical-align: middle; } .mobile-shrink { font-size: .6em; } .not-mobile { display: none; } @media only screen and (min-width: 800px) { .info { width: 45% !important; position: fixed; right: 16px; top: 16px; } .mobile-shrink { font-size: 1em; } .not-mobile { display: block; } } html { font:13px/1.231 Calibri,Arial,sans-serif; *font-size:small; } .info { background: #fff; border-radius: 8px; box-shadow: -4px 4px #444; opacity: .8; padding: 8px; width: 90%; } fieldset { border: none; } legend { font-size: 14px; font-weight: bold; } AppGeo-geo-f763e47/docs/examples/census.html0000664000175000017500000001041412005347446017707 0ustar daviddavid Census
        AppGeo-geo-f763e47/docs/examples/drag.html0000664000175000017500000000422712005347446017331 0ustar daviddavid drag example

        drag

        There are currently two drag modes: dragBox and dragCircle. This demo tests only dragBox when set as the mode during init.

        AppGeo-geo-f763e47/docs/examples/marker.html0000664000175000017500000000450612005347446017675 0ustar daviddavid i <3 u, laura!

        i <3 u, laura!

        AppGeo-geo-f763e47/docs/examples/isGeodetic.html0000664000175000017500000000543712005347446020477 0ustar daviddavid TEMPLATE example

        Is Geodetic?

        [-71.05, 42.36]
        [-8102018.97, 5011809.33]
        [-72.78, 40.99, -69.33, 43.69]
        [-8102018.97, 5011809.33, -7718610.83, 5418454.32]
        [[-72.78, 43.32], [-71.33, 42.43]]
        [[-8102018.97, 5011809.33], [-7718610.83, 5418454.32]]
        [[[-72.78, 43.32], [-71.33, 42.43], [-70.12, 43.16], [-72.78, 43.32]]]
        [[[-8102018.97, 5011809.33], [-7718610.83, 5418454.32], [-8102018.83, 5418454.32], [-8102018.97, 5011809.33]]]
        [[[[-72.78, 43.32], [-71.33, 42.43], [-70.12, 43.16], [-72.78, 43.32]]]]
        [[[[-8102018.97, 5011809.33], [-7718610.83, 5418454.32], [-8102018.83, 5418454.32], [-8102018.97, 5011809.33]]]]
        AppGeo-geo-f763e47/docs/examples/usastates.html0000664000175000017500000000410412005347446020422 0ustar daviddavid USA States

        USA States

        This map reads USA state boundary data as a GeoJSON FeatureCollection and draws it on top of OpenStreetMap.

        Click a state to change its color!

        AppGeo-geo-f763e47/docs/examples/tracking.html0000664000175000017500000000531712005347446020217 0ustar daviddavid GPS Tracking
        < docs

        GPS Tracking

        This simple demo continually follows your location at zoom level 15 showing the Esri World Street Map tiles. It now shows the geolocation accuracy buffer.

        Inspired by Royce Simpson

        AppGeo-geo-f763e47/docs/examples/events.html0000664000175000017500000001174012005347446017716 0ustar daviddavid events example

        events

        The basic interaction events are: move, click, dblclick, and bboxchange. jQuery Geo triggers then when a user interacts with the map.

        event (time) geo argument
        move ()
        click ()
        dblclick ()
        bboxchange ()
        AppGeo-geo-f763e47/docs/examples/hurricane.html0000664000175000017500000001326212005347446020373 0ustar daviddavid hurricane
        < docs

        Hurricane tracking

        Displaying a snapshot of storm data extracted from stormpulse.com

        AppGeo-geo-f763e47/docs/examples/remove.html0000664000175000017500000000340112005347446017702 0ustar daviddavid geomap remove test < docs

        geomap remove test

        Click on the buttons to the right to call geomap.remove on points one at a time.

          AppGeo-geo-f763e47/docs/examples/center.html0000664000175000017500000001361212005347446017672 0ustar daviddavid center/zoom example

          center & zoom example

          This page tests getting and setting the center & zoom options as well as getting the read-only pixelSize.

          The center option is a GeoJSON position. The zoom option for a tiled service a whole number from zero to the number of levels defined by the tilingScheme minus one. The pixelSize is the number of map units that fit in a single pixel of the current view. By default, pixelSize is in meters because the default map service is in web mercator meters.

          runtime options

          Change the center or zoom option and click set to update the map.

          actual values

          The center option is in geodetic cooridinates, [lon, lat], but the internal center is in map units, web mercator by default.

          .geomap( "option", "center" )
          $.geo.proj.toGeodetic( center )
          internal center, always projected
          .geomap( "option", "zoom" )
          .geomap( "option", "pixelSize" )
          AppGeo-geo-f763e47/docs/examples/append.html0000664000175000017500000000765312005347446017671 0ustar daviddavid append test

          append

          This page tests geomap's append method and some style and refresh arguments.

          A geomap widget is initialized to the continental US and a point is placed in Massachusetts. A line extends from MA to South Jersey where a triangle covers an area. For points, geomap draws a pixel-based oval around the map coordinate. Since the size of the oval is based on pixels, it will be the same size at all scales. The pixel length of lines and size of polygons changes at different scales because each point that makes up the shapes is locked at specific map coordinates. The stroke width for all shapes will be the same number of pixels at all scales.

          All the geometry is stored in a single GeometryCollection. This example first draws the entire collection with a broad stroked, off-white style to create a halo effect behind the real shapes. This makes them a little easier to see on the map. Then we draw each individual shape again with color. The first two have the default style which is red. For the last one, we change the color to blue.

          AppGeo-geo-f763e47/docs/examples/label.html0000664000175000017500000000633512005347446017475 0ustar daviddavid label examples

          label

          This example builds on the drawing example by appending a label with shapes. Enter label text (HTML is ok), choose a tool below, and start labelling!

          AppGeo-geo-f763e47/docs/examples/insetmap.html0000664000175000017500000000623512005347446020235 0ustar daviddavid inset map example

          inset map

          AppGeo-geo-f763e47/docs/examples/empty.html0000664000175000017500000000231012005347446017541 0ustar daviddavid geomap empty test
          < docs

          geomap empty test

          Click the map to add points, click the Empty button to remove them all at once.

          AppGeo-geo-f763e47/docs/examples/geo-geometry.html0000664000175000017500000002702612005347446021021 0ustar daviddavid geometry function examples

          geometry functions

          This example appends a few Points, LineStrings, and Polygons. It then calculates some relationships and info about the shapes using the geometry functions in the $.geo namespace. The red box is the bbox of all red shapes.

          distance
          pt, pt
          pt, line
          pt, poly
          line, pt
          line, line
          line, poly
          poly, pt
          poly, line
          poly, poly
          contains
          pt, pt
          pt, line
          pt, poly
          line, pt
          line, line
          line, poly
          poly, pt
          poly, line
          poly, poly
          contains
          poly, pt
          poly, line
          poly, poly
          poly, poly
          centroid
          pt
          line
          poly
          poly
          poly
          AppGeo-geo-f763e47/docs/examples/utah/0000775000175000017500000000000012005347446016462 5ustar daviddavidAppGeo-geo-f763e47/docs/examples/utah/js/0000775000175000017500000000000012005347446017076 5ustar daviddavidAppGeo-geo-f763e47/docs/examples/utah/js/libs/0000775000175000017500000000000012036234152020020 5ustar daviddavidAppGeo-geo-f763e47/docs/examples/utah/js/script.js0000664000175000017500000000552012005347446020742 0ustar daviddavid/* Author: Ryan Westphal */ $(function () { $("#basemapButtons").buttonset().find("label").click(function () { var inputId = $(this).attr("for"), $basemapInput = $("#" + inputId), basemapValue = $basemapInput.val(), tileSize = parseInt($basemapInput.data("tileSize")), serviceOptions = makeService(basemapValue, tileSize); $("#map").geomap("option", { tilingScheme: serviceOptions.tilingScheme, services: serviceOptions.services, center: $("#map").geomap("option", "center") }); }); var options = $.extend( { }, makeService("UtahBaseMap-Lite", 256), { center: [453709, 4333922], zoom: 2, move: function (e, geo) { $("#lblCoords>span").text("" + geo.coordinates); } } ); $("input[value='UtahBaseMap-Lite']").prop("checked", true); $("#pnlSearch form").submit(function (e) { e.preventDefault(); var address = $(this).find("input").val().replace(/,\s*UT/i, ""), addressParts = address.split(","); if (addressParts.length >= 2) { address = address.replace(addressParts[addressParts.length - 1], "").replace(",", ""); $.ajax({ url: "http://mapserv.utah.gov/wsut/Geocode.svc/appgeo/street(" + $.trim(address) + ")zone(" + $.trim(addressParts[addressParts.length - 1]) + ")", dataType: "jsonp", success: function (result) { $("#map").geomap("option", { center: [result.UTM_X, result.UTM_Y], zoom: 13 }); }, error: function (xhr) { displayMessage(xhr.statusText); } }); } else { displayMessage("Please enter both a street address and either a city or zip separated by a comma"); } return false; }); $("#pnlSearch input").watermark("street addres, city or zip"); $.geo.proj = null; $("#map").geomap(options); function displayMessage(msg) { $("#infoBar").html(msg).fadeTo(0, 1.0).delay(5000).fadeOut("slow"); } function makeService(name, tileSize) { return { services: [ { type: "tiled", src: "http://mapserv.utah.gov/ArcGIS/rest/services/" + name + "/MapServer/tile/{{:zoom}}/{{:tile.row}}/{{:tile.column}}", attr: "© AGRC" } ], tilingScheme: { tileWidth: tileSize, tileHeight: tileSize, pixelSizes: [ 4891.96999883583, 2445.98499994708, 1222.99250010583, 611.496250052917, 305.748124894166, 152.8740625, 76.4370312632292, 38.2185156316146, 19.1092578131615, 9.55462890525781, 4.77731445262891, 2.38865722657904, 1.19432861315723, 0.597164306578613, 0.298582153289307 ], origin: [-5120900, 9998100] } } } }); AppGeo-geo-f763e47/docs/examples/utah/img/0000775000175000017500000000000012005347446017236 5ustar daviddavidAppGeo-geo-f763e47/docs/examples/utah/img/BaseMapSelectorSprite-v1.1.png0000664000175000017500000013723312005347446024640 0ustar daviddavidPNG  IHDR t4 pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-gAMA|Q cHRMz%u0`:o_FIDATxwiz߉}_>9W7v0=8$5"EJ! vaAb ^ֆ$%ΰg}oߜCpNRtiP9Uz>B)F2m##pd#pd#ld#ll88G6G6F6FF#32h`cu͵,á\Ld3$ ,B,BM']0&tZM6VyH`gmfr Ciȱ9qtMeH@Z+ܼ|kMU z6C]/-A/޻4M#H:Q"a ~#~ӟ ۶40 VE²,kR JT-zNniR#G[[lnn~fI<4M~8x J) `0{{p @0Qu|=|s P) A W}|[LMLScNΟ= 8w8^~ ETHBME=dxu6n"l(*xV2 "yHu]'LTt:t]G.4677Ç!abY~ B`Q8Al6)ˤR)\ץliRJ4MqR(t:\BZ頔B4昞äyF^ 1"0$X]sUk[;CN u_}{ dgSKyԶ99rce <41R$!f幬/ݧdm>$\b( f2,\"31TkkxuN:ENhFwxG# 0DuLDul& !>lvX4r9:AEA Aܽ{wX08vA |U}wo 03>=.C|/r)ʥ2n!±LҺDH]4 )А*B 7'7u&.EP"B#o8 p6Huom PJmD"F벱⃇>A`YVu C7P t RHI(^|@DD&ų=*uYYYP*($IRB^`0`ss[ny.4MQBG74jM~p%N9?5;ahR8l+%\-R]C$B"Ph_6cV\]Ŏ(i@6~/%206B8Y@L8³ *+kD~)}$zOuc49u*^)%~š5aEigqW_}f5Q㐰>|d:EXMp֭a9>>aܹsp4/>f\y-K;u9,t B"T ]~&/^ik(Ih( L3xR01IO9-PO:*T8N):|aNwQo0Tr92 ZaA0 ݿ8B*|[JIV{A.H8&z$i.+ "diR[YcPkvpm,=t~&JMo¶hݢ͂(*(LΏS7 Dhi23GQs4-[uV Xks-PJ)֖Wpnݢ r{0 |'Tqg4a =7L&!~uiZi STbг۷$;~3GW$6TPvI",C@4E5`D3$H#tliԥHL/}HBF\6Mv RaaL&QJM0HR|scrr(,k'|'|2jqЃ|˲0 c-b0IQJQ)}R| ht$f髀瘱M*$Oue{\\Fri'Oӟ\Pa"w*ScNLb[Mq! -&s;wh6,..h4Љ=xif $ Ο?'> dL&R)4Mu]+NQ<mqud2(۶R )%eve8۷)i2 <EB*Dpt[ "M|"L'܈1y," CN<9y[:^ t-p%!&ggp)N>űVFtnVkrˌV>O1^(!ڽ0/$q5.Ǹß;0M۶p!SSSJ)|>ρyvvvR4MAL1ab&B83|_J&nL&ogs^ U^'3Vba SX_Ƶ[7ͣlLΕ0fOl_([?6ϒ!e$!oᅬa9sS`|~V)%>iI{_ݹsG02 a6tuv$a}4~bHoq:Db8o 1/s=z=lA0OAq`ڝ%.&|%eܸ~׮d pugbl%#a& E&Er$-X VRL2E:@( &-"ԉ|k_ U)nL:MI:!o>R1>7xJB)_z;4 j5 ʈg2PE!@ CBkp2wD-g&y3/aJZHб0=`pU{2 NBK|$\XX C_i=zt8N{ qT*QT=^kH)C`0 !wootrâƶm\2ct]gss!JC {fswϹwgxS=e[\;\{"'?A5RwtAoЧX̡ЇSi<'a'ezt*I٠m,e% |i`onrp~SGҐ(4%?^~ > Ðk׮q\%kB#h4fi4M+GHRDֽ^0dz=z4awސjM便%^|E? ${>|s̝>[\{[|8s1k[|Ͽ D88RCDJ2ܸ[Jl!w })fY8ȹOxBj;ҰBIӹ[}а8|z^@Pos_ĉT*vvv|j8Z,mP*v`0znRl6K" L㰻[%1ovvv0 zJ}Aq-y4MRT `j?|1pyZ-y- c9{?]>sf'l@gĚT B TuMDa(%>`DB2$h E"P`c޼8?43'"Oql.w,n|$qcccTxlnnR*>3MHRCǢWV\.c6v˲( Ьiڰ׺y躎yDQ`0PV9t<3LMMuD3?6|(kc\vgk.⧱R6ݭ: j1;;4j;lt.C&%Tt6Cw'ɠ!B ]iKܽ~ò +*%"@munr-'9s$s,uy_0gϞ%/{q9"W^ell DNCf9r4מ9s0 i4C/ZmL4A!ɀ; qHgeeg}P$ {=N95d>`O9~(z.|8:ܽr)\r7E n߽P DXEMRhR`&B),Ӧj噚ٗ^";7Jbk&=`]߻x2,B[z;M~>FusEΞ=alll^56iR(8|pf|}Ǚ… (8pC^.f=(^m 0 }6SSS@Lt:Oez@X|Ts/|o|[fG4Zu_'9H^)tWR)t!44B/~e C n8li@K4fk]a O^d%kMjKHCczR_&C 4KW.1>>>\R# Qs$I4M"vwb&4mXRVz,..rI J^O$4xG" "|CEvIRDD5Z{WX$BΝ`=/S9#tDT.6v\6C'  Ri$!pBfD2B-l/ot69px ie]rQgQ]Rd#k׮qY4Mcggg8n[XX͛Wؙ!M Fmy'8Yj|[S!tR^)%ǎƍ8q!\!Ra3I&b&SO=E* ڍaH#R(➢aģ?CBȧ>i<ʯ o63؎/_٦ir ʥ|8zwH ffg9Sd'HM k(!<.!>kkw.ߣSX-yT'-unac6̣>^E<>>Ε+Wmӥ^'4M|ߧ9st:=,--q]677 bgid|tb84M~ӟrq:d0`Z֐|S/."Nq-N#r^>Ng$!㖊"4-*[eOǖz3<"%}A MO _'|sf/||-Bzd'~w~s|)P{#qZr>|x}guu%?ѣG)^͛7qQISN"`vv'Dx>‹/8\J`0`br뢛e~L˥ w/u९~|;Ipi'5F$B~D!A!L"4-&p RR2,Yw:}6sO_]˘r|*C"D/]㙯|ϼ;3㣩vڐ4ZTh4T*t]OLL %7!k||4U^piiaat6$ґ#zgd7n0777-MqvC~|٧wz(ˤ8?I* ˡR+|s/&uR$[\d= v(cds9\%]Ө5 ays/mHAKp1K' a?|s/?LdJ%<ߧ`%(HC0f/X<ɓ((J\zJ2(lllP*pE'RD իW`llgrѸc2i$c:U;|1u]jqez-Ο?O$LIS] p>Y <\\dnvH.uCGpi7k\l-pNf!.0HDJbtM*g8h<'8 R}UJ ˄!p3HӿGu+"W^̙3?~|LOOseΞ=i.]DXVlvXz!T1T/:PXhyD2V v\t%ǡVq֭/^\c|>w1>6I24Y\\_s=3n)2_<;5r;4aze+0"Hj_ ld}iF[?}R gT{ő&_җ;Ds'u[?5c*,a Gs AGߣ>e\b{{u''uLI&N͍7u{nf=-)Pvmlnmjs'׍v./1uXzC \R4Tےo}3BX &w2G9s >N`i~H\]cfX]_#ϱ]=|!VR̜ai]-b3Ӽ?^eL~|)$WBS/#,N?b}.]?~GN8͛79qĐo&׮]X,}7nf=/yAt8qRiHjZCA5ʽ)ej^`"86+++VP&-IH`bb">:p/~-Vz|oqjuOemm;d|b/0]>Aݡh~HZgjrb>DZ#trDm5tC(]1s_;ɁB'_ tO?~CtL OH:X^e=ryzU{t=j&loo366F9r_C 0 D!`ssl6) 8qD"`0\p!ވs⽑ӧOsVזc⪔C C[[[H)9x sssr9cp<~׾?rxo\|sO}MQ!Ǐ2`0B.zMfffx'H&mܹ;3TH0 TfImdY\e|B*brzzS~ĉW^LKL%ȤMldyus=Mkx㭟"/74@*BT{P @7BE{P059 5N@35ʳ:; vleQȤg! t yp6 Жer)^ʱcdžm;w ivY\\dbl`es ^ʽ{X^^u]|' ՙLnM<sS)%s\Y?̀";; \C(Kܽr6_x9(Ap?.~  T/}n?(,̓YNIq1M\>+|Stu,|ܣL-ONN2 T*2555ݞvR'N VSCE=N2cqqqg&ܹsr9$R\+똊~Og}}벾ʃLNOS,y_[[J|ŵ+T;҄ ̲x&㇧8gPD]wZm@$- p=P"L۲H86G0iCCuh7`%$v>'d|j㠔 gsg0oVyx[M''xORB7>*.MNN{{7n TAP*ؠ\.ip|̙!jmm%pȑ#u^ϧ?K`v5B6 ~zchh͏O9p#/-餅#X * (,'9*M`JCYz.Magm|&)0Rom 4&LRd?s/I /}$lG ({VnԩSޒiCVX1J)jlllRx̔ޭϞ=K. x>k_u^{m*c)>K̗?>kK+LrhFP ܸ́#83I 1aD Hv⪹ZoCJ33p%0LT7g˫Jq?{|n:DH"!2nm5sߧX)dp 8j6LZZ299ɓ'q êԩSܺu'N>1 "Ӟƞ[V;Ѡ?C۶•묯#`1* .cq4??Wsʯ|Ʊc!}"_!mLi'?2A>+V6lW4vv@IۢQdQ"!47ns-2S=֕KD=]@=, ŏ|{mׯ3666 {p/U{foP(PVg˜8qbU0l !X[[} p7 l6;7ٓX__6M)1.^8]teMvV"?>I)(s""eP|Oᤒ:qE2p\B(W\A?ϝ;wPJUW^NAÐE~:;;;QrH$H$qA2 +k?~9zJyq>৞{t[gm\yP7x/_~ ~E $'"2T=`ɍ[wXy['45N*I Vcq'P P)v.Z^[04rخn319Aqӟ,GMfT۬sa7999d:?t]Lu]ݻP}N>͹3g==鵽}(C!=md2m۴Z-yY\\_N4MZp\.Fԃc|w// :z)!{mta:&n3뼴0GoD?~kw9u4_Ie*m!x~<3?uޠKW{A{$N+1V,x@ˀctZMf+?wy1Ƹz*J)N:\vSNl3ɓ'}ýk8ٛ NT*3t:`0YE:X,bY㰰y,--JVÙtzHPu 6NawTƻl\mC?22i9sj 0 'Nݻw\իW9y6Εw.Ll=O> cPj K\|k_0? ׹E?'rFmηKz$r2b>hRR\|{ aaaI\2;pp$k0 s666HRÊٶm.]DTb||C^E MuVWM~ _{6=78pɃM3U~ij_|?2ϵ93, C LPth4w<3bL&E*c&J(@q~AaѨ7IcV* @!ˢ &J([XRRsJJ*]vMXrl ݮmoJ umWY_[#QT#oos9 KFX"2L]:ab!AM|%aYCDuiۤiJe5s/JbZ\JEu]6R!>ehS L@G`d >tyHP%C"GC{)(04><.}wjiLd7B~c%1riĿ㌻d 2<&R让4  rij*Սxlwn&Ɵ؅nqޗ!yrK+p=ws;}@$ esa1p=Lc!F">Z">(d>BE$ J Ս*a07?mۏY߃zlW,/.Lb| \N=ܑ>  Jz>#~(ހzn'$PhJ+}P&cX_]gX_)v_0T},>x#@gپ..vb6P?/B=`R>z$ 4e@g>RӶbsn_A8V)ץ{ed F(c\!wO 3Bc/y43Q|^@4lI5Jl;e; cvx_Rt ˶x:!ap} ӸͱK@!R~)t>Jyn? UNBd˲bY ), ifF(؏;x 7BeQ*xZ xڰ!(| ]'a[H!B& jun2=w0 E ĽF$Mll=7o>/FHo>0 0h6;]J mw,->ף86l?2qlM B}Am(k{F 51؈J!5 e:-RB!QB44,rTSJM R@ " b!IAɹiWRR("-BHD9:G΄P( D )|0jr>n?J9OMcpw4o6Rv{{+)4¥46X__&-E(E(~U%7v6 "ۧw_HMc~ٰ H1?wryl2a qaplAŲ"lrVGpMvVI#$ףT cS3aа4)8H!Fu΍B9M +PSxr@dce ,g=Laz@u7X-UC9&$eM/Mq92 B(WZ ı,,)'A)_LTQ@(gܰqF(ؗ2 Jzvc4UH'mynPS"ʱYcVu㱚Pt4L4Qd-R"2YfvI'RŅF#{J&>H!4a} G=@J;XIHmVWi-P fҕ REF3QgnfH|m&+,>I)"=N}""j~<>ylUkT2 RHm@]6w6|?2~}8.5K)0 b<ӏ`:׮]piH&tl&p= nU1/laq%Ɠ@ iUyv*}EeQ84#u`nr#S,jnx?.|C' &zRXeVEӌD6~P/FܟKw+"2{<\ύ;;3D=tDG'1?s ǙLpuz:%#Gr(7\a6 +¡S"N@*<@±63 ޮ1?; $Bs{,.r 6kkD#֛@`OTcK@!L!Iy,MҩG$eФ 0vyH2N3>>_bK¥֪sE,=@i)$jwOB$X㌕9y,( D^"A0@H$~&dJ~FeI`6Bh]>Z: zkez^PJU8sh6[eceEFi$&vb[@e(S8M>'aیAEqZ@õ;(! A bo)I b{s@izUT*C.ApJi(%I& p>Vg8 ?`Zxz8U 4t 4lfnn#Gpdʅim)mdžGJޠMA|EPq(e2e%P!l2n3Y ʊ ?aN흿{YXxbJf17{9"0p][.nCE>!mPdO@9+EvzPހf}߂ D(A*%hvc u:aa91 bxe,*! F;!#AiH :7w5 $阭"]$W ʹIVooit:A 5T 6|ĶMmcY~2ϣbS"\|6 fb2*8.MSYDxDZ&aH2()xȃƳBɣ>i&w&~6~a(j[ z]*BВ9w=ekU!w݈Yx8CX`|LqXPplʅ"VAC:J僽 uV@H4sSAU"4J} dcccT*qDu #7HRH~1??E.w4T ci `ːkg21J z>lةڮysCh9*B/l:%ڭTxKV ~}鄑miU[lmjd3iJ*+@7,c+3(4Z&v㑊CL*Q4r<)4aRqxFXz jFc|o5Pm$0F(؏,s؎IuCdR*+Ǽ?v4<ףZݦJplK$dҩVή#U:V e20]3f3@zSn4۬jHDBR:R \e{{C$VDZ9r<[H))ʌUJh*DfM$$\a;ުF\bh##sW Aj~9|aYJB׉RD:)5n\o =`63ÞOgH%ӴZmÌzMخK#IӉAlf7SxVu,DZ)K8$ ÈVX2hڴ]P1z`395aX]Ul83TyXJ&Q [fJ @?8$a[(TVEELH!I=RkVƶ|&azQ@Z0l %$~lYz.;; jBPY,lKJlfGx>Fbs2%&D=V3fvŁ]!Ƈ$m0^)zQECi#8G6G6F6FF##pd#pd#ld#l?֗j'$uj;U_-ô0$Wpm4M ~v5 z,mR*5 !bZn u4Q(ItMRFXz!DuLD)oPJa[ 4]ChQ|;L"cY:vJHukW~ʷ?|ՍEv[$I|C4A>a}D2A"I&~0 u0PJ{ac&ȤssрHIz>1>9MelBD5ڟFm\G.%eش ,\)?` l $v\6 ' JEi=|'`ab )rlUGp훌Of5NLNHlݦժ1hf'ȱq])'`cckö-L$ft ">~MhA@ r40Mp4)%L,a6JЍ$;;[ $Tj'O0^˰B4IA>_7>&faiseMt<ߥ\.@G!4en%8jwS]# tmR'9{iNRwxɧu0*RJnysL:%#/(tvzԪ REf2XB  YAHOxfXt>AÐ:}|_!H 8|`rr5b2B~l$ueyE.{K_jIw V7t%T\:O"i8HbkE^W~?2>}\6Ío˗HgH | YkS#G]@j_#mznĹ_!Q Ðu$qZ;T*8mաV۠<\buyxdʤT,Kg2xl0 x_ӟ"Q[ϾfD0yy>꿡X*2B~ ?ܩVӷOOj>t3G#gOʼn~qX,Ta"߸ݻ79|h#%?$nQJNIz}A$RJv 4$qEkO:cC,񜧰ϽE3_(LV`suҹ,JD`{17;K~lc\ɏܗ/ W!CKE!vuM64-dA H86| C@  PJÍQTy N1=;Cvfxϐ-?B~`1[oLf8~lxؾ$L&h6>>!0=3MӰ/eBò,cvr99:}X,-f(+Զz>y4M'ȧ o~B~;=M3L 6<G؉XzL&sz'=I8ku ]gjjNK$K5iu>6v1+'tmڍMPǑ KS|J*]$?Y{q›#;*}0CölĠ)ҥ"_d2 ,N 1B4i7Z\}nm"-DqvHRm0bn.4l΃L-&x~w;@2'|[p*L&n~-{.=`)ب{ܹ;*|]/C{ST?]nܻVu^o@P# X^$0\,felld IhR $G>! 'ɧHʴ ~_s7;Lڸ`?怽D.J7"s5=r;LdҡTB) Xʁ4JH)eVCQ$I9FM7h5[$q=R)yF!v"G&Eݥ0p_p 4U2 JFǞxד EZ&Q!~'xpwlΦA!?0.Ͻa+W@(mS(ȤH fظRN椘X'?s-lL%-AtFa6Lݗ(7'Hw:nK&17 Àb~tLu+:mv{ M$^gP(\7In}0mDDFFJP*#8|60;;CZrAMA5M#/::Hcch2O{.Ha|lh@5pSETJWnqW |-J؜= aH% J|k뫄JH4=kmL`@JFt} R" 4֖X}pCS]r:;IcꃫyZuLwۄQ D"+pmB n54 0, !QB+`hd4(:Stlf.k| Sgq[&}޼^)lK 0vl^mWD"C4me֖Èllmc(`um (Q:I+cllnH&1 41MCG(؏/gUL otxaT*D.LPolԶ 5N!g%_cqe!tt{=ret^L"D!y#A>1'ڗ>z"RY|Fk[KwtH*'аl< lֶ6- $LDR =,Amm\ѱhu\-N-^w >~NVH2 >ɔeY2E2 O9W`?V@q Usq ;;lLR)OGdJCDҤZuRJ!41[N(#(bg$]jhM$u,Sgll{pyc;R젙B J>(v[A#w#ry GJY4kܼ#4^5>ʓh2"T ݲbg@Hk:B7p&ʗtk*e2$;N!`ll}C~d2õkz(Il'A2nPCx@QG?!w{)2Й;R:m!LCm!#P:^odvvo@ \l*_gk! cYtC|&:ss|?G JQB #zK2`?zJ|W|po!l5[9GDtFMEF>t"`0D7trv0(Ob:N7AHEQDC2=l98srnXD[+CrYɧXY}ȃ;X(H+ςI9i,cl|RHwZm" !T7@7M$5\"""T2cU-!le8A2 ( $ ;I}E =H$;f"wh4OWQ3pyE x--AhOh $ ڝA|N!63Q4cy>mEMu5!! (BRI.|u 3aݪ5\.x/ov>oCuvZ;|~ϡy@a(tG}L3I"npu 8z ^I{F.D e&RA L#$n"tc%0 ͭ-I8(C&fǙ`{M xUz* G!aPt }I&6Y][ =i;Aga**,nT&ة@NnihFy( GR2F,ӦA@D!ik+Xx?4{tzLLU`?8F>[*o&}O2$""tu ql;"P &*HP?B@T؆%1b&4 4la໘I$%!o_ʭ˘ENeiFm} wPN2"Td4I=@6iEJQX1_J @)5麎p#%x,8@`aRJP/9zR*"jɧyǹvݡs,A"N uGJ4sY676"pIݽi`x&RrRZF&nIa 9!+}Rq"C DK9vW&J4݋|l}sW4xmNgJ4Y__h`6d]qcǎEVVVx'vA@2Ķm ~_A/Yp@ң_(ޖi6yJb$duz->|H2$LN-(q<ϣ`JEX{`7_ G=99I"1#z;iZ$IDQƫV'\t%/377ϒdV133r9VWWG(؏!x/ϵ~뺔a4K.Q.d22Cݻisu:333dqt:r9> N>hÇd2ÏA@}WҥKJF٣/ܣ!J8x t4)lllL&rN&j1??d#Gt(˘gqg-:dJ.c~~~= y}{ffL&C#Qz|򓟤X,jpCu/\w!$Qdu/{$uwyo}+ @RKɦ(JYQ(Jȑu>R+㸶2]^eexTWdwv9i4%E" 0`.}}o0ih !OUW_sZVua$zJ){>) eN4)Wxk4}j [ęVVVxٿ?Ν㥗^" C;ZkW*(J2>>RnKRabbq!Y!8$I(Q1::J$!ַ:Ĺsַpܹ ! C>''|Cj+]ӧy9rVRđ#GX\\dvv} v#땅<{>γ>˯گh4֕Jz|?6\\\drr91nֵn%nq׵* n .$I#G033C8jgkpA&''YYYA),(\=p8N Yzm4j5Ν;Ga/L}ksss~h+JZm7p";wߍy8ӏ:vJ#<•+W>Dž GQy[Z[yWxyꩧ o/|￟IZVH@[G28:t_0>;0<@n#>9'yh1}ZtKRaee?@bttZsyfffΟ?ϳ>{~w~? qQjQޭ'M<J~/A@ZZ$'g֏333CE}<Ӝ:u~t؄fqqnK$ sq|A9τ e<|p¬^׊1}Nڌ8 C.V?pZ9yd-Hk_/"I_v9y$aerr?533/_`7pjj7 CKn۷TvVazzy.\RÇFž~h4LvnH©S8h6 v#e=Ckאy|ym;>>·>!Μ9s=G/sI _/-H܊]y׼8IORJ?޷pZkϡCVQ*8u5ETׅBnay7/0-}ɾ%`!{$ 1Y i5nrkmv$NNNk>f{RJjT![Ry6<+>|zn;?eZhu XI%"kʼnG$VcORI~{ݵ,Wz,RJ >I=H(.Mj늞۳VIbMk;q|kͻR_gT*#!(/bz_;ҟt^^^k .'!-?<믰èu1.%;s qE5ќ/$IBoaE46[kZ/lIh^=T*^e!;Z.$s=?cxx}$㸿^3==MRaff߱Nmpa0ɓʮ+͜N>]`7p\]\nj:vĺHk05v5k,li޶íp$I lܷB*L@[[^|?@j&1TSk:t:ONykhn!3lLi+Fdl"  )XHAB )XHAB )XHAB )XHAB )XHAB )XHAB I8ևxfQT|}wL te.ͷ#jԩV|nǡ)eGT1DtBSBlʹݗ9?n{m\ꕀn0s5SqkDePs5C`(˒zɡiR 4 wk jS wfR+$brvJ | < qt'WOj Z"hߑaxӉ6ON*ha >'AV5F䇸2Z\iHzۆcz+P;f\mƸ~F)H Diŕ힢 Fq.:<ץZ W=%Z4 Ͼ'rڦ"+͐xl.P71KMF{fVH0{( q_9K\Jc&F4*u_3h qdSH Qf+f0;BfmQ% g%X; j$a$qF2#`W)b<$CORGM#HFωF*}zɡ%Tˆj   cMjjA qEՁQhz~m̦) #8BU T1Rk qS= C%pPTW@+cC f;$)q8ᑦ1IB)QRXX\$#C'9~##cMт$JH"15mh!&JGK1Νmq_0\r)Fz=CvPhTq \)1ru!{mJ }JPZƆ(fhhv4Ҹ8axtJxۢ!ѽ/Z"즄jH6 Չ&mnÄQVxŷsX8*"p%ᰲƨ)hp%8B7GKZcD) )4kV&jOQ 1-u8>QG>nk4zuNsGv 5+cxN`$djHej2r6FWLL F!qb?YPy8ߟ;=QF 8l3+rr[ƥ,., VHtjNP&I6buX5UqE*Du1nԀq|pюq]H47gSٛ| 2G3F|x\l9(ʾAS0=1rw)?P9BZH qK7uw3 Kj_TQ/M[fXvkM$Kr;ek9{ .]S? -H]%A:JDT}G%D a/BJRD%i!11}xq*%Ib~faw2ݜ\v+)~%:]>{3-^cMvBv gy˸zJҐ =E/CC+LiF=fck%ЍcR0ЋSV-LLcѠ\.Qp8IlF %=P%$ܳ@EE6c8s=FPؽwLYAW=Y˼}8 v\B{2nw7I* q*ie_YXh&,u Wz ( ! A14p$Sk A ܠBS'2:ƗITD:D G#%pWz"gsMH'R+oba%ub\^H2s1BxPO ++ÕJGT\o<:6v^vXtZ+R}R9l8)@#r M|JhHЩ79y\]^N7ml߈\.g)<9)JU_*QvPizebdnV#4zzLZRVv+^zH\q]:.CCC? !w#TE)+Jw?(ru +W%{>~Gs37oMȟс8\G9d.;9fpYpGTpRnI ib`W d pz΁lreQZp$uѱQ*WZFVmwpmp!p|FGFPZs,RKWx+O1R)0F,?K6s6:.\6ޟ \rs"g)V -`S(A9@:jf =45KsqS,L,Vycj*PT36:qtZ9൫g:\jA+T%l;h4qgQLꢛ A⾷ϕKuahNg؁v7Ab0("C\(P# ՐT{$)@ +6sh#e6QZK%TI" JG5TbAuYRO2yNvHGDxfkvOq~Cv 0#AG @ JjBE& st(Qڥ Dڕ\]iJ&ێC OtX^9K95F|H 3s]^|e<}3G C^cldK.#QXMPg`:j$ Ab&ESI.zn F/a~ω(ez JG`HICVZP)h|C" Ыٳ#PZ`J+g@1]Il$GQ x14ëw/rJ#w%G~=C+pɁSDQO=̑o̅?@T|A |O2>>pa|G C8JɥZvBZSgu V]R"(zo;>|?Ax>F9i|NZHcNnт?A… 8C=@v9IVVVx{~}/Zh9$Ƙ:u]* Cõ*##Ɔ4jZ@9 !KhY'J$\~25'B0e$8E*g.-M%cEzwW~W8z(M^?~+LL5/3_8!Ofdt|0a}gfgQUE1Ɔu!&LJmDMV7$!UVPF4 V++1 +ݸ&Ƈ F_Uկ/} s#|zúh6\cJ)G"Cmhgak\p㻼|aňc =4Dhcdrꘈ8:,`\${)0# |j/X ?~Daȃ>Bp`zKyw!CC5~?@ @:FN#<#IbΞy?BKYccS#"dzeOpiB^MX4] R:K87U$]Xaw%g _w^թ|Ͽ|~y,\aD"繴Zm$BA٤14L 1 SU}#w$p,1@Jn5ҨAm1eWF3ktqT* Uk8Z,؍|ioyfNwull"jsϾZ+ƀW}a+m6+tT+65>s/|OPƕG zsAJs=RmEK04$7dj_GgpvwG!c2>}W2#,-]%=ۇ֫SGcaqӯ& f/]w;h7yg^eb8^ w1\WJC* x,5C.-f4)ľ#)X SQ:0:Rx Ü9 ˋ kzm&&cBJ jq34T\)10}ŏ=c~,..ݗ0GTJծ0ϕhI+݄n] CTbjrCrH2Wplvb6~ K|.KEVW9p v$IQp%ߕ'qP}=zann^/G /Khi4,--nT|TUFGi&luiR{{]0wsW904Nɑ8h!$!zࡄG%/h TB )Q, `!, `!, `!, `!VܧׯBY?z}o?o Vjߩk hn1 5z_ƀ*|7mc=,p>Z}ݿ>#xסsGmw\)/FcLb˚dꚺ3~h:wϮ7b^O}?w^cx]ߩݥ1f-F&oM1_tSP( q~03x#5xofgw/F^RJ iqG8k㜭_l<RrfzV-pIH)ͣ߭; {c~bA|tfn0޲`<#Ti cVD܈B(իAE:[Zx鷊\ !tĜ0q]X3_l%ږ$HDhcQ)obA|]'5ּ[mlsΕvo܆L(L:Sۀ;o^ xॵy`LfЅh̾`l%J)ii*TΔ)0c D!܎Z\oRhxjvj}6yA-'XWcAkZV)ˤiڏ_lJJIpJ)a/Y)hR`w;^zc0]`V֕D>αZRob ;#4YL(LBk4YF$N` #ojPfAhgn{Ζ$7 |Kg/d,u37]ӝ|'Y__DYR<ǫZpktVG)%(J)aLqẮTJ u;^V،u@Z+$cQF\w$p$I"1&IqVNQ:MS!r4ij)Xͬxj[^pGgi|Hiiu޵k.ID$IBքZGqLc2Vv* q[t?QT p>ϱϷ`j-5QYB2I,3ZkF沸~+IJ֓m;k V$kZD[߲Z`і$IDE*n!BezZk-4ՎLJR<[GJ6/zXൃ8M~&_X8g?W,˷D& 1FFQD6S)%Rjs$B'g0vBv=^o$dɭ{igpT\K y-Z!dlH#{YւiZi]]}f&!np&/6;`Z 0Dk8춱8(8"+S.y]?Ua86IE͛F譑Q:c\׽fdh%y0j6/բDz=2J)DZQJ qBq,,̲Y4MuEX^/)YHE)Q ÝkPR:L58y^%fZd5-iȹR&Il*?_{iaK@:#M޵hmjϵk'(M;ASJ(257E0 t:&M~ cͪI>Y^[\AfR< vflVm!s V?2o2^nK4n'|߿L))hͥZka"%{?I [껕j7Z2 n v0^pCھ2G.둦)el"ˬeX5*Y4 RJA@ ^fAt~=l?ɦ>n̒*D$$/bi8Zk [6wf֪aY0%lb㜬!2&5\Fg^;kEVOr6a \@2-+հK)e$6dRFۄku+RUr,`6ͼzX@s)"վ/$Ѭ݃$[j\QvnO`j]$I*i]}̺!o^rKV*,j]ʬɮ3`$It6A:I2RJcC9M5h5'Viqߕdn뛕nmzX@RL mi*&MSiUm}[7yy`LTxGfBS xt-F(A۹,ZkUe2iVc#M 4 %UgtZkinKk ȂmoӺt~[YFsbX;9lfw#Q-6b v?t֤4Me6-6kw sLl%2jkoےGuM&gn nu[(0Bʃl#М6uV XrT+4Ymk@=uf][(DeN`ZQ:ɻk82XK7]/'538ty]pZs)lg'aLjrgKlOs.4j_n(6߭EȂ=B~7x@a+9er&ܮspZl *gI#RۂnMJ׎[@eV;F "Zk_kɚf#ww+V dn+`ެ$ĮxUJXiHeugk^1рD }a Ū0z_Y ϡ6+MS9~zc^$$Nmpj *WXff# X7{bě~f@ ^R,^%z߼=] ުH Hhxua7wmdheVwm|tB, 60RRRRRRRRRRpAi!o,^חvV x͉q^,VVљ^[@ow*a魤&w]w[/ߙBIH!, `!, `!, `!l[,Dې>[py^ׅצƗ_) oo$Yx sre:cAl v3`vr$v1\oмQ$V"su@[Tz]O9k#:$?^z%aH\5Ѝ4FA5[ s@&,5pVp=2Y, mqɗ'.\D_+XɴU|M)@j[!V:ނ5H^b K:(j lysxgPף[2.T*{{zyddd1ƗR׌1+W wCB@snF@V,V{?_'/tFn4̻N^>O__%:=?3?3W*ᄋC@#G/rJ/?>:^vI2 8׻2^O~|ūS Z˄o@nm g g,9+ x;v{~4*r׆2>x7/*{@;ZU4s5,k쥗^Ǐ^B:W/lJ+ڝ~@h#'YT{|9^rVp3P LJ_/###;qXx!fs["5zhb񏉉FLkiY@硇K\oKqmBzx=^}٬'QV42om @V=傃 -n5{/% xWp[4ߗkxyԖHe )N,.fz^cIH'y6Gq >t6KB#G=֊Mv| Iݱ1o/p/ Mu# T*6yҦOJ[#c6+}cA3V{/U7T⸮3 qËuVGJ !j;RJ\xm[T)S1`h^b;xmfٮx {=t6ڼ #pǭ=8_ExWK.8k-훺`)t=O0fKRd//wEӝ%R*ZC{fxn p3x3⵭զ1R=:Ub!sG_lY@FmU _nXWB챪BfzY@cz ckUVb?ƞ8ho t[sYkK= /dX07 &[{RM ,p,\p!\B k,F(bYp!.ERH!,,d IH! . .,` ),`a,*!ً f,b. n^0cDa=Mq9axMr=6)xI2`J${^r3k\PEچVevV`-σB@c"^f;q܂kkAw^j<x>^,:xm[ʄ͵Aـlⵗ@c+ƀ&\D/r/╮Y벀j̢#Jm-^^k[J@ P 1:2<-nŏ^5,Pؽזfxh^iVVVv ^'r 0g?oX K.,йl ~WpR8mI2.,,쩑kz[F\{ /=Xb:!yK8hVIaou=Jibv{i"+Mڼlv{^f;JBKN?I W2q `SN Vܯx1,[vr مJ'-dX=W;K]V[5약d[V7ZFxy^nuPqkBXhlUޒxm)t4L鹽>gw[q):{~ x73^[<^^!Y ۷ޗϽ[ۆ$IrX}p-d 2Pڷo=V;5xt&ʕ+~VG$IV2ÜVo%㥮\?}+#&xm.eZ]*ry'xgGn o|_Vfhe^vykX<^s3~Uodx5sxfxm"sֵXPK٥Tȑ#c㔂 ( Ս1P=I#&&&LVFGGJR DR<󥔞8B#ZiEQ6BfqqQijΟ? PQNe;Nnw1ٳg3\́f,2^ekqrWmx+R׉("i%2x%9{pL`HF@9@ rNm6׏5nCV3UV9\V^V׋W>L\_/^f iZ ;([k+eUeoe;\lr :f x<:W6P9-r<=WW^b $ʾO^7<frēX<6ziV-F+ Mz&x X+u0X;l1aK;A@}*X\Vy\Kl ! ,5[v2iZ' (І8Ell؍Y_zY~^[Q؛"K_.)"g7K(L\4iVrFz,$xmnzy?/3$y#],N/*vƎ7S!,Y'# y3!]%(\ʺtIENDB`AppGeo-geo-f763e47/docs/examples/utah/css/0000775000175000017500000000000012005347446017252 5ustar daviddavidAppGeo-geo-f763e47/docs/examples/utah/css/style.css0000664000175000017500000001457712005347446021142 0ustar daviddavid/* HTML5 ✰ Boilerplate */ html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; } article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, q:before, q:after { content: ""; content: none; } ins { background-color: #ff9; color: #000; text-decoration: none; } mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; } del { text-decoration: line-through; } abbr[title], dfn[title] { border-bottom: 1px dotted; cursor: help; } table { border-collapse: collapse; border-spacing: 0; } hr { display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; } input, select { vertical-align: middle; } body { font:13px/1.231 sans-serif; *font-size:small; } select, input, textarea, button { font:99% sans-serif; } pre, code, kbd, samp { font-family: monospace, sans-serif; } a:hover, a:active { outline: none; } ul, ol { margin-left: 2em; } ol { list-style-type: decimal; } nav ul, nav li { margin: 0; list-style:none; list-style-image: none; } small { font-size: 85%; } strong, th { font-weight: bold; } td { vertical-align: top; } sub, sup { font-size: 75%; line-height: 0; position: relative; } sup { top: -0.5em; } sub { bottom: -0.25em; } pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; padding: 15px; } textarea { overflow: auto; } .ie6 legend, .ie7 legend { margin-left: -7px; } input[type="radio"] { vertical-align: text-bottom; } input[type="checkbox"] { vertical-align: bottom; } .ie7 input[type="checkbox"] { vertical-align: baseline; } .ie6 input { vertical-align: text-bottom; } label, input[type="button"], input[type="submit"], input[type="image"], button { cursor: pointer; } button, input, select, textarea { margin: 0; } input:valid, textarea:valid { } input:invalid, textarea:invalid { border-radius: 1px; -moz-box-shadow: 0px 0px 5px red; -webkit-box-shadow: 0px 0px 5px red; box-shadow: 0px 0px 5px red; } .no-boxshadow input:invalid, .no-boxshadow textarea:invalid { background-color: #f0dddd; } a:link { -webkit-tap-highlight-color: #FF5E99; } button { width: auto; overflow: visible; } .ie7 img { -ms-interpolation-mode: bicubic; } body, select, input, textarea { color: #444; } h1, h2, h3, h4, h5, h6 { font-weight: bold; } a, a:active, a:visited { color: #607890; } a:hover { color: #036; } /** * Primary styles * * Author: Ryan Westphal */ body { background: #ccc; } #index { bottom: 0; left: 32px; min-width: 800px; position: absolute; right: 32px; top: 0; } header { background: #fdfdfd; -moz-border-radius-bottomright: 16px; -moz-border-radius-bottomleft: 16px; -webkit-border-bottom-right-radius: 16px; -webkit-border-bottom-left-radius: 16px; border-bottom-right-radius: 16px; border-bottom-left-radius: 16px; padding: 16px 12px 16px 12px; } h1 { color: #1C56A3; display: inline; font-family: Georgia; font-size: 32px; } #basemapButtons { float: right; } span.selector { background: url(../img/BaseMapSelectorSprite-v1.1.png) no-repeat scroll; display: block; height: 49px; width: 50px; } span.Lite { background-position: -90px -276px; } span.Hybrid { background-position: -15px -276px; } span.Hillshade { background-position: -15px -213px; } span.Terrain { background-position: -91px -18px; } span.Vector { background-position: -15px -84px; } span.Imagery2009 { background-position: -15px -149px; } span.Topo { background-position: -15px -18px; } #pnlInfoAndSearch { left: 12px; position: relative; top: 12px; } #lblCoords { color: #1C56A3; display: inline-block; font-size: 14px; font-weight: bold; width: 512px; } .ie7 #lblCoords { float: left; } #pnlSearch { display: inline-block; font-size: 14px; font-weight: bold; } .ie7 #pnlSearch { float: left; } #pnlSearch label span { color: #1C56A3; margin-right: 4px; } #pnlSearch input { width: 192px; } #pnlSearch button { display: none; } #map { background: #ccc; -moz-border-radius-topleft: 16px; -moz-border-radius-topright: 16px; -webkit-border-top-left-radius: 16px; -webkit-border-top-right-radius: 16px; border-top-left-radius: 16px; border-top-right-radius: 16px; bottom: 0; left: 0; position: fixed; right: 0; top: 128px; } #infoBar { background: #ccc; bottom: 0; color: #1C56A3; font-size: 14px; font-weight: bold; left: 0; padding: 16px; position: absolute; right: 0; } .ir { display: block; text-indent: -999em; overflow: hidden; background-repeat: no-repeat; text-align: left; direction: ltr; } .hidden { display: none; visibility: hidden; } .visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } .visuallyhidden.focusable:active, .visuallyhidden.focusable:focus { clip: auto; height: auto; margin: 0; overflow: visible; position: static; width: auto; } .invisible { visibility: hidden; } .clearfix:before, .clearfix:after { content: "\0020"; display: block; height: 0; overflow: hidden; } .clearfix:after { clear: both; } .clearfix { zoom: 1; } @media all and (orientation:portrait) { } @media all and (orientation:landscape) { } @media screen and (max-device-width: 480px) { /* html { -webkit-text-size-adjust:none; -ms-text-size-adjust:none; } */ } @media print { * { background: transparent !important; color: black !important; text-shadow: none !important; filter:none !important; -ms-filter: none !important; } a, a:visited { color: #444 !important; text-decoration: underline; } a[href]:after { content: " (" attr(href) ")"; } abbr[title]:after { content: " (" attr(title) ")"; } .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } pre, blockquote { border: 1px solid #999; page-break-inside: avoid; } thead { display: table-header-group; } tr, img { page-break-inside: avoid; } @page { margin: 0.5cm; } p, h2, h3 { orphans: 3; widows: 3; } h2, h3{ page-break-after: avoid; } } AppGeo-geo-f763e47/docs/examples/utah/index.html0000664000175000017500000000673712005347446020474 0ustar daviddavid Atlas Utah!

          Atlas Utah!

          UTM NAD83 coords: (453709,4333922)
          AppGeo-geo-f763e47/docs/examples/utah/apple-touch-icon.png0000664000175000017500000000547312005347446022350 0ustar daviddavidPNG  IHDRnU8!sRGBgAMA aPLTEsUBsYB{]JkaZ{aJ{eRck{sqcucsƭƵννƶξnj߄  pHYsodtEXtSoftwarePaint.NET v3.5.87;]IDAThCWy_H2DtD0΁?fWzU+V~+O׽+%ɼvfI/f9/ps+!;ܴ5_fwq\ iv.\Zœdl0{Mib kzDTI_׋&:G^sLuYdsV9~'!Ďx"9\S0}~.O&޵즼45l|;֑r8RRvⵛW]}n:2&응T3(zx;L|YvO&GxSlq.hqO4fG"@ y8f62ÃQ'<Nr<ޛvЋ#/3p@|Ffܭ7.m]In/=S:mK-aCO2˵,ȃr|r/עa>pO~5dtc?HW'u5ϳSA-C6niҝXKA xJ`?L{ u\r?4gvό`HJߪ5ڳePTfE\^-Xf2q5eF2$y* qvI}F/Za@`fЩ$(/1 $00"Q+20P`K)ne-0<=pЎXR%O9d'Zl+@ G6?gGu΢kyd1zɒ.E",e[?y`3D Ťِ z Q.O<㖘+8X&sI,YjNeDh_lM{,̯@X1gyxĈ"/M U72kl&tv^288pNX[V8} '׶x;[ 3*kÖ«6NB,Z}\p&^k 2A8qa(^##da"rrȎ9f*@N.hztUz`dpi!rLп29w>sMn0^5a:K R9&7nls*woZW*wl"]E!t'x軼}>|,-KLy\Of0A3:t-&cpD¥=nSNCF{RjB wJL$Y\H~FY~~?^Syp0f;_Be]m {mNd<~+)'}]~ FebA;R,wLAa8ឱbenpo<.{% %^֣Ogkm=_"L>{[o;q};OC^/lDY np_AȜ_OBix}[IENDB`AppGeo-geo-f763e47/docs/examples/utah/favicon.ico0000664000175000017500000000137612005347446020612 0ustar daviddavid ( @XwwXWxxqqquqXXWWXQquWWWQqQUww_XUWWWqquQqUuuwWWUUUPWwqqqqquuqWxwWxxDODDDDDHDDDGDDDDGHDtOODDOODOODHDODOOOHDHDHOHOHOHDDGHDOOGDtDDDHDODGDuwuuuqWXuuuwUqpXUwXXXQwuxuwqqqwuAppGeo-geo-f763e47/docs/css/0000775000175000017500000000000012005347446014473 5ustar daviddavidAppGeo-geo-f763e47/docs/css/style.css0000664000175000017500000001255012005347446016350 0ustar daviddavid/* HTML5 ✰ Boilerplate */ html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; } article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, q:before, q:after { content: ""; content: none; } ins { background-color: #ff9; color: #000; text-decoration: none; } mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; } del { text-decoration: line-through; } abbr[title], dfn[title] { border-bottom: 1px dotted; cursor: help; } table { border-collapse: collapse; border-spacing: 0; } hr { display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; } input, select { vertical-align: middle; } body { font:13px/1.231 sans-serif; *font-size:small; } select, input, textarea, button { font:99% sans-serif; } pre, code, kbd, samp { font-family: monospace, sans-serif; } html { overflow-y: scroll; } a:hover, a:active { outline: none; } ul, ol { margin-left: 2em; } ol { list-style-type: decimal; } nav ul, nav li { margin: 0; list-style:none; list-style-image: none; } small { font-size: 85%; } strong, th { font-weight: bold; } td { vertical-align: top; } sub, sup { font-size: 75%; line-height: 0; position: relative; } sup { top: -0.5em; } sub { bottom: -0.25em; } pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; padding: 15px; } textarea { overflow: auto; } .ie6 legend, .ie7 legend { margin-left: -7px; } input[type="radio"] { vertical-align: text-bottom; } input[type="checkbox"] { vertical-align: bottom; } .ie7 input[type="checkbox"] { vertical-align: baseline; } .ie6 input { vertical-align: text-bottom; } label, input[type="button"], input[type="submit"], input[type="image"], button { cursor: pointer; } button, input, select, textarea { margin: 0; } input:valid, textarea:valid { } input:invalid, textarea:invalid { border-radius: 1px; -moz-box-shadow: 0px 0px 5px red; -webkit-box-shadow: 0px 0px 5px red; box-shadow: 0px 0px 5px red; } .no-boxshadow input:invalid, .no-boxshadow textarea:invalid { background-color: #f0dddd; } button { width: auto; overflow: visible; } .ie7 img { -ms-interpolation-mode: bicubic; } body, select, input, textarea { color: #444; } h1, h2, h3, h4, h5, h6 { font-weight: bold; } /* jQuery Mobile f theme */ .ui-bar-f { background: rgb(116, 176, 66); border: 1px solid rgb(86, 160, 14); color: rgb(255, 255, 255); font-weight: bold; text-shadow: 0 -1px 1px #234403; } .ui-bar-f { color: rgb(255, 255, 255); } .ui-bar-f .ui-link-inherit { color: rgb(255, 255, 255); } .ui-bar-f .ui-link { color: rgb(255, 255, 255); font-weight: bold; } /* Primary Styles Author: Ryan Westphal */ h1 img { width: 24px; height: 24px; margin-right: 4px; vertical-align: middle; } div>h2 { font-size: 1.1em; margin: .5em 0; text-decoration: underline; } p { margin: .5em 0; } th { text-align: right; padding: .5em 1em .5em 0; } td { padding: .5em 0; } b { font-weight: bold; } i { font-style: italic; } h4 { font-style: italic; font-weight: normal; } ul { margin-bottom: .5em; } .geomap-indoc { height: 240px; position: relative; width: 98%; } .objectProperties th { text-align: left; } .objectProperties td { padding: .25em .5em; } .objectProperties tr:nth-child(2n+1) { background: #bbb; } code .comment { color: #393; } blockquote { margin: 8px; font-style: italic; } .ir { display: block; text-indent: -999em; overflow: hidden; background-repeat: no-repeat; text-align: left; direction: ltr; } .hidden { display: none; visibility: hidden; } .visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } .visuallyhidden.focusable:active, .visuallyhidden.focusable:focus { clip: auto; height: auto; margin: 0; overflow: visible; position: static; width: auto; } .invisible { visibility: hidden; } .clearfix:before, .clearfix:after { content: "\0020"; display: block; height: 0; overflow: hidden; } .clearfix:after { clear: both; } .clearfix { zoom: 1; } @media all and (orientation:portrait) { } @media all and (orientation:landscape) { } @media screen and (max-device-width: 480px) { /* html { -webkit-text-size-adjust:none; -ms-text-size-adjust:none; } */ } @media print { * { background: transparent !important; color: black !important; text-shadow: none !important; filter:none !important; -ms-filter: none !important; } a, a:visited { color: #444 !important; text-decoration: underline; } a[href]:after { content: " (" attr(href) ")"; } abbr[title]:after { content: " (" attr(title) ")"; } .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } pre, blockquote { border: 1px solid #999; page-break-inside: avoid; } thead { display: table-header-group; } tr, img { page-break-inside: avoid; } @page { margin: 0.5cm; } p, h2, h3 { orphans: 3; widows: 3; } h2, h3{ page-break-after: avoid; } } AppGeo-geo-f763e47/docs/css/handheld.css0000664000175000017500000000013312005347446016751 0ustar daviddavid* { float: none; background: #fff; color: #000; } body { font-size: 80%; }AppGeo-geo-f763e47/docs/index.html0000664000175000017500000002153112005347446015702 0ustar daviddavid jQuery Geo docs

          jQuery Geo docs

          Welcome!

          jQuery Geo is an open-source, geospatial mapping jQuery plugin from Applied Geographics developed with the intention of making spatial web mapping significantly simpler than it may initially seem. We would like to point out the term "open-source" to explictly state that Google, Bing, & Esri are generally free but not open.

          Please read the following sections for more information and examples, and thank you for considering us! If you have any questions feel free to ask the lead developer on Twitter.

          If you would like only release notifications, you can follow the project itself on Twitter.

          docs

          This project takes pride in having easy-to-use, up-to-date documentation. Before any code is committed, these docs are updated with any public API changes and sometimes internal design decisions. The side effect is that the documenation may be ahead of the code at times. Also, any undocumented features you find in the source should be ignored or asked about.

          examples

          Now that that's out of the way, here are some code examples! Use these as a suppliment to reading the above sections but above all, have fun!

          "everything" examples

          These first two examples attempt to let you test as many of jQuery Geo's features as possible on one page. The first link is a tiled map, i.e., it has a tilingScheme, set-in-stone zoom levels, and uses at least one tiled map service object. The second link is a dynamic map, i.e., it does not have a tilingScheme, displays fully dynamic data from MassGIS, and uses all shingled map service objects. The second type of map usually redraws slower but allows for more accurate zooming.

          You can find isolated examples of individual jQuery Geo features in the component examples section at the bottom of this page.

          demos

          The examples in this second set of use the features of jQuery Geo in a more interesting way. They attempt to show & test how you can use different parts jQuery Geo together to build apps and how we can integrate with external data and libraries.

          showcase

          This third set are more complete examples using jQuery Geo. These try to implement slimmed-down versions of an existing applications and test how jQuery Geo can be used in real-world situations.

          component examples

          This last set of examples attempts to test various components of jQuery Geo in an insolated way.

          internals

          Lastly, short of looking through the source code you can read a bit about the internal design decisions we made in the following section.

          Boston Built badge
          AppGeo-geo-f763e47/docs/what/0000775000175000017500000000000012005347446014646 5ustar daviddavidAppGeo-geo-f763e47/docs/what/index.html0000664000175000017500000000535112005347446016647 0ustar daviddavid what? | jQuery Geo

          what?

          open-source

          jQuery Geo is a jQuery plugin, which means it is 100% JavaScript and ties into the popular jQuery library. It helps make interacting with various web mapping servers and tile sets such as Open Street Map, MapBox, WMS, and Esri ArcGIS Server as simple as possible.

          Internally, Applied Geographics, Inc. has been developing a JavaScript mapping component over the last five years or so and are proud to give our reasearch to the open-source community.

          Our intention is to be a simple & fast approach to a decent percentage of the spatial web's needs.

          geomap widget

          The primary component of our geospatial plugin is a single user interface widget that pulls in tiled or dynamic map images from map servers. By default, this component targets Open Street Map data as tiles rendered by mapquest open but can be easilly configured to use other cached tile sets and/or dynamic services.

          The map widget includes only what is required to show mapping data and handle direct user interaction with the map. The rest can be handled programmatically by the web developer and any other UI framework they choose, e.g., showing and hiding services, changing the widget's mode, hooking into an external zoom bar, etc.

          geo namespace

          Apart from the widget, jQuery Geo has useful geospatial functions in the $.geo namespace. These functions help you calculate bounding boxes, measure the distance between geometries, determine if one geometry contains another, and other functions you might find in the well-known Java Topology Suite. They are all implemented in JavaScript and are included with the rest of jQuery Geo.

          AppGeo-geo-f763e47/docs/404.html0000664000175000017500000000132012005347446015074 0ustar daviddavid not found

          Not found

          :(

          AppGeo-geo-f763e47/test/0000775000175000017500000000000012005347446013732 5ustar daviddavidAppGeo-geo-f763e47/test/jquery.geo.html0000664000175000017500000000164112005347446016712 0ustar daviddavid jQuery Geo Test Suite

          jQuery Geo Test Suite

            lame test markup normal test markup awesome test markup
            AppGeo-geo-f763e47/test/jquery.geo_test.js0000664000175000017500000000226112005347446017420 0ustar daviddavid/*global QUnit:false, module:false, test:false, asyncTest:false, expect:false*/ /*global start:false, stop:false ok:false, equal:false, notEqual:false, deepEqual:false*/ /*global notDeepEqual:false, strictEqual:false, notStrictEqual:false, raises:false*/ (function($) { module('jQuery#awesome', { setup: function() { this.elems = $('#qunit-fixture').children(); } }); test('is chainable', 1, function() { // Not a bad test to run on collection methods. strictEqual(this.elems.awesome(), this.elems, 'should be chaninable'); }); test('is awesome', 1, function() { strictEqual(this.elems.awesome().text(), 'awesomeawesomeawesome', 'should be thoroughly awesome'); }); module('jQuery.awesome'); test('is awesome', 1, function() { strictEqual($.awesome(), 'awesome', 'should be thoroughly awesome'); }); module(':awesome selector', { setup: function() { this.elems = $('#qunit-fixture').children(); } }); test('is awesome', 1, function() { // Use deepEqual & .get() when comparing jQuery objects. deepEqual(this.elems.filter(':awesome').get(), this.elems.last().get(), 'knows awesome when it sees it'); }); }(jQuery)); AppGeo-geo-f763e47/dev-journal-ryan.txt0000664000175000017500000034521712005347446016725 0ustar daviddavid== to do == === examples === * examples - jQuery Mobile * examples - MBCR: http://www.mbta.com/rider_tools/developers/default.asp?id=21899 * examples - drag shapes * examples - ie7 - [bug] floating info div doesn't show up, inputs are alone and on the left * examples - redo the jVectorMap demo page using jQuery Geo * examples - make OSM editing simple ** http://www.maploser.com/2012/03/29/all-i-want-for-openstreetmap-is-simple/ ** http://jvectormap.owl-hollow.net/ ( found via http://www.moretechtips.net/2011/12/22-most-popular-jquery-plugins-of-2011.html ) * examples - geomap resize method * examples - Codecademy course * examples - SVG & other neat elements/media in labels * examples - continent puzzle ** http://stephanmendler.de/thinkmaps/puzzle/index_en.html === future === * geomap - [bug] using shift-zoom during interactiveTransform doesn't zoom to correct location ** tiled maps only ** not as noticeable now that the refresh timeout is shorter * geomap - test changing shingled service URL to get updated images (in case of dynamic data) * geomap - stop using $.data to store bbox since it's only used for drawing; store on _graphicShapes instead * geomap - [bug] exception when calling destroy on uninitialized div * geomap - do not interactiveTransform non-tiled maps out past pixelSizeMax ** pixelSizeMax is calculated by bboxMax on non-tiled maps * geomap - [bug] multiples of the same event trigger after creating more than one map on the same div, even after destroy ** destroy should unbind all geomap events * geomap - [bug] there's an extra service.refresh call after a non-mousedown touchmove after a refresh ** most noticeable on shingled services * geomap - [bug] if panning is false, mode is draw*, and user attempts to pan, the drawing begins (or another point is added) on the touchstop point ** a failed pan shouldn't add a point to drawCoords * geomap - ie (8?) - [bug] ie highlights entire map div during shift-zoom ** possibly only when axisLayout is image * geomap - [bug] first use of mouse/touch in any mode moves map by one pixel on mousedown/touch ** possibly only when axisLayout is image * geomap - [bug] iPad 2 measureLength puts current length on second to last coord instead of last coord * geomap - iPad 2 - [bug] pointAlong doesn't take last point into account in all browsers ** cannot reproduce; possibly axisLayout image only * docs - geo - audit in-place geo calls, e.g., fromGeodetic * geo - audit in-place geo calls, e.g., fromGeodetic * geomap - include bboxMax in interactiveTransform engine * docs - geomap - add indexMax property to service object to limit the view.index number so it can be used in template src * geomap - add indexMax property to service object to limit the view.index number so it can be used in template src * geomap - [bug] page scroll effects zoom center on fixed position maps * geomap - clean up touch tracking * geomap - support high-precision mice better in tiled maps * geomap - don't repeat attr text if the same as one previously added * docs - geomap - zoomMin, zoomMax on service object ** determines if service is visible but doesn't change map interaction, only map zoomMax/zoomMin options do that * geomap - zoomMin, zoomMax on service object * geomap - [bug] errors when setting src to empty string ** "When I added services for my graphics layers with src set to an empty string I got very weird results -- I was seeing the single image from my inset map repeated over and over. I had to set it to a function that returns an empty string for it to work." ** possibly an object reference error when multiple maps are created * geomap - [bug] on two-finger scroll on some laptops, scroll zoom doesn't move much at first, then moves too fast * geomap - remove this-style state properties * geomap - add delegate handler for image load instead of one load handler per image * docs - geomap - services option on actual services should return an array of the services in the selector * geomap - services option on actual services should return an array of the services in the selector * geomap - [bug] cannot wheel zoom in dragCircle mode * geomap - users should be able to escape out of dragCircle * geomap - [bug] cannot wheel zoom in dragBbox mode * geomap - users should be able to escape out of dragBbox * geomap - remove "px" from .css calls * geo - use Array.push instead of $.merge where needed * docs - upgrade to jQuery Mobile 1.1.0 * docs - non-mobile version via adaptive check * geomap - [bug] centroid is wrong (for labels?) at high tile levels (19+) ** see MapGeo showtiles switch * geomap - [bug] changing services array (without changing all services) after initialization fails * geomap - if a service is not visible, detach it's container from the DOM * geomap - create _defaultState object, use for widget-local _widgetState property, reinit _widgetState on _createWidget * geographics - draw to img elements to include in interactiveTransform * geographics - better support retna displays ** http://mir.aculo.us/2012/06/26/flowchart-how-to-retinafy-your-website/ * geomap - see what knowledge Gamecore.js has to offer ** http://blog.getplaycraft.com/gamecore-js/ * geomap - maybe throw an error when setting center to an invalid object, such as the first number in a coordinate array: coordinates[ 0 ] <== wrong! ** oddly, iPod Touch 4 (iOS 4) is fine ** might be related to the jQuery UI bug I found * geomap - implement service-level shape redrawing during interactive movement * geomap - use CSS transition or transform for smoother tiling * geomap - don't request tiles that > max possible y for scale * docs - geomap - view.service.row & view.service.column to string multiple services together or repeat horizontal tiles * geomap - Firefox - [bug] inertial pan is choppy post touchstop ** post inertial pan rewrite * geomap - dragCircle must hook into _refreshDrawing so that the circle moves correctly when the user zooms; which means I have to store the center coordinate as well as pixel * geomap - [bug] on that note, I can't zoom in dragCircle mode * docs - better describe append/find connection and how to append data and use the click event to find it later ** see email reply to Marc * docs - geomap - describe "graphic service" as shingled with src set to empty string or null * docs - warn users about potential CSS/JavaScript issues relating to generated elements ** ul, li, div, span, img * geographics - draw all labels to a string or document fragment and append to DOM once * geomap - compile shingled & tiled string src templates for re-use ** be sure their template names are unique so they don't overwrite each other * geomap - don't redraw graphics if the map doesn't move during pan * geomap - replace data-geo attributes with classes * geomap - cache label coordinates (the labelPixel cannot be cached, it will change each refresh) * geomap - rotate label based on segment * geomap - use pointer-events: none where appropriate * docs - geomap - allow template for label argument to append * geomap - allow template for label argument to append * docs - geomap - allow template for properties on style argument to append * geomap - allow template for properties on style argument to append * docs - geomap - shapeLabel property ** template for labels for all shapes added via append * geomap - shapeLabel property * docs - geomap - allow template for properties on shapeStyle option * geomap - allow template for properties on shapeStyle option * geomap - better integrate resize with interactiveTransform * geomap - determine if moz-transform improves speed in Firefox * geomap - [bug] once we detect a pan, disable the ability to go to multitouch * geomap - [bug] verify label clamping is correct in axisLayout=image maps * docs - geomap - pass the service id (if there is one) to the src callback as a view property * geomap - pass the service id (if there is one) to the src callback as a view property * docs - geomap - support dynamic map services that only work in geodetic coordinates (sr=4326)? ** can be done with src function that uses $.geo.toGeodetic? * geomap - support dynamic map services that only work in geodetic coordinates (sr=4326)? * docs - geomap - pan events (pattern after HTML5 drag) ** can cancel with preventDefault * docs - geomap - zoom events (pattern after HTML5 drag) ** can cancel with preventDefault * docs - geomap - support two-finger vertical slide as zoom on mobile devices * geomap - create own .position function b/c $.position is doing too much ** we don't have to worry about border or margin, all elements are within map div * geomap - pan events (pattern after HTML5 drag) * geomap - zoom events (pattern after HTML5 drag) * geomap - test jQuery widget call chaining when setting option values * geomap - when scroll is zoom, attempt to not zoom while user is scrolling the page anyway * docs - geomap - document the correct way to add/change a service after init * geomap - unbind keydown handler on destroy, it's on the document * geomap - use requestAnimationFrame instead of setTimeout when waiting to move the map during intractiveTransform * expose jQuery Geo as an AMD module so asynchronous loaders like RequireJS and curl.js can use it * cdn - test cache headers with http://redbot.org/ before release * docs - $.geo.WKT object * geo - $.geo.WKT object * geomap - panning cursor (closed hand, for when user is actually panning) * geomap - completely original cursor set for pan, zoom, draw, etc. * docs - geomap - replace method * geomap - replace method * geomap - draw shapes to img and integrate with interactiveTransform * docs & examples - settle on the word "option" in all text (instead of property) to match widget function * docs - make all map examples live * docs - explain the 96px scale bar, why 96? * docs - write a full page about GeoJSON and what each object type is to $.geo * docs - geomap - allow name as service object property ** if a service has a name property, it will maintain a hidden input with the given name * docs - geo - support up to GeometryCollection in distance * geo - support up to GeometryCollection in distance * docs - geo - support up to GeometryCollection in contains * geo - support up to GeometryCollection in contains * docs - geo - support up to GeometryCollection in centroid * geo - support up to GeometryCollection in centroid * geomap - show a drawPoint style while the mouse is down, hide if toolPan or dbltap scale * geomap - audit allocations and reduce garbage ** see http://www.scirra.com/blog/76/how-to-write-low-garbage-real-time-javascript * geomap - re-use services that have the same id as existing services * geomap - deep extend existing service objects when services property is set * geomap - cache point bbox if $.geo.proj is not null? * geomap - spatially index shapes when a tilingScheme is in place * geomap - internal - add _getVisibleTiles method and use it in tiled service and shapes spatial index * geomap - remove wheel plugin and use built-in mousewheel event * geomap - test how the comma selector works with the find method * geomap - compile service src templates, refresh when services changes * geomap - audit destroy and memory leaks (jQuery data values, JavaScript object references, etc.) * code - prefer $.data over $.fn.data * docs - internal - explain what projection is and which one we use by default (3395) and maybe why we call it web mercator & why we can't get to +/- 90 lat * docs - internal - document how geomap draws shapes, the geomapgraphics widget and the reason shapeStyle is a method * docs - demo - location based notes/to do list * geomap - find should check labels first * geo - geometry - implement JTS note: "The centroid is equal to the centroid of the set of component Geometries of highest dimension (since the lower-dimension geometries contribute zero "weight" to the centroid)" * geo - all bbox operations should be done in non-geodetic coordinates for accuracy * geo - support bbox in distance ( fix geomap.find ) * geomap - perf test putting all containers that need to move with panning in a single super-container * docs - geomap - multiple labels * geomap - multiple labels * docs/geomap - store WKT input for each service * geographics - rename the generated style properties to something simple or get better control over closure compiler * geomap - document and implement find's callback syntax * geomap - custering demo/support * proj - take scale factor into account when calculating distance in web mercator * geographics - disable fill by setting style.fill to "" & stroke by style.stroke to "" * geographics - See Modernizr for comment on BB Storm & canvas detection * geographics - document graphics widget * geographics - support border, padding, and margin * geographics - undo manual outer div style changes * geomap - store a copy of shapes as WKT in a hidden input * geomap - only update WKT copy if shape is appended with refresh argument set to true * geomap - find - [maybe] after flatten, check more cached bboxes for non-Point geometrie * docs - geomap - support TMS * geomap - support TMS * docs - geomap - toDataURL method * geomap - toDataURL method * docs - geo - $.geo.guessLocation function * geo - $.geo.guessLocation function * docs - services - document the plugin architecture * docs - geomap - drawPush function ** in the drawing modes, this function starts drawing or adds a point into the already-started shape at the given coordinate ** immediately triggers the shape event if mode is drawPoint * geomap - drawPush function * docs - geomap - drawPop function ** in the drawing modes, this function ends drawing or removes a point into the already-started shape at the given coordinate * geomap - drawPop function * docs - geomap - drawStop function ** in the drawing modes, this function ends drawing and triggers the shape event with whatever coordinates have already been added to the shape * geomap - drawStop * geomap - use profiling to improve pan performance * geo - potentially add address cracking ==2012-07-28== ===multitouch status=== Here's some code to render multitouch status to an h1 tag. For future reference/debugging: $("h1").html("multitouch {
            " + "anchorDistance: " + anchorDistance + "
            " + "currentDistance: " + currentDistance + "
            " + "delta: " + ( ( currentDistance - anchorDistance ) / anchorDistance * 5 ) + "
            " + "}" ); Place it in touchmove. ===multitouch refresh=== I'm disabling refresh during multitouch and it makes the whold multitouch experience better, I think. ===zoomMin=== I'm going to fit this in for b1; might as well complete the API. ==2012-07-26== ===mouse=== Peter's mouse can't wheel zoom easilly. It's a high precision mouse and it doesn't click when you scroll it. I have a feeling I'm getting .25 delta and it's rounding down to zero. ===iOS touch=== I have to stop killing the document events on iOS. Phew! I wasn't shutting _inOp off after multitouch ends. ==2012-07-26== ===zoomMax=== Seems to work ok with tiled & shingled. I think I should document and add zoomMin this weekend. ===pixelSizes=== That bug where rendering zoom 0 with string src...this one: * geomap - [bug] tiled services with pixelSizes set do not render zoom level 0, when src is a template string appears to have been fixed with the latest jsRender for me. Here's a jsFiddle to prove it: http://jsfiddle.net/ryanttb/RNrNC/ ==2012-07-25== ===zoomMax=== Only clamp if it's *over* the zoomMax value. ===shapeStyle=== Since I'm not creating geographics widgets (or elements) for layers during startup, the shapeStyle property doesn't work. ==2012-07-24== ===refresh tiles=== I'm going to see if I can set jQuery Geo up to load tiles faster on faster browsers. Depending on how fast the initial refresh runs, I can decrease the timout delay. ===click=== The y value of a clicked coordinate is off a little. I'm creating a jsFiddle to find out what's up. It's not off. Something in their website is messing up my calculations for map point location. ===refresh=== Wow, I didn't notice until now that the new interactiveTransform code wasn't triggering refresh if the user was moving the mouse, even if they weren't actively panning. That's a good one to not have in b1 :) ===zoomMax=== I have too much redundant code calculating/testing agains zoomMax. I need to specify which functions don't test agains it. Likely _getPixelSize should not but _getZoom should. ==2012-07-22== ===force=== There is code from our original implementation to reload tiles. It is no longer being triggered. I'm wondering if I should remove it. There is also code for dirty tiles. They are removed at the end of refresh. I'm not sure I need to keep that code in there because I don't think it's being triggered either. ==2012-07-20== ===jsRender=== There's new syntax for default templating. It uses the {{>var}} syntax. I think the old one is still valid, {{:var}} but the new one is preferred. I will change jQuery Geo to use the new one by default. I should also change the docs. Ah, no, it's new syntax to do HTML encoding. I'll have to check the measure templates but I think I will go with higher performance {{:var}}. ===refresh=== I need to take control of when this is called so I can handle service-level refresh properly. That's better. _refresh will only run on the map itself and calls _refreshShapes on all the service objects. ===interactiveTransform=== I turned the timeout back up to 500. Panning was no longer happy in IE with some shapes to manage. ==2012-07-13== ===interactiveTransform=== A side effect of the way I'm doing interactiveTransform is that changes to the widget options bbox, center, and pixelSize aren't immediately available. I need to at least update the public options during each change. That may be a little expensive because I will have to do projection but is necessary. Ok, I think that's better, except that I forgot the zoom option. Added. ===tile query=== I've decreased the delay to begin checking for new images from 500ms to 256ms. There's a balance here somewhere. ==2012-07-10== ===dragCircle=== Time to move this into _refreshDrawing. But first, I have to trigger the Point shape event. Maybe not. I can't zoom. That's against the docs but I think I can leave it for b2. ==2012-07-07== ===dragCircle=== I'm going to add this to beta. It will work similar to dragBbox, including sending the bbox. ===dragBbox=== I may rename this to dragRectangle before the b1 release to keep the drawing modes more about geometry than geography. ==2012-07-06== ===bboxMax=== A side effect of changing bboxMax is that zoom's value will have to change. This means that changing bboxMax should refresh the map services. There's going to be more to do later when I want to handle changing bboxMax properly at runtime. It should hook into the interactiveTransform engine. For now, though, I'm going to make it work right during init. Heh, bboxMax wasn't doing anything right :) It now sets both centerMax & pixelSizeMax. ===inset=== A new example is up based on AppGeo's MapGeo product's inset map. ===dragBbox=== This needs to finally send a bbox. Also, handle points differently. No more click event but you will get a Point shape event. ==2012-07-05== ===inset shingled map is off=== If I pre-render an inset map and use a shingled service, the extent box is wrong vs. what we see on the map. ===bboxMax=== Initializing this property should set _userGeodetic because sometimes you want to init with bboxMax: [], zoom: 0. ==2012-06-22== ===client work=== I finished the docs last time, then client work stopped me from finishing the code. ===bostock=== In implementing the Bostock demo, I found a bug in jQuery Geo. There's a way around it but it's a little slower. The bug will go away when I fix bbox storage on appended shapes. ==2012-06-07== ===vacation=== I've been away for almost two weeks. Time to finish b1. ===zoomMax=== This is where I left off. I'm also considering zoomMin and zoomMax on service objects but that's not until later if needed. ==2012-05-23== ===tiled=== The new origin stuff appears to work better. I'm going to run through the other examples & see if I'm ready for a build. ===chrome=== Chrome's screen tearing is really bad. I'm going to try to disable 3d transform in Chrome. Maybe it's just my laptop, Chrome is doing the tearing even without translateZ. I'm reverting the changes for that test. ===bbox=== I'm getting a bbox event after a single tap. ===setInteractiveTimemout=== I need to only call this if: a) it's already been called once (to keep it going) & b) we actually change centerInteractive or pixelSizeInteractive. The programatic changes are going to be a part of this, too. I need a way to turn on trigger during setInteractiveTimemout. ===programatic=== I updated all the programatic calls to use the new system with the ability to say not to trigger. I will need to test these but for now, I do think I'm finally ready to merge. ===merge=== I merged the interactive rewrite into b1. There are bugs that I will have to work through before this becomes beta. ===initial zoom=== No matter what your initial zoom is, you can see the map at zoom 0 before the new tiles show up. That makes sense given the changes I've made. ok, the area that handles init options checks to see if the widget has been created before heading into intractiveTransform mode. ===ie8=== I *know* ie8 support is broken. I haven't even tried it yet. We will keep supporting that browser, though. ==2012-05-22== ===mouseup=== I'm ignoring rogue mouseup events now. Hopefully, that will clean resize up a bit on Chrome & Firefox. ===resize=== Seems to work like it did before. I'm going to increase the frequency (decrease the timeout) of the resize check. In the future, I want the resize in two parts, one to move stuff around in real time/animationFrame time, another to perform the final refresh. Maybe move the latter back up to 500ms? Maybe not. 67ms is too soon, Chrome flickers. I'm bumping it back up to 500ms for now. This should really be part of the new interactiveTransform code. At least, moving the images around and waiting for the final setCenterAndZoom. The issue I'm seeing with tiled now is that if I pan and the resize before the new tiles come in, the map jumps from the interactive to the final center. Same with shingled. For now, I think I may be done enough with this to merge back into the main project. That's a lie. I disabled a bunch of stuff before doing this, like marquee zoom. Any of the immediate mode changes. ===immediate=== I'm going to try to tie these into the new interactiveTransform. ===draw=== The last obvious thing broken is moving the draw points during interactiveTransform. shapesContainer is no longer part of panContainer which is now only draw or measure layers. Scratch that, I'm not going to move the original panContainer. I need to include the draw and measure coordinates in the new interactiveTransform stuff as well. That works ok, I think. I might change it later depending on how was shape drawing to img elements goes. I still need to test scale changes with drawing but I have a feeling it's fine. Took the code from pinch zoom. ===tiled=== I forgot, tiled still needs some of the origin fixes I put into shingled. ==2012-05-14== ===mouseup=== Chrome & Firefox trigger a rogue mouseup event when maximizing the window. I don't think that's right but I suppose I have to handle it. But, for some reason, geomap in Firefox doesn't trigger the refresh. ==2012-05-10== ===shingled=== Much better now! Two things I was missing: 1) I needed to base calculation on the original map origin of the scale container & 2) the position is now %-based, like tiled. ===keepAlive=== I don't think there's a need for this any more so I removed it. I had better make sure :) Oh, right. It was for opacity. We don't want to layer semi-transparent images. The code's not here. I see where I set keepAlive but can't find where I delete the images. This may be a regression from, like a2. I probably had it chained to a line I deleted. Oooh, I didn't need it anymore when I added the concept of a pan container way back. Since I no longer have pan containers, I have to add keepAlive back. Yep, I had to add it back with the pan/zoom rewrite. ===resize=== For resize, I should be able to just resize each scale container. Everything else is %-based. ==2012-05-07== ===shapes=== I need to finish the rewrite by making sure graphic overlays move correctly. I might cheap out and hide the graphics for the b1 release. The geographics widget needs its own interactiveTransform method. ===canvas=== Do I need my blit canvas to be part of the document? I hope now, will remove it soon. ===wow=== I was originally moving all the servicesContainer for all services INSIDE the loop where I was moving all services. Also, _$servicesShapesContainer did not include the draw or primary shapes containers. I wonder if that was on purpose. It should not include the draw container because those shapes change during any change in the mouse or map. ===shapesContainers=== shapesContainers will eventually need the transform, but again, maybe not now. For now, I'm hiding the drawn shapes during interactiveTransform. ===jump=== There's still a jumpiness issue when you catch it just before/during refresh. Old tiles that have already been scaled pop into weird locations. Should I fix it now or continue with shapes? Probably, I should finish with shapes and then work on bugs. ===pinch zoom=== Hmm, there are issues here once I turned refresh back on. It's with double click zoom as well, once you start panning. A single hardware pinch zoom appears to work perfectly if you don't pan any time after the zoom. I end up in Africa or the Virgin Island a lot from MA on the iPad. Definitely a problem with refresh. Disabling the refresh timer shows that interactiveTransform still works fine. I'm not doing any pixelSize clamping in _setCenterAndSize. That must have originally been somewhere else. With that change, there is still the jump issue of old transformed tiles but I don't seem to end up in Africa. ===pinch jump=== I need to jump to the closest pixelSize, not the smallest. It will make this smoother...maybe in the future as well as it only affects when they zoom in just shy of the half-level mark. ===shingled=== I'm creating a new shingle for each pan, which is right, but not positioning it correctly after refresh. Actually, this is a much better representation of the jump issue I'm seeing in tiled. If I fix this, I may be able to fix tiled based on it. ===data vs. parseInt=== I'm going to guess that storing a number with $.data is much faster than trying to use parseInt on current CSS values. Although, the parseInt would only happen on refresh, while the .data call will happen with every pixel move. ==2012-05-06== ===shinged=== I have to get this started. Appears to work pretty well. What's left for beta? ===non-moving divs=== I don't think I need the transform on divs that don't move, such as the event target and content frame. I'm removing it for now. ==2012-05-01== ===rewrite=== I turned refresh back on and there's still that image repeating. I'm going to log some stuff and see what I can discover. First step, interactiveTransform is being called on every mouse move even when the mouse isn't down, that has to stop. ===pixel-size=== Wow, I was making a new scale container every time because I had changed to using data-pixel-size but was still testing for data-pixelSize. The duplication is now gone. You can still mess up the view if you start panning right at the right moment, just as it's about to refresh but I can live with that for now. ===shingled=== I suppose shingled is next. ==2012-05-01== ===shingled=== Since tiled is pretty much ready for linking to the true refresh, I can either fix shinged now or actually implement the refresh. I suppose I should try to finish the rest of the geomap widget with tiled for now. It's not fun to be unable to refresh the map in this in-between state. ===refresh=== Tiled services are ready to be merged into refresh. I'm going to skip the _panEnd stuff now and just go to _panFinalize. I can add the inertial pan back later. Calling _setCenterAndSize at the end of my timer now. Pretty fast! I'm getting weird behavior with tiles that aren't in the current view, though. And some, look like they're repeating. It all settles down after the refresh but the quarter second leading up to it there is a visible jump. ==2012-04-27== ===transform=== Setting the transform on the images helped iOS. Settig it on the map div itself helped Android a lot and iOS a little. ===iOS=== If there's anything else over the map, iOS doesn't respond very well. It doesn't let me pan (scrolling the page instead) and pinch zoom is just weird. Out of a whim, I didn't include the jQuery UI style sheet. iOS now works like the others. I wonder what's in the style that it doesn't like. Latest version of jQuery UI (1.8.19) still has the issue. I wonder which widget does it. Weird, if I take out the .button() calls, the demo works on iPad. iOS works fine with fixed position. It's still the .button calls. I'm sniffing out the button calls for iOS 4-5 for now. I don't have time to figure out that issue. ===ie9=== I've been wanting to use better features in ie9 for a while. Let's see how this goes because with the new code, I have to drop the filter. I didn't like using filter anyway. I cannot belive how nicely the transform scale + transform-origin work in ie9! I might investigate using them instead of the % hook on the scale container for webkit & Firefox. ==2012-04-27== ===panzoom=== _inOp gets set to true during pan. When to have the interactive center and pixelSize match the current values? Any function where timeoutInteractive is null, likely. I may have been moving the services' shapesContainers twice, once in _panMove and again in the service's serviceContainer.children().css call. No, the service container is the data-geo-service object. Its only children are scale containers. I'm not going to move the scaleContainers separately during pan...oh, I have to because they will move at different velocities. ===transform=== I'm attempting to add transform support for iOS. 3D CSS transforms make the images bounce around funny during scaling. At least, when I set the CSS on the scaleContainer. ==2012-04-26== ===measure=== In some instances, the measure tool doesn't position properly. Going to change it from a div to a span to calculate width better. The container can stay a div. Only the actual label needs to be inline. Fixed. I'm also clamping to [0, 0] so the measure label doesn't move past the left or top of the map. ===pixel measure=== I can tell I will have to add support for axisLayout=image into the measure code. The clamping is backwards. ===centroid=== On bad polygon geometry (hourglass is the common example), our centroid function returns weird results. I might clamp to the bbox for now as a stopgap until I fix it for real. That's better. Not great but not nearly as much weirdness. ===pan/zoom=== Back to this. I need to disable the pan pop as well as calls to refresh. When panning, we move the _$panContainer. It contains various top-level items (shapes/draw/measure containers). Each service moves their own content. Pan finalize resets the pan container as well as the shapes container for all services. I'm still doing too much in touchmove. Now caching the reference to services shapesContainers. ==2012-04-24== ===pan/zoom=== Where was I? :) Right, first disable all refreshing and attempt a the new interactive pan. Not all refreshing will be disabled, the function/option calls from the developer should be honored. ===zoomTo=== Private but never called? ===no refresh=== With all _setCenterAndZoom calls commented out, the pan container still jumps back to starting position. That's expected with the current code but shouldn't happen when we're done. That jump needs to wait for the full refresh. ==2012-04-20== ===b1 docs=== I got some more docs in. I need to take a small break and actually rework the pan/zoom engine. ===pan/zoom=== So it begins. I think the first thing to do is create the clearable refresh time during pan/zoom and remove the duplicate refresh code in interactivePan & interactiveScale. ===google=== Google Maps requests new tiles during pan when running in Chrome on the desktop, however, the mobile website waits until the user lets go of the map. ==2012-04-12== ===polygonize=== That's what the bbox->polygon function will be called. It's in GEOS. Their docs say: Polygonizes a set of Geometries which contain linework that represents the edges of a planar graph. While that's supposed to be only for linework, e.g., a LineString to Polygon, I think it's fine to extend that to bbox. It's not called polygonize in JTS, there's a Polygonizer class and a getPolygons method. I'll simplify that, too. ===shift=== I changed the shape value to dragBbox so I can use it in the code a little more smoothly (choosing cursors, actually switching the mode). ==2012-04-11== ===foss=== I gave my talk, went ok. Gotta get back to docs. ===dragBbox=== This mode should operate even if pannable is set to false. There's a test in the code where I have to special case that out. ==2012-04-10== ===foss=== I'm coding at foss4g! ===Deferred=== Deferred demo is done. ==2012-03-30== ### markdown The new markdown file looks nice! ### docs Time to document the last feature that are going into b1. Actually, I want to lint the last file, tiled.js. ### Deferred context The last lint issue is that I shouldn't create functions in a loop. That's done when the user returns a Deferred object as the tiled service's src property. The function calls _loadImage on the service object but needs more than the url, which is all the Deferred done call gives it. How do I get the rest, such as $img, pixelSize, etc. $.proxy? But isn't that creating a function anyway, just one that lint can't see? Yes, it does. Maybe I can put the data on the Deferred object itself. I don't see why not. ==2012-03-30== ===grunt=== I haven't written in a while. Checking out grunt now. Wow, that was cool. jQuery Geo now compiles with Grunt and I also have a jQuery plugin package file! ===graphic holes=== With canvas, I have better control of drawing polygons with holes. It's pretty nice. I can't wait to get into WebGL. ==2012-02-15== ===labels=== The code already worked the way I wanted! No .geo-label div is created if you don't at least provide an empty string label. ==2012-02-12== ===find=== Need to implement the * selector. That was easy. $.isPlainObject thankfully returns false on strings. ===unloaded image=== It appears that when you pan starting on an area that has an unloaded image, i.e., empty space, this._center gets set to string values. Checking on this now. ===shingled 0=== To prohibit shingled maps from zooming out past 0, I had to change quite a bit of code. I now have getZoom & getPixelSize methods that will work regardless of tilingScheme. I'm also calculating pixelSizeMax when bboxMax changes and making sure the non-tiled zoom doesn't go less than 0 in two spots. That seems to do the trick. ===service-level shape refresh=== Shapes on services draw twice, heh. That was a tough one. Turns out, when I create the service-level geomap widgets, I wasn't setting _graphicShapes to a new array before passing the (this) object to the widget factory. All services were sharing the same _graphicShapes reference. ==2012-02-11== ===current services=== I need to make sure their style property is always full, that's the point of having an internal copy. This means I have to fill in visibility & opacity when I create the services based on defaults. === service style=== $.extend({ visibility: "visible", opacity: 1 }, style) That returns what you would expect if style is undfined. ===str src=== I can't mod index in the template. I feel that there is a way, but it's not there yet. ==2012-02-06== ===mousewheel=== This needs to be updated, it doesn't work with jQuery 1.7. ==2012-02-04== ===options=== Right, this._options does equal this.options but only because the latter must be called so and we can minify the former for internal use. ==2012-02-03== ===proj=== I seem to be able to detect geodetic coordinates ok. I'm switching all of the $.geo functions to use it. So far, so good. ==2012-02-02== ===transition=== They look cool, but I don't think this project is ready for transitions, they have some unexpected side-effects. I would like to rewrite the interactive portion anyway. ==2012-02-01== ===destroy=== There's a bug with shingled services if I call destroy and try to re-create. ===services=== Changing the services option will destroy all service-level shapes. I'm not sure what to do about that. Eventually, I will re-use serviceContainers (and service-geomaps) based on the new services array coming in but I currently don't do that. ===proj=== Finally, to get rid of proj. The point is, you should be able to use projected coordinates even when $.geo.proj is not null. The same geodetic test applies to both bbox & coords because the first two elements of either are the x and y of some number. Nice! ==2012-01-31== ===shapes zoom=== Service-level shapes don't refresh while zooming and it's not going to be easy at the moment. All I can do is call geomap("refresh") on the serviceContainer which, since they're just service pseduo-map widgets, will only refresh the shapes. The problem is they don't have access to the in-between state of the zoom so the shapes don't draw correctly. I will fix this later when I re-invent the pan/zoom code for beta. For now, service-level shapes will not draw during interactive zoom. However, it's good to have an idea of how the new system will need to work. Each service-map widget will check the _interactiveCenter & _interactivePixelSize values to draw shapes in proper positions. ==2012-01-30== ===geographics=== This widget needs some updates. For now, I'm just going to add the resize function. Note, with canvas, you don't need to set size CSS at all. The canvas is, by default, inline-block with width and height based on the html element attributes. Also, as is shown in this fiddle, changing the runtime width & height properties of the canvas element does clear the canvas: http://jsfiddle.net/jcGY2/ ==2012-01-28== ===service-level shapes=== Where was I before I stopped to add Deferred & fix bugs? Right. The service-level geomap widgets should now initialize their own shapesContainer. ===resize=== resize is a method on the service object because shingled need to stretch the current image. I need to finally add resize to geographics. ===find=== find will have to query and include service level shapes. ===map=== This will be simpler if I allow services to get to the private map variables (similar to how I allow the service object to do it?). No, probably during create. Can you have protected properties in a jQuery UI widget? I would like to be able to pass a reference to the map during create...I could also use .data. That worked fine. I now have this._map which will be the same as this for the map object and a reference to the map object for services. Nice! On parts that need to work the same between maps and services, (such as _refreshShapes), I can just call this._map.x and it will be correct. ===shapeStyle=== This should be fine for services. ==2012-01-27== ===Deferred=== The src function will be allowed to return a Deferred (or Promise) object. If it does, geomap will wait for the done or fail events. The src function will call resolve or fail. ===service shapes=== The opacity method might have to stay as a service method because it must directly manipulate image elements in some cases. However, the toggle method can operate on the new service container. ===init services=== So, the jQuery UI widget factory udpates non-array options fine, i.e., when I get into the _create method, this.options has whatever the user supplied merged in with the default options. However, array options are not copied so any changes to the initial service option are not maintained. Not true, but it does unfortunately merge the first user supplied service with the default service, osm. ===options=== I forget why I have _options and options. They are supposed to be internal vs exteternal but they are equal references. ==2012-01-24== ===a4=== What's next for a4? static mode. ===static mode=== This shouldn't be too hard. Currently, any non-defined mode string will act close to static. That's different from how I want it to work. The mode "static" should be static and undefined modes should act like pan for now. The switch appears to have gone well. I can set the mode to "23" and it acts like it's in pan. That's a feature I will define more fully later and document before it's official. ===labels=== Time to merge labels into geographics. This is a huge step toward service-level shapes. I should be able to find all $labelsContainer references and move them into sections of geographics. Now that labelsContainer is part of shapesContainer, the next step is to put shapesContainer under a serviceContainer (which is inside servicesContainer). Got that? ===service-level shapes=== Here we go! Each serviceContainer has a div that contains all the images. The geographics widget will be a sibling of that. I may need a new container :/ the extra div was the tiled service's scale container. I need a container for the service/graphics elements. The map itself will have to manage this new container. I think the internal service objects will get this container and now append their functionality and elements to it. It will no longer have to return a new div for which the map will create a sub-geomap. ==2012-01-23== ===addressing=== I think address parsing (cracking) will be a useful feature for geocoding to non-Google geocoders. I might want to add that to $.geo at some point. Christian has some Python code that does it already I can port. ==2012-01-21== ===pinch aftermath=== Adding pinch was pretty easy. The only big issue was if a second finger touched a short time after the first. To counter, I fake as if all touch has stopped and initiate a new one. There's room to consolidate code here but I'll get to that later. ===drawPoint=== This acted funny with pinch zoom in that when the second finger hit late, a shape event got triggered at the first finger. ===draw other=== Similar issue, touchstop gets triggered after pinch zoom and a segment is added to the shape. Maybe related to calling touchstop. We get in an odd state, actually. The segment shows up but the next touch causes it to disappear and a new one appear instead. I'm going to put this as a bug and get back to it later. There's much more actual functionality to get into alpha 4. ==2012-01-20== ===pinch=== This is mostly ready for iOS. It's a little jumpy so I think I have to detect a second touch while the first one is down as long as they haven't started panning yet and move into pinch zoom. If the second finger is late, we still only get the touchmove event which will work great. ===android=== I am going to coin "hold scroll" for android to counter their lack of multitouch. When the user holds the map in the same place for between .5 seconds and before the browser takes over, the user can move the touch point vertically to start zooming as if there's a scroll wheel. I was going to have "expand zoom" (coined by Laura) where it works similar to "hold scroll" but instead of acting like a scroll wheel, it acted like the bbox was expanding from the hold position. In effect, a zoom in only fake pinch zoom. However, I like the zoom in/out ability of the fake wheel better. This will also work on iOS, I think and even desktop. ===web workers=== I eventually want the $.geo functions to allow the browser to use web workers but they'll have to be in a javascript file. Hopefully, I can use data URIs. I could always grab the worker js from the CDN but that would require internet access. What if it's all an internal site, like for government. Or, graphics only that doesn't need servers. I can use data URIs but I wasn't able to have a local variable in the function. You can, but you need all %20's instead of spaces. ==2012-01-17== ===geomapshape=== May be getting multiple shape events when in drawPoint mode and attached via bind("geomapshape"). Not just shape, all events. If you recreate a map on the same div & rebind an event to a new function, it will trigger more than once. ===wkt=== While not in this release, I have a need to fix WKT parsing. Finished parse LineString & (single ring) Polygons. ===pinch=== Next on the list is pinch zoom. I can hook this into the scroll zoom mechanics based on pinch center & ratio of initial pinch bbox to current pinch bbox to scale the tiles. Initially, I'm going to jump one scale level (or scale ratio) like wheel zoom. Later, when I update the whole interactive movement engine, I'm going to transition to the next scale level. This will tap into the _wheelLevel variable, which I should possibly rename later. Dropping out of multitouch (lifting one finger) will end interactive zoom & call setCenterAndZoom. We pick the largest ratio between x & y changes. ==2012-01-16== ===zoom=== Accidentally moved some code to where it didn't belong & broke interactive zoom. Fixed. ==2012-01-12== ===getUrl=== I would like to further have the service object's properties match html rather than css. I might rename this to just src. ==2012-01-11== ===scroll & drag=== I need options to disable the default behavior of scrolling and dragging. ===html attr=== I think my options should reflect more like HTMl attributes than css properties. Including service object options. That might make me change visibility back to visible :( At least I'm not beta yet. Scratch that, it's a presentation option and all presentation options should follow CSS. However, I may move it to a style property of the service object. Are there other style properties? Only opacity. ===scroll=== I would like to support two-finger vertical slide as zoom on mobile devices but I'm not ready to write that up yet. Hmm. Can I handle scroll without an option? I can detect page scrolling and set a timeout. If the user has been scrolling the page, we don't want to scroll the map. But, what if the user's cursor just happens to be on the map when they want to scroll the page. I'm keeping scroll, the developer should have control to turn it off all together. ==2012-01-2== ===service=== I'm still thinking about service-level methods. I'm not going to add the *All methods right now and I'm not going to have the single methods dive into the services (other than find, which even in jQuery digs into sub-elements not in your collection). The table I wrote below won't go into the docs. Almost done with the docs for this. I wonder if I can have the jQuery UI widget method find merge results when more than one element are used in the selector. Unlikely but it would be cool. I'm going to have to assume not for now but keep that in mind. ===geo-service=== I am going to document that all service divs have the geo-service class. So, the default service will be both .osm and .geo-service. ===find=== It's quite clear to me that I should be able to call find on services. That will return shapes in that service. What does calling find on the map do? Should I have it search map and all services as planned or limit it to just map shapes? I have no idea what this would do in jQuery UI widget factory: var shapes = $( "#map,#map .osm" ).geomap( "find", { type: "Point", coordinates: [ -71, 42 ] }, 4 ); What will be called, what's the return...just the first? Just the last? For this version, I'm going to have find on the map only return shapes appended to the map. That will match how the other functions work and document that you cannot use the comma selector with the find method. ===proj=== I need to get the final doc changes in for the $.geo.proj auto-handling. The definition of "map coordinates" is determined by the last use of center or bbox. The "map coordinates" are used as return values for the center, bbox, and the bbox property of the view object passed to getUrl. Now, how to write that... ===replace=== Removing the rather extraneous label and style methods from my to do list and adding the much more useful replace method. replace( existingShape, existingShape, style, label ) is the same as append( existingShape, style, label ) but that's fine. If you want to remove existingShape and add a new one, you won't need two calls (remove & append). ===find=== I'm not going to add a shapes method either. I want that to be part of find. The next version of the find method should take various selector strings such as * and return an array of shapes. This also makes me want to revisit whether or not find can dig into services...I'll see what Peter thinks. I feel like I want users to be able to write either: $("#map .osm").geomap("find", "*") or $("#map").geomap("find", ".osm *") append, replace and empty are very one-item specific but find is a digging query operation. I think I just convinced myself that it should be different. It should dig into the services. That's what I think devs will expect. I already can't use find with more than one target...so I'm already breaking the convention of the other three methods. I'm not going to support the service selector in find's selector argument at this point. But I documented how it will work with a service element selector and that seems pretty cool. ==2012-01-01== ===offline=== Responded to an email asking about offline support. I wrote a few things in my reply that should give him some ideas. I'll copy them here: I have thought of offline support. While something like that likely won't be directly part of jQuery Geo itself, there are different ways to approach it depending on needs. I have plans to put up some demos to give developers ideas but here's a short list: 1. Using the getUrl function to cache downloaded tiles in session storage on IndexDB. Since this function in the service object can do anything you want, it's perfectly fine to check some HTML5 storage options for tiles and returning, e.g., a data URI before attempting to access the Internet. Users will get roaming charges only when the images aren't in the cache. However, the amount of images you can store in the cache is limited by what the browser sets for the cache's upper limit. Some mobile browsers allow users to increase this limit, others don't. This is an option better suited for sites that want to show large areas with many zoom levels. 2. Pre-caching the whole tile set in HTML5's appcache. This is suited for a site that only serves a small area and not too many zoom levels. You would have to get a copy of all the tiles and list them in a cache manifest file. If the user zooms or pans outside the site's area, they can get some "no tile" image. The huge advantage is that users can first browse to the site on WiFi, the app will cache the entire map (which will take a while) but can then walk around and map tiles will instantly come from the local cache. The disadvantage is that HTML5 appcache is usually only 5MB which won't hold too many tiles. ===remove=== I'm still trying to decide about whether or not remove should remove all references in all services or whether I need removeAll. There is precedent for xAll methods in jQuery. I will also need empty. This is too much for a4. Maybe beta or beyond. method | map or service | function ========================================================================== append( shape ) | map | appends shapes | | only to the map append( shape ) | service | appends shapes | | only to the specific service find( Point, radius ) | map | finds shapes appended | | only to the map find( Point, radius ) | service | finds shapes appended | | only to the specific service findAll( Point, radius ) | map | finds shapes appended | | to the map or any service, | | will not return duplicates remove( shape ) | map | removes shapes appended | | only to the map remove( shape ) | service | removes shapes appended | | only to the specific service removeAll( shape ) | map | removes shapes appended | | to the map or any service, | | will remove all duplicates ==2011-12-22== ===buffer=== I'm going to implement buffer as an internal geo method for now & document it later. It's needed. ==2011-12-21== ===two finger=== So, Google has settled on two finger single tap for zoom out. Fine. ==2011-12-09== ===measure=== Previous measure shows up if you destroy & create map after originally double clicking to end a measure. In destroy, _drawCoords and _drawPixels are both empty. Where's the data come from? When back into the new control, _drawPixels has values. There isn't a _drawCoords. Ah, widget factory was using old data, I have to make sure everything is cleared during create, including these two arrays. ===measure-pan=== Problem when you pan the first time while drawing in axisLayout image. It's not just axisLayout image. It's also not measure, it's drawPolygon as well. Ok, this is new ;) I works fine in a3. Maybe something with the implementation of axisLayout. Doh! Another "don't set arrays equal to each other" issue. Does this happen to other devs? ==2011-12-08== ===semver=== All that chatter about what version naming to use and then the jQuery blog points to this: http://semver.org/ Also, here's the deal about the new plugins site: http://blog.jquery.com/2011/12/08/what-is-happening-to-the-jquery-plugins-site/ ==2011-12-05== ===measure area=== I have to work on the measure area tool. Something's not quite right...oh yeah, I haven't implemented it yet. ===length=== measureDistance should be measureLength. The measureLabels object should have a length property. ==2011-12-01== ===getUrl=== I was going to bring our urlFormat property over from the old code but now I think I want it to be the same property on the service object. I think getUrl can be a function, but can *also* be a string for shorthand. This will obviously be a jsrender template string. ==2011-11-30== ===twheat=== I'm going to keep the twitter-heat demo and also leave twheat as its own app. ===service-level=== Finally writing some service-level shape docs for 1.0a4. ===wheel=== I would like to add a wheel option. We have a wheelMode property on the internal control that can be a few different things. I would like this to be simpler. Maybe just "wheel" and have it be "on" or "off". Or a boolean? But a boolean would limit future additions. ==2011-11-23== ===measure=== I'm going to port measure over as pretty much how it's done in our original project, in that it will have its own dedicated label. ===measure-label=== Trying to make the measure label look nicer than before. I'm adding a style to the document head just for the measure tool. I'm prepending it so designers can override any of the properties. ===jsrender=== Pulling in jsrender for the measure label. I'm going to have to do it anyway for shapeLabel, may as well do it now. Works well for my needs, I'm going to document the measureLabels option. ==2011-11-22== ===jQuery 1.7.1=== I'm still using 1.6.4 and will likely release that way. I'll have to test with 1.7. The notes say that .1 fixed a bug in mousewheel event. I didn't even know they had a mousewheel event. Maybe I can stop using the wheel plugin I've been using. ===label-container=== Judging from the layout below, I'm going to change textContainer to .geo-label-container and have it move around exactly like the shapesContainer. More like serviceContainer because it doesn't need to be the size of the frame. #map .geo-map .geo-event-target.geo-content-frame .geo-services-container .geo-service* .geo-shapes-container canvas .geo-labels-container .geo-label* .geo-draw-container canvas .geo-measure-container .geo-measure-label.geo-label ===refresh polygon=== I'm still curious why I don't use toPixel on Polygon shapes as a whole? Why the loops? Right, I was thinking toGeodetic. geomap's toPixel function only takes up to two dimensional arrays. Updated both functions. ===pan=== I need to pan both shapes and labels at the same time. I think I need a new container for these because drawing might be part of this as well. ===length & area=== Documenting and coding these because I'll need them for the measure tools. ===LineString middle=== There must be something in JTS that's similar to Esri's ILine.QueryPoint function but I can't find it. This is for getting the point along the line for the label. I want to add a generic function to $.geo. Ah, LineSegment.pointAlong. Documenting pointAlong. Also implementing it! Works pretty well. ===line rotate=== I would like to rotate the line label based on the current segment but that will have to wait. ===geographics=== I'm going to merge labeling into geographics so that I can move the tech as a whole to indivdual services. That'll come later when I need to do service-level shapes. ==2011-11-21== ===measure=== I started porting measureDistance today but merged the branch in after being able to draw a line. The rest of it depends on being able to draw labels. Our internal library has _labelShape specifically for measuring but I'm going to merge that into the labeling engine for this release. ===append=== I need to update the append docs to include label before I do anything. Done. Since it's needed right away, I'm going to start porting labels over. ===shapesContainer=== Can I re-use $shapesContainer for labels? I'd rather not keep track of a second div. However, I think $shapesContainer *is* a canvas element so that's not going to work. Yeah, it's a geographics widget which...no, geographics appends the canvas. I can re-use that element...but semantically, it isn't correct. That won't work anyway, I need these to exist at the service div level so they can be targeted by CSS. However, labels not associated with a service would not be in a service div and would need their own div. ===layout=== Currently, the layout is, e.g.: #map .geo-map .geo-event-target .geo-services-container .geo-service .geo-shapes-container canvas .geo-draw-container canvas ($textContainer) ==2011-11-15== ===twheat=== I'm going to make this a real app with its own subdomain. I would like to use paging because the first page doesn't have enough results with a geo argument. What happens when there's no further pages. Is there a "next_page" property? Is is null? The page will be more impressive if I try to geocode the location property to get more results. Heh, this will blast a lot of queries at MapQuest. I'm going to have to store ids i've already processed. That's soo much nicer! Maybe I can get a couple old pages worth as well on the first search. Twheat exists! ==2011-11-14== ===a4=== Time to start a4 docs. Hopefully this will be the last alpha. ==2011-11-10== ===merge=== I merged in the changes to support photos. It amounts to only a few hundred bytes minified and can be pretty useful. I couldn't find a good example service to use for the axisLayout demo. ==2011-11-09== ===axisLayout=== Peter likes axisLayout as well...sold! ===first=== Trying this out for the first time. I can get image tiles from an image server but the zoom is all wrong and it's not centered. wheel zoom is also pretty wrong. ===bbox=== bbox min values are negative. I suppose that makes sense because it's trying to put the top-left corner of the image in the center of the window. It should be tring to put the center of the image in the center of the window. ===mapbox=== MapBox uses an "official" tiling spec. In that spec the origin is in the bottom left. That doesn't mean the y-axis is flipped though but it does change how I calculate the tiling scheme. Maybe it does go up. That's awful, why would they do it different than web mercator? Crisis averted, maybe? It looks like V2 of the MapBox API uses top-left origin and XYZ tiling: http://mapbox.com/hosting/api/ Maybe not averted? Calvin is saying that TileStream itself (as in not hosted by MapBox) only has one API. That doesn't sound right. ===getTiledZoom=== This is wrong for image types the way we want to understand pixelSize with images. A low zoom means a low pixelSize which is opposite of maps. I seem to have fixed that. I'm getting closer. ===refresh=== Refresh is ignoring tiles on the bottom & right edge of the viewport. ===top-left=== The image still starts out in the middle of the page but you can move it around and zoom. ===getUrl=== I forgot that while Peter's image server determines zoom levels backwards, I was going to handle that in the getUrl function of the service and have the pixelSizes of the tilingScheme be like normal. This works much better. Now I only have the top-left issue. That's not true, zooming bounces the new image to somewhere else, i.e., isn't smooth or correct. ===center==== So, I realized that at geomap zoom level 0, the image is way zoomed out and my center should be the center of the full image in pixels, so pixel width /2, etc. I changed that but my tiles are still misaligned. Ha! I wasn't checking for undefined if you pass a zoom of 0. That means I wasn't setting the new center & pixelSize with updated values. All set. Now I'm only offset in the y location and I have a feeling that's because of the axisLayout. ===osm=== Somehow, the osm class i getting on the serviceContainer element even though I'm completely redoing the services array at init. ===centerMax=== I think for now I have to assume that at max zoom, the whole service fits in a tile and the center is in the center of the tile. I don't have a way yet to specify the center of a tiling scheme, only the top-left. ===pan=== Pan is backwards as well when it creates the new bbox. Fixed pan. ===zoom=== Looking good! interactiveScale is last. Then maybe I should support shingled. Wait, no, that was interactivePan, when pulling in new tiles. Zooming twice is a bug but that's in core jQuery Geo, not this image addition. ===shingled=== Here's a link to a sample shingled image: http://lib.byu.edu/mrsid/bin/image_jpeg.pl?client=sample&image=sample.sid&x=1024&y=2048&level=0&width=1024&height=480 Actually, there are levels so that's a tiled image. Yeah, definitely tiled because the level argument doesn't allow fractional numbers. ===ie select=== I think I forgot a userselect somewhere because if there are no inputs on the page and you pan, IE highlights everything in blue. Every map tile. Adding any input or link to the page fixes this. Also, adding this to inside the map div seems to fix it too: That fixed nothing. The issue isn't with panning, it's with shift-zoom and happens no matter what's on the page with IE9. ==2011-11-08== ===image coords=== I need a new property to determine the direction of the y-axis but I want it to be more generic. The difference is a different coordinate system, the side effect is the inverted ordinate axis. Maybe just "coordinateSystem". I don't want to confuse users with the difference between coordinateSystem and tilingScheme though. The full, proper term would be coordinateSystemAxisDirection or coordinateSystemAxisType. There seems to be a little precedence for CoordinateSystemAxis, found in GeoTools: http://docs.geotools.org/stable/javadocs/org/opengis/referencing/cs/CoordinateSystemAxis.html Nothing in JTS. Hmm, axisLayout? Why not, it's short and specific. axisLayout = "map" | "image". Yes. I like it. ==2011-11-07== ===gzip=== I added gzip to jquerygeo.com & all subdomains. jQuery Geo (minified & gzipped) is now 17k and falling! ===move=== I don't like that mouse move events seem laggy with this release. I need to find out what's different. I thought it was that I'm sending move events even while drawing that removing that hasn't helped. ===drawing=== Wow, geomap._refreshDrawing was terrible and geographics._drawLines needed a little tweaking. ===return false=== I didn't have any return falses at the end of my event handlers. I hope that plus the drawing fix makes panning better. Oops, I went too crazy and added too many and wasn't letting the browser grab events it needed. Chrome's type=number input went crazy up or down if you didn't move the mouse away. ===chrome=== I've done what I can. The issue appears to be with Chrome or something I'm doing with Chrome. Drawing and panning speed is tremendous in IE9 and Firefox 7. ===geolocation=== Wow, after any timeout, Firefox stops checking for watchPosition? Is that part of the spec? Nope, not part of the spec. Oh, it *is* part of the spec if it fails due to timeout. It does sound like it's not supposed to trigger until the position changes despite what you put in maximumAge. ==2011-11-01== ===shapeStyle=== Time to redo the shapeStyle example in a much more awesome way. Did I miss something? jQuery UI widget factory isn't complaining that shapeStyle isn't an option on the widget even though I haven't added it yet. New demo is super-cool! ===refreshShapes=== I almost had this function clear the shapes geographics until I realized that it's recursive if there's a GeometryCollection. Can't do that. ==2011-11-01== ===refresh=== Cleaned up the wording for append, remove & empty. Also, going to have append allow style only, refresh only, or both. ===refreshShapes=== Due to performance, I'm going to disable the auto refresh after interactiveScale of shapes if the number of shapes is over a certain limit, say, 255. ==2011-10-31== ===tile paint=== Another app I want will be tilepaint.jquerygeo.com. It won't actually use jQuery Geo but will repaint tiles on the fly for you based in an input URL and color changes. ===fromGeodeticPos=== There's a bug trying to convert some positions of a town near Concord in the voting demo. I wonder what's different about that geometry. The shape is a multipolygon which I am not handling properly. It can be a quadArray. I also removed all the $.each calls which should speed things up a bit. All set now. ===ArcGIS Wrapper=== agw.jquerygeo.com will take an ArcGIS Server endpoint and spit out the jQueryGeo you need to initialize a map to that service. It should handle both cached and dynamic services. ==2011-10-30== ===voting=== I'm working with Calvin Metcalf at MassDOT attempting to push all the data into jQuery Geo. I might want an option to turn off scaling vector data because it's rather slow. Maybe only do it if they have WebGL. Disabled it for now. ===refresh=== The refersh property must be made public, pushing large number of features isn't useful without out. ==2011-10-29== ===id/class=== I'm at WhereCamp Boston 2011 and going to try to finish Alpha 3 while I'm here starting with making id optional. ===initOptions=== Was getting undefined when a user passed nothing as in the simplest test. ===class=== So, I forgot that class is a reserved word. I'm not sure what to do about that. I can make id optional for now but I'll have to decide about class as a property name. I know as an object literal, I'm supposed to enclose the word in quotes but that's not going to look right for the user who wants to use this. I might have to call it cssClass or something. I'll find out what jQuery uses. Google Closure won't even minify the build with the word class used as I'm using it. When I'm creating an element using jQuery's argument that takes an object for attributes, what do they use? They require quotes. ===id=== I'm still storing the service state by id. Since both id and class are optional, I think I need to store it as an array. That's not true, I can store an id on the service object via $.data. The id can be $.now. I wonder if $.now actually has different values if I'm creating more than on service at the same time? I will need to test and potentially use a different means to create the id. ===service create=== I'm going to assume that the service doesn't already exist during create. Not sure if that's a good idea though. Maybe for now, I won't and I can make the create code smaller later after I have time to test. I completely forgot that I'm going to store the entire service state via $.data. That will make things a lot easier. Seems to work ok. ===double click on unloaded=== When a singled image hasn't loaded after pan and you double click on empty space, the zoomed area seems wrong. ===fusion=== Andres from Google is showing radius query using fusion tables. Seems like something I can do with jQuery Geo. ===kml=== I might have to support kml. ===maps.jquerygeo.com=== I should support typing a url to a geojson file to append all of the json. ==2011-10-28== ===style=== Both shapeStyle and drawStyle get and set a plain JavaScript object and should be widget "option"s. While changing them does have side effects, they perform no action themsevles. ===centroid=== I'm leaving centroid in a3 but removing support for GeometryCollection for now (in the docs & code). That can come later. ===distance=== No sense having the two lines that support arrays, they'll never hit a valid switch case and it's not in the docs. ==2011-10-25== ===service state=== I finally moved it to a $.data store on the services container. It was getting messed up moving between pages in jQuery Mobile when one of the pages had a map. ==2011-10-21== ===resize=== Shingled maps don't resize properly. I think I have to have a resize method in there & call it from geomap. All set, I had to mark the current scaleContainer as not being for the given scale any longer and re-center it. ===visible=== I can't decide about this property of the service object. I need an API audit from Bocoup :( Since I have opacity and visibility in shapeStyle, and I know I'm not going to change them, I think I do want to have the naming synergy because I do have opacity in service properties that I'm not going to change. Ugh, but the toggle method takes a true or false value. But so does jQuery's and that changes a CSS property from one text string to another. ===change service object=== Unlike the shape objects, I think it's fine if I change the service object's visibility property. It's sort of awful to see the check for undefined & I change it anyway when they use the toggle method. Why not just set it to "visible" when I create the service? ==2011-10-15== ===draw pan=== The current version didn't get the code ported over that disables inertia while drawing. I think I need to put that in because without it, the drawing does feel too fidgety. I was calling _panEnd instead of _panFinalize for the draw modes. ===draw polygon=== Finally ported this code over. Seems ok. ==2011-10-14== ===maps=== I would like to make an app that lives at maps.jquerygeo.com and has some useful functionality similar to Google maps but uses all open data. ==2011-10-12== ===push it=== jQuery Geo is still functional in Chrome drawing all of the census tracts of MA. That's over 55,000 points and 3,000 features. Not too bad. ==2011-10-07== ===drawLineString=== I've ported some initial line code and actually made it much more elegant than our internal one. ===shingled=== The shingled demo needs some work. ==2011-10-06== ===bbox=== I pushed out a great new bbox example page. It links to a live jsFiddle even so people can play with the code. ===jQM buttons=== I did have to make the full screen map an external page. It worked ok after that and the back button still works. ===jQM=== jQM has virtual buttons to handle either touch or mouse input (some devices have both at the same time): vclick, vdown, vmove & vup. However, they don't handle multi-touch so I think I'm going to have to stick with what I have at the moment. I can't require jQM just to have jQG work on mobile. ===draw=== Porting our shape drawing code over finally. We're getting a new geographics widget to differentiate drawing from appended shapes. ===drawStyle=== I forgot to write about the drawStyle method. This one might actually be a true option as it will never be service-specific. It can only apply to the map widget. ===draw functions=== I need to rename some things. I've been using a few old names from our internal code but they don't quite make sense with some of the newer names of public properties. Mostly, shape should mean anything added via append and draw is the actual in-process drawing. Two internal method names should be: _refreshShapes (instead of _drawGraphics) & _refreshDrawing (instead of _redrawShape) ===drawPoint dblclick=== As the docs say, a double tap will zoom in just like in pan mode and not trigger the shape event. ===geographics=== Oops, my underlying geographics widget is sharing the same canvas context. Flicker city! Ah, much better. ===drawPoint=== Because I'm delaying before I trigger the shape event, it feels slugish. Maybe I can drop the delay down to 100ms. Too fast, I'm getting the shape event. ==2011-10-04== ===jqcon=== I gave a presentation to jQuery Conference Boston 2011. I didn't have much time because I was sharing a block with another speaker. So, my presentation was rushed but I still think a few people interested. I will have to get better at conveying that this is not a wrapper for Google Maps or OpenLayers. We do not host any 3rd party controls. ===jQM buttons=== With a jQuery Mobile controlgroup or navbar on the same page as a full screen map, I get huge performance issues on Android. iOS seems ok with it. Desktop browsers are fine. The map doesn't pan while sliding your finger but it does show up in the new location when you let go. Removing the navbar completely didn't help. I think that unless it's a small in-page map, I'm going to have to make the page external. ===bbox=== To test these new bbox functions, I'm going to redo the bbox example page. ==2011-09-30== ===json=== I can store a tiling scheme in JSON but just realized that I can't store a service definition in JSON because of the getUrl function property. ==2011-09-29== ===zoom=== Documenting and adding the zoom method. ===bbox=== Made bbox public. It's also now storing projected coordinates. $.geo.proj can also accept bbox arguments now. ==2011-09-28== ===disable auto-proj=== Peter suggested (for actual GIS users) a way to disable $.geo.proj but keep the object where it is. The situation is: "I know I'm working in a projection, and I want $.geo.proj to match that projection, but I don't want it to attempt to auto-project coordinates I pass to $.geo functions or geomap because I'm going to send it projected coordinates, but I do want the object around for when I might want to un-project some coordinates to geodetic." That's wordy but it does make sense. However, instead of adding a boolean on $.geo called autoproject and telling people that they can shut it off, I'm going to test diving into arguments to determine if they are geodetic and auto-projecting myself. There will be a performance hit but I need to test if it's too much or worth the simplicity. I think I'm going to find that it's worth the simplicity. I can then remove A LOT of words from the docs about if $.geo.proj is null, blah, blah. That's fine for input values, but what about auto-unprojecting output values? Maybe I do need that boolean property on $.geo? Or I can store the last way center, bbox, or bboxMax were set and return values in the same format. I would rather it not be that tricky though. If I do add a property, it would only need to be for geomap. The $.geo functions are stateless. ===wkt=== Working on WKT.stringify/parse. There will be a $.geo.WKT object. Moving along, made the frame of a nice test page too. ===destroy memory=== A destroyed geomap remembers what was in _graphicShapes. This means that any other private property initialized with _prop: default, is remembered. There could be other issues...until I replace all indivdual properties with a single state objects. For now, I'm going to reset _graphicShapes to [] in createWidget. ==2011-09-27== ===destroy=== Somethings wrong with destroy, can't create after. One thing missing is that resize is called (by jQuery Mobile?) after the call to destroy which causes a script error. I have to make sure I unbind resize. Huh, I've never had to unbind a handler before. Heh, destroy erases any content you had inside the widget before you created a geomap. ==2011-09-26== ===refactor=== Found bugs in serviceType.destroy and graphics due to code refactor. The CDN, while wonderful, takes too long to update. I suppose it's not the best idea to put the test branch on the CDN. Done. I'll still occasionally copy test to the CDN but mostly I'm going to update the non-CDN'd version until I know things are ok. Alpha 3 docs online & tweeted about! ==2011-09-24== ===resize=== My code refactoring broke auto-resize. I wonder what else I broke :) ==2011-09-23== ===filename=== I renamed the compiled JS files to match what code.jquery.com has for jQuery itself and jQM. jQUI isn't on there, which is odd. ===widget factory syntax hack=== Testing if the syntax I want is possible with the jQuery UI widget factory pattern. I only want the one widget, but I want to be able to call some functions on other child elements. I already hit a snag. Calling .geomap("toggle") on an element that has not been initialized as a geomap widget doesn't trigger _createWidget, _create or toggle. ===serviceTyep files=== I'm going to split out the service type objects into their own files. That'll help me make sense of the geomap.js file. To do that, I had to move _serviceTypes from being an option of geomap to a propery on $.geo itself. This will help third-party service type plugins down the road. ===widget vars=== I think I have to move all the widget vars back into the object passed to $.widget so that they don't conflict with each other, e.g., multiple geomap widgets. As they are now, I think they're all plugin-level widgets. ===sub-widgets=== This is awesome. It looks like I can get the syntax I want. Now to figure out the best way to call the method in the parent geomap widget from a service widget. It seems like the vars created in the closure supplied to $.widget are still used by all widgets on the page. Do I really have to store state in a data object on the element? Yes, they are shared. Yes, I will have to figure something out. I just had to plaster my code with this's. I don't like it but it now supports the toggle/opacity syntax I want and *I think* also supports multiple maps on the same page (I think). That's going to increase my minified size quite a bit. I'm going to have to go back and see what I can do to clean it up but I'm choosing proper functionality over code size for the moment. ==2011-09-21== ===docs=== I'm trying to clean up the docs and change notational $.geo to jQuery Geo, but not mess up anywhere I mean to reference $.geo the namespace. ===class=== I have a better plan for service id. I'm going to keep my plan for having the presense of a name property create a hidden input but I'm going to allow the service object to have a class. The class will be applied directly to the built-in service divs. I will still apply data-service-type="tiled" or data-service-type="shingled" to the divs. To apply certain methods to specific services, you will now target the service class under the map element: $("#map .osm").geomap("toggle", false); // this will hide OSM. ===service create=== I'm going to require that the service type's create function return a jQuery collection of one item that is addressable for that service. It doesn't really HAVE to have anything in it but I'm going to store service state on it using $.data($el, "geoServiceState", {}) or something. ===jqm=== Upgraded to jQuery Mobile b3 & added some color to the headers of various doc pages. ===service id=== After talking to Peter, I'm going to allow class and id with a note that if you use id, you'll have to be careful of adding more than one map on the page. I like this plan. Also, if you do it by id, you can target it directly: $("#mass-gis").geomap("toggle"); ===widget tricks=== I'm not sure I can do the selector tricks I want with the widget factory. I may have to change my docs & design if I can't do it elegantly :( ==2011-09-20== ===cache=== I may be caching too aggressively. I think I should remove caching from $.geo.bbox and instead cache inside of append and clear the bbox cache in remove. I really only need it in the find method. ===jquerygeo.com=== It's time this project got its own nice site. Also, (mt) is faster than my previous host from places farther away than MA. ==2011-09-18== ===shape=== Working on the event docs. ===name=== I was originally going to rename id in the service objects to name so I could use it as an input name on a hidden input. However, I'm now going to require id but allow name as an optional property. If present, it will create the hidden input. This is now a future task and will not be in alpha. ===append=== While adding the refresh argument to append, I started thinking again how I want to implement service-level graphics. It would be very nice if I could have the map>service syntax to jQuery and call append, remove and empty on that. I think I defined the syntax a while ago...yeah, see "On shape functions" from 2011-06-02. The issue I have is that a page can have two maps. The default service has id=OSM. So, if I allowed $("#map #OSM") syntax, it would cause the page to have two elements with the same id, #OSM. However, $("#map [data-geo-service='OSM']") is way to wordy. I'll have to discuss this with others later as this is not an alpha feature either. ==2011-09-16== ===foss4g=== FOSS4G is an inspiring conference. I gave my talk and people seemed interested. There was a question about Google. I answered that it's illegal to use them and Chris Schmidt mentioned on Twitter that it's not illegal, it's just hard. We're talking different things. jQuery Geo would use Google tiles directly, which is against license. We will never host a third party widget inside the jQuery Geo div as part of the core functionality. OpenLayers wraps the official Google widget to get around the license restriction (since it's the official Google widget, there's nothing wrong with it) & keeps it up to date (or slides it around) when the user interacts with the OL map. I might do something similar as a blog post when I open up the service types plugin system but until then, but it won't be part of jQuery Geo..."here's how to do it if you want", type of thing. The developer would have to pull in the Google maps API themselves. ===centroid=== I'll have to see if JTS uses Point or Coordinate as a return value & match it. Centroid needs to use $.geo.proj for accuracy. The centroid should be calculated in web mercator & projected back to geodetic. ===proj=== The way we do projection is different than how GIS does it. Usually, when you define a projection, you work in non-geodetic coordinates because the coords have been projected to a flat plane. With jQuery Geo, you work in projected coordinates (I call them non-geodetic) when you set $.geo.proj to null. This can be a little confusing but I think it works. The first thing we would have to do internally is set $.geo.proj to null because we use pro ===bbox proj=== bbox might be an issue. a bbox in geodetic coordinates (lon/lat) that is a rectangle, will not be a rectangle in web mercator. That's not a problem with setting the bbox property on geomap but could prove interesting for the bbox of geometry objects. For example, the bbox of a square polygon will not be a parallelagram in geodetic coordinates. SUGGESTION: Calculate & cache bbox in projected coordinates SUGGESTION: Document that lon/lat bboxes will not appear to be correct? ===bbox cache=== Peter and I got into a talk about caching bboxes. He's worried that we will have too many floating references to objects that cannot be collected. That is a valid point. For example: a user creates a polygon as an object literal, they then call $.geo.bbox on it, then the function ends. We will have a cache of the bbox, but most importantly the cache will reference the original polygon so the browser cannot remove it from memory. I agree that this isn't a great situation. However, the performance benefit gained by the find method is hard to ignore. Also, this only becomes a problem when the developer calls bbox directly. Even though we call it during the find method (building up cache), they are all removed when the dev removes shapes from the map with the remove method. I also know I need to research more about how $.data works with objects. I may be wrong about the reference/memory leaks. ===point bbox cache=== Now that I know I should cache bbox as non-geodetic, I think I should revisit my jsperf regarding caching a point. Since there's going to be much more calculation involved in $.geo.bbox, I might want to cache points. However, I think I should only cache them if $.geo.proj is not null. When it's null, non-cached points will still be faster as per my original jsperf test. ===events=== The new shape event will need a new event type. Position event won't cover it but it's similar. I'm not 100% sure if I should merge them. The new event type will be a shape event. ==2011-08-24== ===utah=== While zooming in, Chrome skips zoom level 12. I wonder if that's a bug in the control. It is. It's a rounding error in _getTiledZoom. Using floor and * instead...fixed. ==2011-08-19== ===contains=== Contains is spatial ref agnostic and is called by distance. == 2011-08-07 == === bbox === I think I'm missing something from my bbox description. === append === I would like to say that devs can call append again on a shape and it will replace the existing one and clear the bbox cache. That might be a good compromise for bbox cache clearing because I don't want a method specifically for that. Maybe, I'm not sold on the word append replacing something that's already there. Does jQuery have a replace function? SUGGESTION: geomap - append should allow re-append of existing shapes, replacing the old one and clearing the bbox cache === bbox ex === I'm writing an odd example and I already forget if fromGeodetic can take a single position. It can, according to my docs :) === from/to pos === I keep going back and forth about coordinate vs. position in terms of words. I almost thought of changing fromGeodeticPos to fromGeodeticCoord but they /are/ called positions in the spec so I'm going to leave it. Again, it's spoken words (of which I suppose I am now including API function names) and code, which is GeoJSON object properties and arguments. Still confusing, this will never be settled so I'm dropping it. === bbox cache === Oops, I wasn't namespacing my data. I thing it has to be geoBbox because the namespaced data attribute would be data-geo-bbox. == 2011-08-06 == === alpha 2.5 === I released a new version last week and it seems to work well. I'm happy with it. On to documenting the features of alpha3! === label === I'm going to add labels and I think I want a label argument to append, however I want both style and label to be optional. In other words, you can pass a shape and a label. The label argument will be a string of html or a jQuery collection of elements to append to a label div. The outer label div is controlled by geomap. It will have a class on it, geo-label, if devs find they need or want to control it that way, i.e., add plain text and control the label style using the class. === jQuery a plain === Is a jQuery collection a plain object? Not according to this fiddle: http://jsfiddle.net/ryanttb/4rHK5/ So, I will have two optional args: style and label. Style has to be a plain object. Label can be a string or jQuery object. I'll say style comes first but they can be in any order. === shape props === Even though I have args on append, I will eventually allow both style and label properties on the GeoJSON object. They're not standard but not illegal according to the spec. === stored label === For speed, I will have to build the label HTML during the call to append, whether or not I use the shapeLabel property on the map or the label supplied during append. === override === The label supplied to append will completely override the map's shapeLabel property. === centroid === While I would like a LineString's centroid to be a point along the line so I can using it for labeling, that's not the accepted definition of a centroid of a line. According to JTS, it's calculated like a polygon, except when there is a polygon as part of a GeometryCollection. In which case lines and points are ignored when calculating centroid. === line label === Checking to see if JTS has an official point-along-line function that I can add w/o creating my own name. It doesn't seem to. I just decided to not label on the centroid for lines but on the "center point" of the line. As you add more points, the label will move further along the line. === envelope & bbox === So, OGC simple features doesn't seem to define an Envelope class. The Envelope function is defined to return a Polygon, eww! === ogc text align === They do define text alignment options called HorizontalAlignment: start, center and end. Might be useful later for text label options. === $.geo & proj === Internally, I need to call the geometry ops in $.geo and I will already have a projected bbox or geometry object. I need a way to tell methods such as $.geo.expandBy to not call $.geo.proj.fromGeodetic even if $.geo.proj is not null. I think for now I will have an internal (and undocumented save for here) argument at the end called ignoreProj. If truthy, it will not call fromGeodetic. A false value or undefined will call fromGeodetic if $.geo.proj is not null. The documentation will always say fromGeodetic is called if $.geo.proj is not null. SUGGESTION: Add an internal ignoreProj argument to $.geo geometry functions. === scaleBy === I haven't used it yet buy my original port of the scaleBy function was wrong. I was calling expandBy which would make scaleBy(bbox, 1) actually increase the size of the bbox, however, scaleBy(bbox, 1) shouldn't change the size at all. Also, expandBy was wrong basing itself on center instead of just modifying the min/max values directly. === geodetic bbox === I forgot that from/toGeodetic don't currently support bboxes. What am I doing already in geomap? Ah, right. I only needed it once (the bbox property) so I'm converting to two positions by hand. I think I should make a conveniance method in $.geo.proj. fromGeodeticBbox or something. I'm not going to make it public. Devs shouldn't have to call it, they can work in whichever projection/non-projected state they set $.geo up as and the public functions can handle it. SUGGESTION: add private _from/_toGeodeticBbox methods I did remove the, "if $.geo.proj is not null X first calls fromGeodetic..." shpeal that I had in all the bbox methods because it's not accurate. I won't call from/toGeodetic, I'll call a private method. Actually, I should be able to detect a bbox vs any other geometry in the *Geodetic methods. It will be an array of 4 numbers, so .length == 4 and $.isArray(value[0]) == false. Maybe I'll put bbox conversion into them after all. == 2011-07-30 == === alpha 2.5 === It's been too long since I had a chance to work on this and I want to get an alpha 2.5 release out. I need to push this back in an change my current branch name. I think it's alpha3 at the moment. === jsperf === I wrote a perf for point & linestring bbox cache testing. The test makes me think jQuery.data doesn't do what I think it's doing. When I cache the bbox in a local var, it's very fast but when I cache with data, it's not. * Here's the point test: http://jsperf.com/point-vs-bbox * Here's the line test: http://jsperf.com/line-vs-bbox It's always faster to test points by themselves, i.e., don't worry about checking for a cached the bbox. === branch === I was on master, so I pushed, then created & switched to alpha2-5. === opacity === When developing the heat map example, I remember running into an issue where I couldn't get the opaicty to look right between the border and center. Maybe I fixed it somewhere else because I can't seem to reproduce that. I can still get it on the latest fiddle of the heat map. It's when the opacity is 1 and the strokeOpacity is 0, the stroke still shows up but it should be hidden. I still can't recreate this on the shapeStyle test page :( Ah, but the twitter heat example has the issue. Turns out I was or'ing the stroke/fillOpacity with regular opacity in _getGraphicStyle. That's not the right place to do anything with them, and never or. === service opacity === I'm going to pull in the service opacity method from AppGeo.Web as "opacity" on each service object, like refresh. That's done. I haven't documented/implemented what happens if you don't pass a service id. It's required. I'm not sure what I want that to do yet. === visible === When starting to think about geomap.toggle, I realize I have a naming conflict so to speak. The service object has a boolean visible property while the shape style has a string visibility property. I think I want to change the service to match the shape style. I don't think there are any attributes in HTML that pertains to visibility so I'm going to match CSS even in the service object which is more internal and less graphical. That said, I don't want to start renaming things in alpha 2.5 so that'll wait until 3. SUGGESTION: Rename service.visible to visibility having either "visible" or "hidden" values === service props === So, I noticed that when a service is created, I don't modify the service objects to fill all the supported properties. So, when toggle is called, there's potentially not an initial visible property set. I think for now, alpha 2.5, I will have the toggle function assume that there could be an undefined service.visible. The refresh method does the same. Later, though I think I might want to set defaults during _createServices. === proj === New projection code seems to work and is awesomely 150 lines shorter! === resize === I'm going to hook into the window resize event automatically but I will still need a resize method later in case the dev changes the div size/css. SUGGESTION: Add a resize method to let geomap know the div has changed size programatically I'm not sure of the correct way to kill & remake graphics now that it's a jQuery UI widget. It appears that I can call distroy & re-create it. Resize, is working though when getting smaller, there is a space for the scroll bars. I don't remember having that issue with the internal AppGeo.Web control. That is an issue to tackle after alpha 2.5. === dbl tap === What is a thumb? On touch devices, and other soft-dblclick devices I don't take into account that the second click/tap might be too far from the first to count as a tap. There is no move event to cancel. I'm now calculating distance between the two based on _anchor (previous) and _current ( current :). This will need testing. I'm setting it at 10px for now, line 1480 of geomap.js as of this writing. == 2011-07-19 == === wkt === Wrote up some to-WKT code for our internal control today. WKT will also be supported by parseWKT and textify methods in $.geo. SUGGESTION: Support WKT with $.geo.parseWKT (like JSON.parse or $.parseJSON) and $.geo.textify (like JSON.stringify). === centroid === Wrote up some centroid code for all but GeometryCollection as well for our internal control. Code similar to this will end up in $.geo.centroid. == 2011-07-15 == === presentation === My first real talk about $.geo went well, I think. Next up is FOSS4G in September and, possibly, jQuery Conference Boston in October & Harvard WWW in December. === alpha 2.5 === I think I want to push out a bug-fix release of the alpha 2 tech. I'll tag it as alpha 2.5 in github but overwrite the alpha2 js file on host. Well, rename the old one as alpha2.0 in case people find a bug in the new one. I need to write down exactly what to do for alpha 2.5. === shape images === People really want images on shapes, particularly points. I'm removing this feature from my TO DO list: * geomap - Document and implement passing a function to shapeStyle and append that returns a geomap style object based on feature or geometry properties because I have a much better plan that involves the label div. It will be a normal div and have a class. Each will have relative position and designers can manipulate it however they want. == 2011-07-12 == === fiddles === Some fiddles for my demo on Wednesday: # show a map: #* http://jsfiddle.net/ryanttb/A6avG/ # show a map & zoom to boston #* http://jsfiddle.net/ryanttb/2qBgw/ # show a map & zoom to geolocation #* http://jsfiddle.net/ryanttb/Pre4k/ # add a location search #* http://jsfiddle.net/ryanttb/3LpqG/ # add a twitter search: rpp=100 #* http://jsfiddle.net/ryanttb/79zTk/ # use map center as geocode, radius=(pixelSize * width/2 ) / 1000 #* http://jsfiddle.net/ryanttb/2PCUu/ # change style to heat map (16x16 size 8 border-radius) #* http://jsfiddle.net/ryanttb/PUeRc/ # update on bboxchange #* http://jsfiddle.net/ryanttb/8LQLW/ # show tweets in popup #* http://jsfiddle.net/ryanttb/y2gTh/ == 2011-07-07 == === bbox === I added bbox caching! I even check to see if the GeoJSON object has a bbox property, which is legal. There's no way to update the bbox but that'll come later. === distance === I almost tried to have distance support taking in a Feature but that opens a whole can of worms. I'm going to fix find to only send base geometry types to distance. DOCUMENT: geometry methods will only take base geometry types (Point, LineString, Polygon & Multi*) or coordinate arrays I had some weird comment on this method, it should be documented to only take base types, as I just said. === form input === I was talking to Chris last night about what geomap does that others don't and he reminded my about the idea I had of keeping a hidden input of the shapes as WKT. This would mean that I had to have a property on geomap for the map's name and also definitely change the service object to use name instead of id for when I add service-level shapes. WKT becomes a problem though when they've added features. I suppose I would dig into the features and only pull the geometry. === json === It's been a while since alpha 2. I'm working on a demo that draws the US state boundaries as graphics. == 2011-06-30 == === min === Srsly? I wasn't using minified jQuery in my examples? Wow. == 2011-06-29 == === alpha2 === Released alpha 2. I don't think anyone's really using it yet though. == 2011-06-28 == === on services === I think it would be nice to deep extend service objects that come in via the services property if a service with the given id already exists in _currentServices. This way, you could set the initial opacity of OSM by simply sending {services: [{id: "OSM", opacity: .8}]} during init. SUGGESTION: deep extend existing service objects when services property is set === on opacity === I was beginning to try to throw the opacity & toggle methods into alpha2 but setting the services property is too flickery. I want to do it more like the old widget but that will require adding opacity and toggle methods into the services types. That will have to wait. It will be much faster to call the opacity/toggle methods on geomap than to set the services property each time. I will have to document that. SUGGESTION: require opacity and toggle functions in the service type objects == 2011-06-27 == === on events === I almost forgot that I don't want bboxchange to fire when the developer changes a property in code. Unlike jQuery UI, my events trigger only when the user does something. === on alpha 2 === I'm trying to put this together. == 2011-06-24 == === on shape methods === I'm almost done. I need to finish empty and then I have what I wanted for an alpha 2 release! === on Point vs. coordinate === I think I'm going to settle on using Point objects everywhere except the projection functions. Which means I need to change find to accept a Point instead of an array. This should work out because the position events already send GeoJSON objects instead of position arrays. === on geometry === contains doesn't care about projections. Lon/lat values do not need to be projected. I got done some of the geometry functions in $.geo but I'm leaving them private for now until I have a chance to document them and fully implement them. === on proj === Finished changing the $.geo.proj docs to explain that it will convert any GeoJSON coordinates array. I think I will also change the requirements to implement other projections by having the developer only have to override single position conversion functions (instead of worrying about the dimentionality of the passed array). Done. === on find === Now that proj is more powerful, I think I can handle find. == 2011-06-18 == Accidentally coded append differently than how I documented. Will fix the code. Documentation FTW! I can't decide if the geometry functions in $.geo should only accept the base geometry types or not. Initially they will not. I don't want to even think about getting into $.geo.distance(multiPoint, geometryCollection). $.proj should go up to a three dimensional array to handle the coordinates in a Polygon. Go big or go home, I'm going to support four dimensional arrays so that I can get MultiPolygons as well. That will handle all of the GeoJSON types that have the coordinates property. If you have a GeometryCollection (geometries property), a Feature (geometry property) or a FeatureCollection (features property), then you're on your own. I may change every mention of "web mercator" to "spherical mercator" to be more specific. == 2011-06-17 == Attempting to change drawPoint from ovals to rounded rectangles. Shortcutting to drawArc if the width/height/borderRadius are the same. Since I plan to make geographics public at some point, I thought I might make the drawPoint/Line/Polygon functions take actual GeoJSON shapes but I think that might conflict with some functionality internal to the geomap during digitization...I'll have to revisit this. I seriously need to settle on the word "position" in my code when referring to an array containing an x/y. I use coordinate a bunch because that's what I used in the old project. Oh, but the property name of the GeoJSON object is coordinates. Heh, this is so confusing :) Ok, as I have been doing: coordinates in code, position in documentation. I'm using cowboy's safeParse but can't tell what it's guarding against. I thought it would always give me a number but that's not the case. Guard against NaN or undefined? Should drawing a bbox ignore borderRadius? I haven't decided. You can fill and then stroke the same path, just sayin'. Point graphics now draw as rounded rectangles. There's weirdness if your sizes are a little off though. I should probably start clamping values to each other like width & height to borderRadius. Yeah, if either is smaller than borderRadius the drawing gets weird. Maybe I should clamp borderRadius instead. Probably. Yeah, have to clamp borderRadius to min(width, height)/2. I don't think you can disable fill by setting style.fill to "", but you should be allowed. It shouldn't be required to set fillOpacity to 0. I just dropped a couple loops out of my graphic drawing in geographics. Should help a bit :) == 2011-06-12 == I'm finally pushing the renaming changes to the main project. === On examples === I talked to Boaz at Bocoup the other day. He suggested cleaning up the examples. I already had this in mind but I should probably do it sooner rather than later. Especially the simplest example. It will look nicer if I cut the div down to 256x256 to match the initial tile I think (done, it already feels better). I do need to keep the examples specific and don't want to add any HTML or JavaScript to them that does not directly relate to the feature I'm testing in the example. He also suggested unit tests and an API audit, both of which are great ideas and much needed by $.geo. === On ovals === Peter and I discussed how points are drawn and what width and height mean in geomap styles. We both agree that ovals are not very useful or used constructs in GIS and it would be better to have rounded rectangles. Therefore, I am dropping ovals and intead supporting a borderRadius property. Circles are still possible as long as your width, height and border radius are all the same, you will have a circle. This will be the default. === On double-click zoom === Peter and I both agree that double-click zoom should operate similar to mouse-wheel zoom in that the bbox should scale according to the placement of the mouse cursor during double-click instead of completely re-centering. You will notice that mouse-wheel feels right and double-click can be confusing. SUGGESTION: Double-click zoom should scale according to cursor location instead of re-centering === On position events === I cannot decide if I should officially make the geo argument passed to the position events (move, click, dblclick) a true GeoJSON Point object. The only difference would be the presense of a type property set to "Point". However, the extra pixels property that I have on the geo argument is not part of GeoJSON and will remain in memory. Also, if a developer pushes the new object to a database they are storing extra information that they don't need and will be useless later. Is the pixels property even that useful? The dev can call geomap.toPixels if they need it. I added the pixels property just because I had the pixels lying around in the internal handling of the event. I think I might just not pass them. It would be more useful to a developer I think to have a true GeoJSON Point object that they can send to geomap.append or a database without worrying about having extra useless data stored with it. SUGGESTION: Remove the pixels property from position events and add the type property to make the event argument a true GeoJSON Point I just updated the docs and changed the implementation. I already like this a lot better and am now thinking that the bbox event type could actually send a true GeoJSON Polygon with the bbox property set. That would be totally within the GeoJSON spec and might be useful. That's a bit of extra code on the widget's side though so for now I'm going to leave it as is. I can add that feature later since the current implementation (an object with just a bbox property) is already partially in a true Polygon's spec. FUTURE SUGGESTION: Send a true GeoJSON Polygon object as the geo argument of bbox events === On returning jQuery collections === I need to better design the return values of the shape methods other than find & shapeStyle. Should append, remove and emtpy return the jQuery object of the map elements that the call originated from? Probably. I just tested and yes, as long as you don't issue a return statement inside a jQuery UI widget method, jQuery UI will return the original jQuery collection for you. == 2011-06-10 == === On geographics === I am going to leave drawArc in the graphics widget. The drawPoint method will draw our default point shape (rounded rectangle) but, in the future, when custom drawing is in, a developer can use the drawArc if they want. === On proj === Peter has updated web mercator <=> geodetic code for me to drop into $.geo.proj. == 2011-06-06 == === On renaming shape functions === Renamed the shape functions. That was annoying but I'm glad I only had addShape implemented. === On jQuery UI widgets === The widget factory does hide methods that start _ from being called. So much for renaming drawArc to _drawArc and still calling it from geomap. DEPRECATED SUGGESTION: Turn geographics into a NON-jQuery UI plugin Did I totally get the scoping wrong for the jQuery UI widget? I have local vars in my initial plugin closure. Will they conflict if there are more than one map? SUGGESTION: Verify that vars local to initial closure do not conflict when multiple maps are placed == 2011-06-04 == === drawArc === I just realized that by dropping geographics.drawArc in favor of drawPoint I am losing the ability to draw the circles I need for digitization modes. I wonder if, before I turn DrawPoint into a box-like function, that I should copy it to _drawArc. Will jQueryUI.widget let me call it from geomap? === shapes === Chris and I were talking about merging append (previously addshape) and find into one call: shapes. If you pass a GeoJSON object or array of, it will add them. Otherwise, it will find them. Thinking about this today, I don't quite think that's the way to go. I mostly feel that calling geomap functions to manipulate shapes is closer to adding elements to a jQuery collection. In other words, to call the geomap functions you must have already wrapped an element with jQuery, $("#map").geomap("funcName"). When you wrap elements with jQuery normally, you have to call append, find, etc. Geomap will work the same with. Of course, I do still want the syntactic sugar later: $("#map").append(geoJsonObj); == 2011-06-02 == Who needs a blog. I feel like the best place to keep a developer journal is in the project itself so here we go. === On addShape's style argument === I showed Peter the shapeStyle demo. He expected that the shape-specific style applied via addShape would only override properties set during addShape. Further manipulation of the base shapeStyle would cascade to the shapes for any properties not explictily set. You know, like CSS. This is obviously the correct way to go and I already forget what made me code it the other way last night. Likely that I was coding at 2am and thought that if a user was passing a style to addShape they would want ALL style properties set in stone for that shape. That is not the right idea. If they want all properties set in stone, they can override all properties in the style object sent to addShape. I changed the implementation before leaving work. === On storing & modifying style === My initial implementation drawing shapes in $.geo is very similar to how I did it with our internal control. I also showed Chris the shapeStyle demo and explained how you can add a style that's different from the base style on the map. He suggested that there be a way to change the style of an already added shape. I figured that I could make addShape update existing geometries instead of adding a new one but the syntax felt wrong. An updateShape method would work and could pass right through to addShape internally. He also suggested allowing access to the internal GeoJSON->style map (as a return value for addShape) so they can maybe change the existing styles that way. However, something doesn't feel correctly designed about that. We discussed attaching the style to the GeoJSON object. I already had supporting that in mind. If the user happens to have put a style property on the GeoJSON object before passing it to addShape, I would use that when drawing. A style passed to addShape would override that. The cascade would be: base style => GeoJSON object style => addShape style. A developer can keep the style property on the object even when it's stored, such as in GeoCouch, something that Guido wants a lot. That said, I know I'm going about this wrong. As I said, my initial implementation feels too much like the old one and I want to do something much slicker in the jQuery world. On my walk home, I realized that since I am only storing a reference to the GeoJSON object and the user supplied style I can probably connect the style object to the GeoJSON object using jQuery's data method. I wasn't sure if targeting a plain object is allowed in jQuery. I know it's possible but that doesn't mean I should. I remember IRC talk about it but forget the outcome. Info on ticket 8108 (http://bugs.jquery.com/ticket/8108) reveals that the DataLink plugin does this so I'm going to assume it's ok. This little fiddle shows that the data properties don't show up with stringify http://jsfiddle.net/ryanttb/PetpJ/ but I'm going to do more research to see if it changes the object in a way devs will notice. The data method doesn't natively support namespacing. I could do it myself using a period but I would like to follow what jQuery Mobile is doing with their data attribute stuff. They use data-jm-role which I believe equates to the call .data("jmRole") but I need to check up on that as well. So if I were to do data-geo-style, that would be .data("geoStyle"). I can live with that. SUGGESTION: Store $.geo styles via $(geoJsonObj).data("geoStyle", style) === On shape functions === Again, the shape functions feel very old and were grabbed from my internal control. Tonight I was thinking about a new way to do this and it involves being able to wrap GeoJSON objects with jQuery collections and intercept $.fn calls such as .css. Also, non-jQuery UI functions can be added to the geomap widget's div to replace the old addShape method. For example: $("#map").geomap("addShape", geoJson) could be $("#map").append(geoJson). How would I add shapes to specific services in the future? $("#map [data-geo-service='OSM']").append(geoJson) maybe. This might be going too far. Perhaps the old way is fine but use newer names (without the Shape suffix): $("#map").geomap("append", geoJsonObj), $("#map").geomap("append", "OSM", geoJsonObj), $("#map").geomap("remove", geoJsonObj) and $("#map").geomap("empty"). SUGGESTION: Rename the shape manipulation methods The methods also need to take arrays of GeoJSON objects as returned by databases and jQuery collections of GeoJSON objects as possibly returned by the find method. SUGGESTION: Shape manipulation methods should handle arrays Looking back at the above code, I feel like maybe if I really can get the selector-based way to work, e.g., intercept the append call on the geomap widget, I could target the services using a class. They are divs inside the map, I should be able to trap them: $("#map .OSM").append(geoJsonObj); That does look really nice. SUGGESTION: (future) Trap existing jQuery calls: append, remove and emtpy, on both the widget element and the service elements as syntactic sugar, forward them to geomap calls However, using the class selector feels wrong. Especially if I'm telling them to use the id property when creating the service objects. I could switch it to name when creating the service objects, then: $("#map [name='OSM']").append(geoJsonObj); I need to find out if any of this is possible as soon as possible. It's still shorter than calling geomap. I would have to warn users to make sure the space is there, this needs to be a descendant selector. SUGGESTION: Use name instead of id in the service objects. === On finding shapes === So you can append and remove shapes. Fine. But I also want a better way to search for shapes. Chris and I mulled over a selector-based way. I think I still want the simplicity of $("#map").geomap("find", position, pixelTol). That will cover a lot of use cases, users click maps a lot. However, there should be other ways to get at your shapes in a UI widget way: $("#map").geomap("find", [-67, 43], 8); // find all shapes within 8px of the map position (special case) $("#map").geomap("find", "[type='Point']"); // Finds all points $("#map").geomap("find", "[name='OSM'] *"); // all shapes in the OSM service (future) $("#map").geomap("find", ":intersects(wkt(POINT(-67 43)))"); // Advanced spatial filter, OGC selector names (way future) Here's how they would look with the future jQuery syntactic sugar: $("#map").find([-67, 43], 8); // find all shapes within 8px of the map position (special case) $("#map").find("[type='Point']"); // Finds all points $("#map [name='OSM']").find(); // all shapes in the OSM service (future) $("#map").find(":intersects(wkt(POINT(-67 43)))"); // Advanced spatial filter, OGC selector names (way future) AppGeo-geo-f763e47/grunt.js0000664000175000017500000000416512005347446014456 0ustar daviddavid/*global module:false*/ module.exports = function(grunt) { // Project configuration. grunt.initConfig({ pkg: '', meta: { banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' + '<%= grunt.template.today("yyyy-mm-dd") %>\n' + '<%= pkg.homepage ? " * " + pkg.homepage + "\n" : "" %>' + ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>/<%= pkg.author.company %>;' + ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */' }, concat: { dist: { src: [ '', 'js/excanvas.js', 'js/jsrender.js', 'js/jquery.mousewheel.js', 'js/jquery.ui.widget.js', 'js/jquery.geo.core.js', 'js/jquery.geo.geographics.js', 'js/jquery.geo.geomap.js', 'js/jquery.geo.tiled.js', 'js/jquery.geo.shingled.js' ], dest: 'docs/<%= pkg.name %>-test.js' } }, min: { excanvas: { src: ['js/excanvas.js'], dest: 'js/excanvas.min.js' }, jsrender: { src: ['js/jsrender.js'], dest: 'js/jsrender.min.js' }, widget: { src: ['js/jquery.ui.widget.js'], dest: 'js/jquery.ui.widget.min.js' }, dist: { src: ['', ''], dest: 'docs/<%= pkg.name %>-test.min.js' } }, qunit: { files: ['test/**/*.html'] }, lint: { files: ['js/jquery.geo.core.js', 'js/jquery.geo.geographics.js', 'js/jquery.geo.geomap.js', 'js/jquery.geo.shingled.js', 'js/jquery.geo.tiled.js'] }, watch: { files: '', tasks: 'lint qunit' }, jshint: { options: { curly: true, eqeqeq: false, immed: true, latedef: true, newcap: true, noarg: true, sub: true, undef: false, boss: true, eqnull: false, browser: true }, globals: { jQuery: true } }, uglify: {} }); grunt.registerTask('default', 'lint concat:dist min:dist'); }; AppGeo-geo-f763e47/LICENSE-MIT0000664000175000017500000000204112005347446014404 0ustar daviddavidCopyright (c) 2012 Ryan Westphal Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. AppGeo-geo-f763e47/LICENSE-GPL0000664000175000017500000003537312005347446014413 0ustar daviddavid GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. AppGeo-geo-f763e47/index.html0000664000175000017500000003673412005347446014765 0ustar daviddavid jQuery Geo

            jQuery Geowrite less, map more

            jQuery Geo - an interactive mapping plugin

            jQuery Geo, an open-source geospatial mapping project from Applied Geographics, provides a streamlined JavaScript API for a large percentage of your online mapping needs. Whether you just want to display a map on a wep page as quickly as possible or you are a more advanced GIS user, jQuery Geo can help!

            You can check back here or follow @jQueryGeo on Twitter for release announcements. Also, head over to the lead developer's Twitter account, @ryanttb, for development info, links, or to ask questions.

            Download

            Using jQuery Geo requires adding one element, including one script (apart from jQuery itself) and calling one function. The following copy-and-paste snippet will help you get started.

            <div id="map" style="height: 320px;"></div>
            <script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
            <script src="http://code.jquerygeo.com/jquery.geo-1.0b1.min.js"></script>
            <script>$(function() { $( "#map" ).geomap( ); });</script>

            code.jquerygeo.com is on the CloudFlare Content Delivery Network (CDN) so our minified, gzipped library will get to your client as fast as possible!

            Beta 1 released!

            Over 120 commits and five months after the release of alpha 4, jQuery Geo is now feature complete with what we planned for version 1.0!

            The highlights are mentioned here and you can follow the link at the end to read more details.

            New interaction engine

            User interaction is a big part of an interactive map widget, obviously!, and in beta 1 we have optimized panning, zooming, and how they work together. Your maps should feel more responsive overall.

            Wicked fast mobile

            Using CSS3 features on modern mobile devices brings tremendous speed improvements to iOS and Android.

            New default map

            Probably the most noticable change, jQuery Geo is still using OpenStreetMap data by default but in the form of tiles rendered by mapquest open. It's your same open data but the servers are faster and the cartography is nicer.

            New build environment

            jQuery Geo now builds with grunt from Ben Alman making it 100% lint free, smaller, and supporting the next generation of the jQuery Plugins website.

            Drag modes

            There is a whole new mode style called drag. Previously, draw modes such as drawPoint and drawPolygon, allow the user to perform individual clicks or taps to create shapes. New modes have been added that trigger shape events on a single motion: dragBox and dragCircle. They disable map panning and allow quick digitization of rectangles and circles, great for spatial queries and selecting! They both send GeoJSON Polygon objects as the geo argument to your shape event handler.

            Load events

            Two new events, loadstart and loadend, allow you to display indicators or give feedback to users while map tiles or other images are downloading.

            Forcing refresh

            Sometimes you have time-dependent, continuously updated data and images coming from a map server. New arguments to refresh allow you to get updated images even if the map's viewport (and thus, image URLs) hasn't changed. You can also refresh only specific services that you know will have changed, leaving other more static images in place.

            Zoom level constraints

            Whether you have a tiled or non-tiled (all shingled) map, you can now limit how far in and/or out a user can zoom with the new zoomMax and zoomMin options.

            Breaking

            There is one, small breaking change in how all template strings are processed. This is due to a change (and finalization in the API) to jsRender, which jQuery Geo uses for a service's src template strings and measureLabels template strings. In short, use {{:variable}} where you used to use {{=variable}}. You can read more about this change on Boris Moore's blog post: http://www.borismoore.com/2012/03/approaching-beta-whats-changing-in_06.html.

            Enjoy!

            Thanks for checking out jQuery Geo! We hope you find it useful and will keep you updated as we press on to a 1.0 release!

            Click here to checkout the full changelog

            Edge

            The links above will always point to the latest stable release. However, you can test the most recently committed docs, code & demos by heading over to the test release.

            Test docs & demos

            Thanks!

            AppGeo-geo-f763e47/apple-touch-icon.png0000664000175000017500000000431412005347446016632 0ustar daviddavidPNG  IHDR``F sRGBgAMA aPLTE~   ! #",+-,/.0/10KILJNLTRUSWUXVZW[X\ZLLMMUUigjhkiwtwtxuyvzwVVđđƕǖǗͣͤΥ犊½'`tRNSS% pHYsodtEXtSoftwarePaint.NET v3.5.87;]$IDAThCi_1 (xp(". C 3IҤtW~K>MT<G VEwy=v;1%Bq{/l_O& bQ*ooa|?<+$G]NL>DKg1&έn%}`L:{! ~AɃԴH*F$1`]#/#]# XO/# 1-:x͋ڈD0/#Q)FO96R $ظI,60) C:} Kopr.PW"}y*'#C])ؠdl"x|V_T;J})>n1v! mgBl*}$Sz2W?Cb~,R32&t!bklL=(pD~U v}&0U?}[|9%k$:v} 0QEB s!` vK΢-Z5ˀɐfd*#Q,!z+A(InsGXwd)?GlQFR CԜMPͨ>bC= C97@gL) ? jiP;C AA iHGne48/%$"qQH 텞e=ާʯo^afT w JENi+Q{7*dIENDB`AppGeo-geo-f763e47/package.json0000664000175000017500000000141712005347446015244 0ustar daviddavid{ "name": "jquery.geo", "title": "jQuery Geo", "description": "An interactive mapping and spatial analysis plugin.", "version": "1.0b1", "homepage": "http://jquerygeo.com", "author": { "name": "Ryan Westphal", "company": "Applied Geographics, Inc.", "email": "ryan@trippingthebits.com", "url": "http://trippingthebits.com" }, "repository": { "type": "git", "url": "git://github.com/AppGeo/geo.git" }, "bugs": { "url": "https://github.com/AppGeo/geo/issues" }, "licenses": [ { "type": "MIT", "url": "http://jquerygeo.com/blob/master/LICENSE-MIT" }, { "type": "GPL", "url": "http://jquerygeo.com/blob/master/LICENSE-GPL" } ], "dependencies": { "jquery": "~1.5" }, "keywords": [] } AppGeo-geo-f763e47/favicon.ico0000664000175000017500000006410612005347446015103 0ustar daviddavid00 %00.&  4 ~E &NW hv^hb(0` H ~}}~@x}}~}00ddqqAA}8}}^^pp}0~33}`}}~}\\TT56:;\\yy0Xkk&& 22**:;FF~~VV89>?iiOP jj``zz}}/0KKiiFF~~GG))?@}}lm[[RR~~KK,,>?}MMwwrr ab[[]]YZ mmaa  <<3300QR kkhh./z{HI..22RRqrUURR  23..33&&9:gg;;11 CCII::34TTQQ ()fg  66YZrr @@qqjj..xy aa00^^((oo=>%&~~YY88BBSShh<< 45KKiiFF00`attooAA ![[RR??ppjj..MMhhnnww 01  hiQQmmaa 02 **ss``^^ kkhh@ACD IJ   9:)*IJ$$TUDFww&&\\==AAiiAA**00NO ,,EEab <<22;;9:$$QQ RR**&'QSrr  hhii``[[ 11KK,,WX}}eellcdXX 22GG))ZZ}}?@EE II##++VX jj}~hh##55## ]]ef%%99#$00 11++NO}8}lmOP\\__KKqrz{RRWW@@p}``}(}}Xx}ﷷ((~}``xx}x}}``pp}~(}}@(}}}}~@?(0`~   !&&..1156:;###$%% ((..++##$$&&)),,/011003455:;229:=>;;==--00225588;;<:.J$(~}&nG.JѢmgf  1Ѣ-:*4iѢ=:DG41ff ӷژ%k  2\m >~8vڶڲj9j%r7#y1e}c9lt~Xzf>}9U}rЁ /qf~{ 0٪ +zl}}EF  T  4'T#[Sw#a7Eqb,&W 8do >;66)f f+#]Ѐ } qa y 3e8_ |sp y 3e+`7ce('^~q";) ap*<!/ :8Ws]alWux]^Ea%lxau?( @ {8@@@@@@@@@@@@@@@@@@: }t}~} }~}fy};;vv}}FF }{#~nnww}f~ckk{{}~yy~Ux}44||55--))ABLL~,}ss'(XYIJ55((jj}68}''YYxx~~bbJJWX}}?@..&&&&~~##@@yy..,,!!DDee'(abyy^^3355pp@@++qqOO ((**77@@22AA@@!!ttSSBC@@|| 89ll**,,~~@@ UUpp%%uumm##@@*+TT%%56HH$$ ddMMjj@@YYoo''GHLM33ssMM ==11@@zz$$pp==%% !YY@@VVWW))ii&&op@@*+ ,,55==--&'@@ @@xx kkqq@@44>>MMde''YY**@ALLCC**@@GGjjZZ&&!!abUUAA}@6}DDff]]&&""cdQQ==}>|%}圜<=::GG%&rs((PP//st''EE??44~2s }44~ww\\}y<|`~~} ~3399~<~}}}~}}O$0@@@@@@@@@@@@@@@@|1|' ( @~  &&**;;!"%& $$)*//()..""%%)),,++,,452255::::??00239:9:..002255==???@@@IIPP@@DEFFBBGHKMRRYZhhrr||ff``oouuvvyy||CCHHOOLM@@RRUVXX]]UUDDHHLMPPRRUUcclmz{ppuucdeejjlmwwqruuwx{{VVXX\\``eeiikkooppssttwwyy||:G||||||||||||||||||{; E|}F HLKK~,""><NB=Y6J)ntr^Ia4&yv%1*]q!D`C*+_/y[)+?ʑ0z.ΕvY?αc 1b+1ײTײb4yt'ڬ1W*AV rmhow5VV8x\ S64wQ($#Q$nf1rz&$60Q5(i!k l2[ng4p32$]Z%8oX/Ƚ%inZ8nX/Ƚ$jmYOZ]%j5n6d%[Y/Oݣe @P(0 |Z|^8}%%HHFFFFFFFFFFFFFFFFFFFFFFFFKK,,}F0~__jj D}]]kkoomm} @VW==~~22ZZPPKL00|V}lGGNOVV~~~$$45WW}|YY=><< ^^TTMNYY]]12TT&&CCEEttyy]]aassjjffddaaee//~~00eeii33ij00**~iimm[[nnOPxx@@((<<<./~~[\bbuuyy}~++@@bbll&&CCUUyy}}99??}}//mm!!8877}}uuBB==ooyy78CD}heeqq>>99kk|}66CD~~}z0VW@Az{BBYZBBCC99L}}}녅 .}[[}}__}$*|`|b4?(0~  %%--00>>!"""-.%%&&((++/0/03333>>2255679:>>8899::==//007788::<<==>>?@FFHHKK__HHLLOOAAEFNNWW__YY]]jjmmllop~~DDAABBDDMMAAPPST\\UVWW\]ZZ\\BBCCPPTTUUaadeee``ccefiijjmmootussyzbcffmmnnqquuyyyy~~yz{{}}~~WWZZ__``ggkklloorrvvuu{{~~87777777777779:EBFHG AI"zZ<;@y&AC$3 {[@CD%\Y?giD]h} ^]_./_c#d/qclRfPp>-enQ|by Nno0)4 tUaorxOjlYSuwڣ ,6w!m+*xᢃX4u1Mkᤁ52w'JTKv߇LVLM,ߥWx`?(   @}^^pp}\\TT\\yy0}ǨKK~}[[YZaa ..&&34TT aaooRR??..**``kk$$TU9: **rr}?@ ##jj}``}``xx}}}(  44;<99=>PPWWQQEEOO\\Z[^^STDEJJLLZZYZ__EEGGLLJJKLQQPPYY__RRSSTTUUWWggcc~~qrssttyy\\^^ffzz}}nnppqqsszz{{~~?AAAAAAAA@FFFFFFBDCEHQQQQQ." >;GPTTTR, ]) ST___-^ /M_UV__bbb!`bb`IKabggOffJN85\gvc'9YvL< ev}o*d}X(#lwx}}|tjn6>%Z:i4+qz7=&[8$k3+s1h~m{prW0uy2AppGeo-geo-f763e47/index-full.html0000664000175000017500000007434112005347446015721 0ustar daviddavid jQuery Geo

            jQuery Geowrite less, map more

            jQuery Geo - an interactive mapping plugin

            jQuery Geo, an open-source geospatial mapping project from Applied Geographics, provides a streamlined JavaScript API for a large percentage of your online mapping needs. Whether you just want to display a map on a wep page as quickly as possible or you are a more advanced GIS user, jQuery Geo can help!

            You can check back here or follow @jQueryGeo on Twitter for release announcements. Also, head over to the lead developer's Twitter account, @ryanttb, for development info, links, or to ask questions.

            Download

            Using jQuery Geo requires adding one element, including one script (apart from jQuery itself) and calling one function. The following copy-and-paste snippet will help you get started.

            <div id="map" style="height: 320px;"></div>
            <script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
            <script src="http://code.jquerygeo.com/jquery.geo-1.0b1.min.js"></script>
            <script>$(function() { $( "#map" ).geomap( ); });</script>

            code.jquerygeo.com is on the CloudFlare Content Delivery Network (CDN) so our minified, gzipped library will get to your client as fast as possible!

            Beta 1 released!

            Over 120 commits and five months after the release of alpha 4, jQuery Geo is now feature complete with what we planned for version 1.0!

            New interaction engine

            User interaction is a big part of an interactive map widget, obviously!, and in beta 1 we have optimized panning, zooming, and how they work together. Your maps should feel more responsive overall.

            Wicked fast mobile

            Using CSS3 features on modern mobile devices brings tremendous speed improvements to iOS and Android.

            New default map

            Probably the most noticable change, jQuery Geo is still using OpenStreetMap data by default but in the form of tiles rendered by mapquest open. It's your same open data but the servers are faster and the cartography is nicer.

            New build environment

            jQuery Geo now builds with grunt from Ben Alman making it 100% lint free, smaller, and supporting the next generation of the jQuery Plugins website.

            Drag modes

            There is a whole new mode style called drag. Previously, draw modes such as drawPoint and drawPolygon, allow the user to perform individual clicks or taps to create shapes. New modes have been added that trigger shape events on a single motion: dragBox and dragCircle. They disable map panning and allow quick digitization of rectangles and circles, great for spatial queries and selecting! They both send GeoJSON Polygon objects as the geo argument to your shape event handler.

            Load events

            Two new events, loadstart and loadend, allow you to display indicators or give feedback to users while map tiles or other images are downloading.

            Forcing refresh

            Sometimes you have time-dependent, continuously updated data and images coming from a map server. New arguments to refresh allow you to get updated images even if the map's viewport (and thus, image URLs) hasn't changed. You can also refresh only specific services that you know will have changed, leaving other more static images in place.

            Zoom level constraints

            Whether you have a tiled or non-tiled (all shingled) map, you can now limit how far in and/or out a user can zoom with the new zoomMax and zoomMin options.

            Breaking

            There is one, small breaking change in how all template strings are processed. This is due to a change (and finalization in the API) to jsRender, which jQuery Geo uses for a service's src template strings and measureLabels template strings. In short, use {{:variable}} where you used to use {{=variable}}. You can read more about this change on Boris Moore's blog post: http://www.borismoore.com/2012/03/approaching-beta-whats-changing-in_06.html.

            Enjoy!

            Thanks for checking out jQuery Geo! We hope you find it useful and will keep you updated as we press on to a 1.0 release!

            Here's the full changelog:

            * geographics - use canvas compositing for Polygons with holes
            * geographics - [bug] on polygons with holes, stroke draws a line from exterior ring to interior one
            * docs - geomap - trigger a shape event when a user finishes measuring
            * geomap - trigger a shape event when a user finishes measuring
            * geomap - [bug] elements inside the map div lose their position setting
            * geomap - trigger bboxchange when we update the map size after the window resizes
            * geomap - [bug] multiple map widgets share the same compiled measureLabels template names and overwrite each other
            * examples - inset map/multiple maps example
            * geomap - [bug] in zoom mode, dragging from bottom-right to top-left draws box but doesn't zoom
            * geomap - [bug] any mouse down triggers refresh, even without pan
            * cdn - fix caching
            ** Cache-Control header max-age set to 5 years
            ** remove Expires header
            * geomap - upgrade to jsrender 1.0pre
            * deploy - build releases using grunt
            * deploy - make a package for new jQuery plugin directory
            ** https://github.com/jquery/plugins.jquery.com/blob/master/docs/package.md
            * deploy - lint JavaScript files
            * docs - geomap - dragBbox mode
            * docs - geo - polygonize function for bbox
            * geo - polygonize function for bbox
            * geomap - dragBbox mode
            * docs - geomap - shift option (default, zoom, dragBbox, off)
            * geomap - shift option (default, zoom, dragBbox, off)
            * docs - geomap - loadstart, loadend events
            * docs - geomap - allow append to take an array of shapes
            * docs - geomap - allow remove to take an array of shapes
            * docs - geomap - improve services option documentation
            * geomap - clamp measure labels to [0, 0]
            * geo - clamp centroid to bbox
            * geomap - measure label for polygon should be in centroid
            * geomap - merge interactive pan and zoom into one, faster system (pan/zoom rewrite)
            * geomap - [bug] iOS - panning is visually jumpy but settles on the correct bbox in the end
            * geomap - pinch-zoom doesn't follow user's fingers close enough when scaling
            * geomap - [bug] pinch zoom on iPad 2 (iOS 5) doesn't refresh tiles when zooming out
            * geomap - request new image in shingled service during interactive pan
            * geomap - [bug] zoom in more than once with zoom method moves tiles to the wrong spot
            * geomap - [bug] only services that have finished refreshing move when the user pans
            * geomap - [bug] map panning is jumpy, appears to be related to shapes and/or drawing context
            * geomap - [bug] pan sometimes lags on first drag
            * geomap - tiled data-scaleOrigin should be stored as an array
            * geomap - android - [bug] cannot always pan map after appending shapes
            * geomap - android - browser stops pan/zoom after 7 logos on logo demo
            * geomap - [bug] mouse wheel on bad or missing tile doesn't zoom out on first rotate
            * geomap - increase mobile performance by 9000
            * docs - geomap - add argument to refresh to force reload of images for dynamic data
            * docs - geomap - allow service-level refresh
            * docs - geomap - zoomMax option (tiled & shingled)
            * docs - geo - include method for bbox
            * geomap - bboxMax should reset center & pixelSize
            * geomap - [bug] initializing center, zoom, & bbox doesn't set all properties
            * geo - [bug] polygonize doesn't return valid polygon when using geodetic coordinates
            * geomap - [bug] dragBbox doesn't include the bbox property in the shape
            * geomap - dragBbox should send a Point (with bbox) for single clicks
            * docs - geomap - dragCircle mode
            * geo - include method for bbox
            * geomap - dragCircle mode
            * geomap - [regression] refresh & toggle methods no longer keep original service objects in sync
            * geomap - [bug] when a singled image hasn't loaded after pan and you double click on empty space, the zoomed bbox seems wrong
            * geomap - allow service-level refresh
            * geographics - remove the blit canvas from the DOM, i.e., don't attach
            * geomap - don't initialze service-level geographics until they're used
            * geomap - add argument to refresh to force reload of images (in case of dynamic data)
            * geomap - loadstart, loadend events
            * geomap - allow append to take an array of shapes
            * geomap - allow remove to take an array of shapes
            * geomap - zoomMax option
            * geomap - [bug] cannot interact with other elements on the page on iOS after panning the map (#71)
            * geomap - iOS - [bug] after one finger is removed, stop processing as if multitouch is still on
            * geomap - dumb high-precision mice down on tiled maps
            ** otherwise, the high precision rounds down to zero change in zoom
            * geomap - use linear distance for pinch zoom calculation
            * docs - geomap - zoomMin option
            * geomap - zoomMin option
            * docs - geomap - use MapQuest Open by default; can't deny that it looks much nicer
            * geomap - use MapQuest Open by default; can't deny that it looks much nicer
            * docs - geomap - rename dragBbox to dragBox
            * geomap - rename dragBbox to dragBox
            * geomap - [bug] error using tiled deferred services

            Alpha 4 released!

            It's been a long three months but we're very happy to announce the release of jQuery Geo 1.0a4! Here are some highlights and details:

            At the service level

            In alpha 3, you could append and interact with shapes on the map. In alpha 4, this is extended to services! Service-level shapes have their own shapeStyle apart from the map's and hide when their service is hidden.

            More modes!

            There are new modes to let you measure distance & area, and a static mode for when you want to display a map but not let users interact with it. Apart from the three new built-in modes, you can also create custom modes to help organize your app.

            What's that? CSS labels!

            You can now give any shape a label when you append it. You can style the label from your regular style sheet using the .geo-label class which opens labeling up to all the design power of CSS3. There's even more potential if you put a class or id on your map service because you can target labels on different services using CSS rules. Also, labels can be any HTML which opens them up to new features in HTML5!

            More service src options

            The old getUrl property has been renamed to src (see Breaking below) and you can now set it to a string template. jQuery Geo will stick your tile row, column, zoom, or image bbox in for you. Services defined as a string are a little easier on the eyes than a function and can be stored as JSON data.

            You can still use a function and the function can now return a jQuery Promise to delay loading of the map image or tile. Want to calculate a Mandlebrot image in a JavaScript web worker without blocking user interaction? Return a new jQuery.Deferred() and call resolve when you're done!

            Mobile

            This version has better mobile support including pinch zoom on iOS and Android 3+ as well as other bug fixes for mobile devices.

            Don't worry about $.geo.proj so much

            You can now send either geodetic (lon, lat) or projected (x, y) coordinates to any library function and it will return accordingly if you stay on the default web mercator projection. You should still set it to null or implement the (to|from)GeodeticPos functions if you need to change projections.

            Breaking

            There is one deprecation (a service object property will be renamed in beta) and one minor breaking change.

            To align this API with HTML itself, the getUrl property on service objects will be renamed to src. Using either src or getUrl will work for this alpha release but getUrl will be removed for beta. Please update any map services to use the new src property when you're defining them.

            Also on service objects, the initial opacity and visibility are in a property of the service object itself named style. Your old services will still function but ones you may expect to be hidden initially will be visible until you update the service object.

            To exemplify both of these changes, instead of:

            {
              type: "tiled",
              getUrl: function( view ) { return ""; },
              visibility: "hidden"
            }
            you should write:
            {
              type: "tiled",
              src: function( view ) { return ""; },
              style: { visibility: "hidden" }
            }

            Everything else

            With over 60 commits, there are more features and bug fixes to write about. If you dare to click the link below (or read the README file on the project's GitHub page) you can get a better idea of what went into this build. This is the last alpha release (!) and the path to beta will add unit testing, a better build process, and smaller, more refined source code. Thanks for all your support!

            * geomap - [bug] changing the tilingScheme doesn't update pixelSize, maxPixelSize, center or centerMax
            * geomap - [bug] shingled services throw exception during resize
            * docs - geomap - axisLayout option
            * geomap - axisLayout option
            * docs - upgrade to jQuery Mobile rc3
            * docs - allow page refreshing
            * docs - geomap - more modes: measureDistance, measureArea, static
            * docs - geomap - append label argument
            * docs - geomap - toPixel/toMap should take all coordinate dimensions like the proj functions
            * geomap - toPixel/toMap should take all coordinate dimensions like the proj functions
            * geomap - move the drawing container instead of individual points during pan
            * geomap - [bug] drawStyle resets after window resize
            * geomap - append label argument
            * docs - geomap - measureLabels option
            * geomap - measureLabels option
            * geomap - measureDistance mode
            * geomap - measureArea mode
            * docs - geomap - service-level shapeStyle
            * docs - geomap - getUrl string option
            * geomap - [bug] create doesn't clear drawing shapes
            * docs - geomap - service-level shapes
            * docs - geo - detect geodetic coordinates and call $.geo.proj automatically, don't require devs to set $.geo.proj to null
            * docs - geomap - add projection section explaining how bbox & center affect map unit type
            * docs - geomap - rename getUrl to src
            * docs - geomap - scroll option
            * docs - geomap - pannable option
            * geomap - src string option
            * examples - string service src
            * geomap - [bug] map tracks mouse when not panning if click on other elements
            * geomap - pannable option
            * geomap - scroll option
            * geomap - [bug] shapesContainer is being cleared twice during mouse wheel zoom
            * geomap - support pinch zoom on iOS
            * docs - geo - add recenter function for bbox
            * geomap - static mode
            * docs - geomap - allow Deferred or Promise as return value from src function
            * geomap - [bug] widget factory merges first service with default sometimes causing exceptions with shingled services
            * geomap - allow Deferred or Promise as return value from src function
            * geomap - [bug] resize event triggered too many times during resize
            * geomap - service-level shapes
            * geomap - service-level find
            * geographics - add a resize method, call from geomap.resize
            * geo - add recenter function for bbox
            * geomap - [bug] errors creating second un-tiled map after destroying a first on same element
            * geomap - refresh shouldn't request new images if the map element is hidden
            * geomap - [bug] delayed multitouch isn't nearly as smooth as true multitouch
            * geomap - [bug] tiled pinch zoom isn't smooth
            * geo - detect geodetic coordinates and call $.geo.proj automatically, don't require devs to set $.geo.proj to null
            * geomap - [bug] mouse wheel doesn't work with jQuery 1.7
            ** upgrade to latest jquery.mousewheel plugin
            * geomap - service object visibility and opacity options should be moved to a style property
            * geomap - use _currentServices in all functions unless we actually need to update the public options services object
            * geomap - don't change user's service objects in opacity/toggle
            * geomap - show attr text
            * docs - geomap - selector argument to find method
            * geomap - selector argument to find method
            * geomap - pan mode should use a hand cursor by default
            * geomap - [bug] only services that have finished refreshing move when the user pans
            ** for a4: hide unfinished services
            * geomap - [bug] a user can mess with the center option, e.g., convert numbers to strings, and it can wreck havoc with map state
            * geomap - [bug] zoom option doesn't return proper values for shingled services
            * geomap - [bug] non-tiled maps can zoom out past zoom 0
            * geomap - don't request tiles that are -y index
            * geomap - [bug] initializing tiled map by non-geodetic bbox always causes zoom level 0
            * docs - geomap - empty string needed for label element
            * geomap - [bug] double tap to end shapes adds two points before ending the shape, in different places
            * geomap - [bug] lifting fingers after pinch zoom in drawLineString or drawPolygon modes sometimes adds fake visual coordinate on touch point last lifted
            * docs - upgrade to jQuery 1.7.2
            * geomap - [bug] scroll=off doesn't zoom map but also doesn't allow document scroll
            * geomap - [bug] changing mode does not reset measure drawing
            * geomap - [bug] jQuery UI Widget Factory no longer passes pageX & pageY event properties during _trigger when using jQuery 1.7
            ** upgrade to Widget Factory 1.8.17
            * examples - all demo (shingled)
            * docs - geomap - custom modes
            * examples - all demo (tiled)

            Alpha 3 released!

            jQuery Geo 1.0 Alpha 3 is mostly about sketching!

            • new modes: drawPoint, drawLineString, and drawPolygon allow users to draw on your map
            • new event: shape triggers anytime a user draws a feature
            • new style option: drawStyle lets you change how the shapes look while being drawn

            It's also about geometry functions!

            • $.geo's center, height/width, expandBy, scaleBy & reaspect functions operate on bounding boxes
            • $.geo's bbox, distance, contains & centroid functions operate on geometries

            Many examples have more class and now link to jsFiddles to further explain what's going on!

            And a tiny bit about size

            jQuery Geo is now hosted on a CDN with gzip enabled bringing the entire library to your neighborhood at under 18k.

            Breaking

            There are some minor breaking changes to make the API more consistent.

            • The getPixelSize function is now a read-only option named pixelSize:
              $( "#map" ).geomap( "option", "pixelSize" );
            • The shapeStyle function is also now an option, e.g.:
              $( "#map" ).geomap( "option", "shapeStyle", { color: "red" } );
            • The boolean visible property on service objects is now the visibility property found in CSS and geomap styles and can be "visible" or "hidden":
              $( "#map" ).geomap( { services: [ { id: "roads", visibility: "hidden", ... } ] } );

            Edge

            The links above will always point to the latest stable release. However, you can test the most recently committed docs, code & demos by heading over to the test release.

            Test docs & demos

            Thanks!

            AppGeo-geo-f763e47/README.md0000664000175000017500000004136712005347446014245 0ustar daviddavid# jQuery Geo After years of internal development, we are pleased to bring our JavaScript map widget and spatial analysis tools to the open-source world in the form of a jQuery plugin. ## Getting Started Using jQuery Geo requires adding one element, including one script (apart from jQuery itself) and calling one function. The following copy-and-paste snippet will help you get started. ```html
            ``` You can also download the latest release as a [minified JavaScript file][min] or a [full, uncompressed one][max]. [min]: http://code.jquerygeo.com/jquery.geo-1.0b1.min.js [max]: http://code.jquerygeo.com/jquery.geo-1.0b1.js ## Documentation The latest docs are hosted at: http://jquerygeo.com Release and other announcements via @jQueryGeo on Twitter: https://twitter.com/jQueryGeo News and smaller updates via @ryanttb on Twitter: https://twitter.com/ryanttb ## Contributing In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [grunt](https://github.com/cowboy/grunt). ## Release History ### 1.0b1 (2012-07-30) * geographics - use canvas compositing for Polygons with holes * geographics - [bug] on polygons with holes, stroke draws a line from exterior ring to interior one * docs - geomap - trigger a shape event when a user finishes measuring * geomap - trigger a shape event when a user finishes measuring * geomap - [bug] elements inside the map div lose their position setting * geomap - trigger bboxchange when we update the map size after the window resizes * geomap - [bug] multiple map widgets share the same compiled measureLabels template names and overwrite each other * examples - inset map/multiple maps example * geomap - [bug] in zoom mode, dragging from bottom-right to top-left draws box but doesn't zoom * geomap - [bug] any mouse down triggers refresh, even without pan * cdn - fix caching ** Cache-Control header max-age set to 5 years ** remove Expires header * geomap - upgrade to jsrender 1.0pre * deploy - build releases using grunt * deploy - make a package for new jQuery plugin directory ** https://github.com/jquery/plugins.jquery.com/blob/master/docs/package.md * deploy - lint JavaScript files * docs - geomap - dragBbox mode * docs - geo - polygonize function for bbox * geo - polygonize function for bbox * geomap - dragBbox mode * docs - geomap - shift option (default, zoom, dragBbox, off) * geomap - shift option (default, zoom, dragBbox, off) * docs - geomap - loadstart, loadend events * docs - geomap - allow append to take an array of shapes * docs - geomap - allow remove to take an array of shapes * docs - geomap - improve services option documentation * geomap - clamp measure labels to [0, 0] * geo - clamp centroid to bbox * geomap - measure label for polygon should be in centroid * geomap - merge interactive pan and zoom into one, faster system (pan/zoom rewrite) * geomap - [bug] iOS - panning is visually jumpy but settles on the correct bbox in the end * geomap - pinch-zoom doesn't follow user's fingers close enough when scaling * geomap - [bug] pinch zoom on iPad 2 (iOS 5) doesn't refresh tiles when zooming out * geomap - request new image in shingled service during interactive pan * geomap - [bug] zoom in more than once with zoom method moves tiles to the wrong spot * geomap - [bug] only services that have finished refreshing move when the user pans * geomap - [bug] map panning is jumpy, appears to be related to shapes and/or drawing context * geomap - [bug] pan sometimes lags on first drag * geomap - tiled data-scaleOrigin should be stored as an array * geomap - android - [bug] cannot always pan map after appending shapes * geomap - android - browser stops pan/zoom after 7 logos on logo demo * geomap - [bug] mouse wheel on bad or missing tile doesn't zoom out on first rotate * geomap - increase mobile performance by 9000 * docs - geomap - add argument to refresh to force reload of images for dynamic data * docs - geomap - allow service-level refresh * docs - geomap - zoomMax option (tiled & shingled) * docs - geo - include method for bbox * geomap - bboxMax should reset center & pixelSize * geomap - [bug] initializing center, zoom, & bbox doesn't set all properties * geo - [bug] polygonize doesn't return valid polygon when using geodetic coordinates * geomap - [bug] dragBbox doesn't include the bbox property in the shape * geomap - dragBbox should send a Point (with bbox) for single clicks * docs - geomap - dragCircle mode * geo - include method for bbox * geomap - dragCircle mode * geomap - [regression] refresh & toggle methods no longer keep original service objects in sync * geomap - [bug] when a singled image hasn't loaded after pan and you double click on empty space, the zoomed bbox seems wrong * geomap - allow service-level refresh * geographics - remove the blit canvas from the DOM, i.e., don't attach * geomap - don't initialze service-level geographics until they're used * geomap - add argument to refresh to force reload of images (in case of dynamic data) * geomap - loadstart, loadend events * geomap - allow append to take an array of shapes * geomap - allow remove to take an array of shapes * geomap - zoomMax option * geomap - [bug] cannot interact with other elements on the page on iOS after panning the map (#71) * geomap - iOS - [bug] after one finger is removed, stop processing as if multitouch is still on * geomap - dumb high-precision mice down on tiled maps ** otherwise, the high precision rounds down to zero change in zoom * geomap - use linear distance for pinch zoom calculation * docs - geomap - zoomMin option * geomap - zoomMin option * docs - geomap - use MapQuest Open by default; can't deny that it looks much nicer * geomap - use MapQuest Open by default; can't deny that it looks much nicer * docs - geomap - rename dragBbox to dragBox * geomap - rename dragBbox to dragBox * geomap - [bug] error using tiled deferred services ### 1.0a4 (2012-02-19) * geomap - [bug] changing the tilingScheme doesn't update pixelSize, maxPixelSize, center or centerMax * geomap - [bug] shingled services throw exception during resize * docs - geomap - axisLayout option * geomap - axisLayout option * docs - upgrade to jQuery Mobile rc3 * docs - allow page refreshing * docs - geomap - more modes: measureDistance, measureArea, static * docs - geomap - append label argument * docs - geomap - toPixel/toMap should take all coordinate dimensions like the proj functions * geomap - toPixel/toMap should take all coordinate dimensions like the proj functions * geomap - move the drawing container instead of individual points during pan * geomap - [bug] drawStyle resets after window resize * geomap - append label argument * docs - geomap - measureLabels option * geomap - measureLabels option * geomap - measureDistance mode * geomap - measureArea mode * docs - geomap - service-level shapeStyle * docs - geomap - getUrl string option * geomap - [bug] create doesn't clear drawing shapes * docs - geomap - service-level shapes * docs - geo - detect geodetic coordinates and call $.geo.proj automatically, don't require devs to set $.geo.proj to null * docs - geomap - add projection section explaining how bbox & center affect map unit type * docs - geomap - rename getUrl to src * docs - geomap - scroll option * docs - geomap - pannable option * geomap - src string option * examples - string service src * geomap - [bug] map tracks mouse when not panning if click on other elements * geomap - pannable option * geomap - scroll option * geomap - [bug] shapesContainer is being cleared twice during mouse wheel zoom * geomap - support pinch zoom on iOS * docs - geo - add recenter function for bbox * geomap - static mode * docs - geomap - allow Deferred or Promise as return value from src function * geomap - [bug] widget factory merges first service with default sometimes causing exceptions with shingled services * geomap - allow Deferred or Promise as return value from src function * geomap - [bug] resize event triggered too many times during resize * geomap - service-level shapes * geomap - service-level find * geographics - add a resize method, call from geomap.resize * geo - add recenter function for bbox * geomap - [bug] errors creating second un-tiled map after destroying a first on same element * geomap - refresh shouldn't request new images if the map element is hidden * geomap - [bug] delayed multitouch isn't nearly as smooth as true multitouch * geomap - [bug] tiled pinch zoom isn't smooth * geo - detect geodetic coordinates and call $.geo.proj automatically, don't require devs to set $.geo.proj to null * geomap - [bug] mouse wheel doesn't work with jQuery 1.7 ** upgrade to latest jquery.mousewheel plugin * geomap - service object visibility and opacity options should be moved to a style property * geomap - use currentServices in all functions unless we actually need to update the public options services object * geomap - don't change user's service objects in opacity/toggle * geomap - show attr text * docs - geomap - selector argument to find method * geomap - selector argument to find method * geomap - pan mode should use a hand cursor by default * geomap - [bug] only services that have finished refreshing move when the user pans ** for a4: hide unfinished services * geomap - [bug] a user can mess with the center option, e.g., convert numbers to strings, and it can wreck havoc with map state * geomap - [bug] zoom option doesn't return proper values for shingled services * geomap - [bug] non-tiled maps can zoom out past zoom 0 * geomap - don't request tiles that are -y index * geomap - [bug] initializing tiled map by non-geodetic bbox always causes zoom level 0 * docs - geomap - empty string needed for label element * geomap - label divs should have class="geo-label" & style="position: absolute;" * geomap - [bug] double tap to end shapes adds two points before ending the shape, in different places * geomap - [bug] lifting fingers after pinch zoom in drawLineString or drawPolygon modes sometimes adds fake visual coordinate on touch point last lifted * docs - upgrade to jQuery 1.7.2 * geomap - [bug] scroll=off doesn't zoom map but also doesn't allow document scroll * geomap - [bug] changing mode does not reset measure drawing * geomap - [bug] jQuery UI Widget Factory no longer passes pageX & pageY event properties during trigger when using jQuery 1.7 ** upgrade to Widget Factory 1.8.17 * examples - all demo (shingled) * docs - geomap - custom modes * examples - all demo (tiled) ### 1.0a3 (2011-11-01) * docs - geomap - more modes: zoom, drawPoint, drawLineString, drawPolygon * geomap - [bug] tiles do not show when pixel sizes are near or lower than 1.0 * geo - cache bbox as geoBbox to match namespacing convention started by jQuery Mobile * docs - geo - initial bbox operations: center, height/width, expandBy, scaleBy & reaspect functions * docs - geo - initial geometry operations: bbox, distance, contains, centroid * docs - geomap - shape event * docs - geomap - refresh argument in append, remove & empty * docs - geomap - document the resize method * docs - launch jquerygeo.com * docs - upgrade to jQuery Mobile b3 * docs - services - remove id property, explain the class property * docs - rename getPixelSize to just pixelSize * docs - services - change visible to visibility so it matches shapeStyle & CSS * docs - geomap - allow child selector syntax to target service elements with toggle & opacity methods * geomap - split servieTypes to different files * geomap - add data-geo-service to all service container elements, set to type of service * geomap - add data-geo-map to map divs initialized with geomap, remove on destroy * geomap - allow child selector syntax to target service elements with toggle & opacity methods * geomap - [bug] toggle does not refresh the map services being shown for the first time * geomap - [bug] destroy keeps window resize handler * geomap - [bug] destroy erases content originally inside map div * geomap - serviceType objects' destroy method isn't being called * geomap - [bug] destroyed geomaps remember appended shapes * docs - geomap - zoom method * geomap - zoom method * geo - calculate bbox in projected coordinates * docs - proj - mention that Geodetic methods can also do bbox * geo - geometry - bbox function * docs - geomap - destroy method * geo - bbox - center function * geo - bbox - height/width function * geo - bbox - expandBy function * geo - bbox - scaleBy function * geo - bbox - reaspect function * docs - geomap - drawStyle option * geomap - [bug] shapeStyle not maintained after resize * geomap - [bug] second drag while in inertial pan causes map to jump back * geomap - drawPoint mode * geomap - drawLineString mode * geomap - refreshShapes should check bbox cache before drawing * geomap - drawPolygon mode * geomap - port zoom mode * geomap - port shift-zoom mode for pan & draw modes * geo - geometry - distance function * examples - distance * geomap - rename getPixelSize to just pixelSize * geomap - [bug] zoom method doesn't work with shingled map * geomap - store service state data as jQuery data on serviceContainer element * geo - geometry - contains function * geomap - rename service.visible to visibility having either "visible" or "hidden" values * geo - geometry - centroid function * geomap - make service id property optional, add HTML id to serviceContainer if present * geomap - append should cache the shape's bbox (instead of the bbox function) * geomap - remove should remove the shape's bbox cache * geomap - empty should remove the bbox cache for all shapes * geomap - make the refresh argument in append public, add one to remove & empty * geomap - disable shape redraw during interactive zoom if more than 255 shapes * geomap - [bug] shape bbox culling hides shapes that are partially on screen & should be drawn * docs - geomap - make pixelSize a read-only option instead of a function * geomap - make pixelSize a read-only option instead of a function * docs - geomap - make shapeStyle an option * geomap - make shapeStyle an option * examples - rewrite shapeStyle example ### 1.0a2.5 (2011-08-03) * geomap - find - [bug] does not handle GeoJSON features * geomap - find - allow for 0 pixel tolerance * geomap - find - check for bbox on non-Point geometries before getting too specific * geo - bbox - cache shape bboxes * docs - do not suggest that it's ok to change the geometry now that we're caching bbox * geomap - jsperf test of bbox query vs. geom query on point data * geographics - [bug] 0 opacity acts as full opacity * geomap - add opacity to service type objects & call from geomap's opacity method * geomap - add toggle to service type objects & call from geomap's toggle method * geo.proj - update bundled web mercator projection code (removed 150 lines of code) * geomap - auto-handle window resize events * docs/geomap - scale map according to cursor location instead of re-centering during double-click zoom * geomap - iOS - [bug] second tap can be anywhere & cause a zoom * geomap - shingled - [bug] map doesn't resize correctly * examples - geomap drawStyle option ### 1.0a2 (2011-06-29) * geomap - Support dynamic map services * geomap - [BUG] geomap causes a script error if jQuery UI is already included * docs - Document shape methods * geomap - [BUG] Port of soft double-click does not work * geomap - [BUG] Cannot see dev-supplied inner content if not set to rel/abs position * geomap - Add mobile test page * geographics - Port graphic code from internal control * geomap - Implement append method * geographics - drawArc should use style's width and height and only take center as an argument * geomap - Document and implement the public refresh method * geomap - Implement shapeStyle method * geographics - Draw points as rounded rectangles via width, height & borderRadius properties on shapeStyle, drop oval functionality * geomap - Remove the pixels property from position events and add the type property to make the event argument a true GeoJSON Point * proj - support up to four dimentional array to convert MultiPolygon coordinates in one shot * proj - add functions to convert individual positions that developers can re-implement for their own projection * geomap - implement remove method * geomap - implement find method * geomap - [bug] toPixel should round pixel values * geomap - [bug] GeometryCollection shapes do not draw with their parent shape's style * geomap - implement empty method ### 1.0a1 (2011-05-09) * docs - Document a new interface to our internal map control * geomap - Port interactive map widget base to jQuery UI widget factory * geomap - Support tiled map services ## License Copyright (c) 2012 Applied Geographics, Inc. Project lead by Ryan Westphal Licensed under the MIT, GPL licenses.