This is a wiki for a reason. Anyone can contribute. If you see something that is inaccurate or can be improved, don't ask that it be fixed--just improve it.
[ Disclaimer, Create new user --- Wiki markup help, Install P99 ]

MediaWiki:LocMaps.js

From Project 1999 Wiki
Revision as of 19:06, 30 July 2019 by Loramin (Talk | contribs)

Jump to: navigation, search

Note: After saving, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Clear the cache in Tools → Preferences
// I need filter and map!
// TODO: Move these somewhere more central.

// Polyfill from:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter#Polyfill
if (!Array.prototype.filter){
  Array.prototype.filter = function(func, thisArg) {
    'use strict';
    if ( ! ((typeof func === 'Function' || typeof func === 'function') && this) )
        throw new TypeError();
   
    var len = this.length >>> 0,
        res = new Array(len), // preallocate array
        t = this, c = 0, i = -1;
    if (thisArg === undefined){
      while (++i !== len){
        if (i in this){
          if (func(t[i], i, t)){
            res[c++] = t[i];
          }
        }
      }
    }
    else{
      while (++i !== len){
        if (i in this){
          if (func.call(thisArg, t[i], i, t)){
            res[c++] = t[i];
          }
        }
      }
    }
   
    res.length = c; // shrink down array to proper size
    return res;
  };
}

// Polyfil from:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#Polyfill

if (!Array.prototype.map) {

  Array.prototype.map = function(callback/*, thisArg*/) {

    var T, A, k;

    if (this == null) {
      throw new TypeError('this is null or not defined');
    }

    var O = Object(this);

    var len = O.length >>> 0;
    if (typeof callback !== 'function') {
      throw new TypeError(callback + ' is not a function');
    }

    if (arguments.length > 1) {
      T = arguments[1];
    }

    A = new Array(len);

    k = 0;

    while (k < len) {
      var kValue, mappedValue;
      if (k in O) {
        kValue = O[k];
        mappedValue = callback.call(T, kValue, k, O);
        A[k] = mappedValue;
      }
      k++;
    }
    return A;
  };
}

(function() {

  var zones = {
    'Ak\'Anon': {
      height: 614,
      image: 'Akanon.jpg',
      interval: 250,
      maxX: 250,
      maxY: 2250,
      minX: 1250,
      minY: 250,
      width: 384,
      zeroX: 62,
      zeroY: 567,
      zoomX: 0.25,
      zoomY: 0.25
    },
    // TODO: This duplicates the "Gorge of King Xorbb" entry; make an aliases array or something
    'Beholder\'s Maze': {
      height: 357,
      image: 'Map_gxorbb.jpg',
      maxX: 1000,
      maxY: 1500,
      minX: -2000,
      minY: -1500,
      interval: 500,
      width: 400,
      zeroX: 112.5,
      zeroY: 173.5,
      zoomX: 0.12545,
      zoomY: 0.12545
    },
    'Butcherblock Mountains': {
      height: 480,
      image: 'Butcherblock-v3.jpg',
      interval: 1000,
      maxX: 3000,
      maxY: 3000,
      minX: 3000,
      minY: 3000,
      width: 500,
      zeroX: 251,
      zeroY: 240,
      zoomX: .073,
      zoomY: .0727
    },
    'East Commonlands': {
      height: 279,
      image: 'Map_eastcommons.jpg',
      interval: 1000,
      maxX: 5000,
      maxY: 2000,
      minX: 2000,
      minY: 2000,
      width: 642,
      zeroX: 469.3,
      zeroY: 133,
      zoomX: 0.0887,
      zoomY: 0.0887
    },
    'Eastern Plains of Karana': {
      height: 554,
      image: 'Map_ekarana.jpg',
      interval: 1000,
      maxX: 2000,
      maxY: 2000,
      minX: 4000,
      minY: 5000,
      width: 450,
      zeroX: 119.5,
      zeroY: 193,
      zoomX: 0.0793,
      zoomY: 0.0788
    },
    'Eastern Wastes': {
      height: 452,
      image: 'Map_eastern_wastes.jpg',
      interval: 1000,
      maxX: 7000,
      maxY: 1000,
      minX: 6000,
      minY: 9000,
      width: 550,
      zeroX: 284,
      zeroY: 62,
      zoomX: 0.038,
      zoomY: 0.038
    },
    'Erudin': {
      height: 663,
      image: 'Erudin.jpg',
      interval: 100,
      maxX: 0,
      maxY: -600,
      minX: -500,
      minY: -1500,
      width: 370,
      zeroX: 29,
      zeroY: -336,
      zoomX: 0.63,
      zoomY: 0.624
    },
    'Erud\'s Crossing': {
      height: 452,
      image: 'Map_erudsxing.jpg',
      maxX: 2200,
      maxY: -400,
      minX: 400,
      minY: -2000,
      interval: 200,
      width: 550,
      zeroX: 667.9,
      zeroY: -121,
      zoomX: 0.305,
      zoomY: 0.272
    },
    'Firiona Vie': {
      height: 555,
      image: 'Map_firionavie.jpg',
      interval: 1000,
      maxX: 6000,
      maxY: 5000,
      minX: 4000,
      minY: 5000,
      width: 540,
      zeroX: 324,
      zeroY: 282,
      zoomX: 0.053,
      zoomY: 0.0525
    },
    'Gorge of King Xorbb': {
      height: 357,
      image: 'Map_gxorbb.jpg',
      maxX: 1000,
      maxY: 1500,
      minX: -2000,
      minY: -1500,
      interval: 500,
      width: 400,
      zeroX: 112.5,
      zeroY: 173.5,
      zoomX: 0.12545,
      zoomY: 0.12545
    },
    'Greater Faydark': {
      height: 532,
      image: 'Greaterfaydark.jpg',
      interval: 1000,
      maxX: 3000,
      maxY: 2000,
      minX: 3000,
      minY: 2000,
      width: 550,
      zeroX: 269,
      zeroY: 255,
      zoomX: .089,
      zoomY: .089
    },
    'Grobb': {
      height: 456,
      image: 'Grobb.jpg',
      interval: 200,
      maxX: 200,
      maxY: 600,
      minX: 800,
      minY: 200,
      width: 550,
      zeroX: 109,
      zeroY: 341,
      zoomX: 0.442,
      zoomY: 0.439
    },
    'Halas': {
      height: 434,
      image: 'Zone_halas.jpg',
      interval: 200,
      maxX: 600,
      maxY: 800,
      minX: 600,
      minY: 200,
      width: 550,
      zeroX: 252.2,
      zeroY: 346,
      zoomX: 0.458,
      zoomY: 0.46
    },
    'Kerra Island': {
      height: 504,
      image: 'Kerra.jpg',
      interval: 500,
      maxX: 1000,
      maxY: 1500,
      minX: 1000,
      minY: 1000,
      width: 415,
      zeroX: 146.5,
      zeroY: 277,
      zoomX: 0.238,
      zoomY: 0.238
    },
    'Kithicor Forest': {
      height: 333,
      image: 'Map_kithicor.jpg',
      interval: 1000,
      maxX: 5000,
      maxY: 3000,
      minX: 1000,
      minY: 2000,
      width: 560,
      zeroX: 449.5,
      zeroY: 198,
      zoomX: 0.0875,
      zoomY: 0.089
    },
    'Lake Rathetear': {
      height: 450,
      image: 'Map_lakerathetear.jpg',
      interval: 1000,
      maxX: 3000,
      maxY: 5000,
      minX: 3000,
      minY: 2000,
      width: 450,
      zeroX: 247.3,
      zeroY: 342.4,
      zoomX: 0.0755,
      zoomY: 0.0755
    },
    'Nektulos Forest': {
      height: 519,
      image: 'Map_nektulos.jpg',
      interval: 1000,
      maxX: 2000,
      maxY: 3000,
      minX: 2000,
      minY: 3000,
      width: 271,
      zeroX: 137.4,
      zeroY: 264.8,
      zoomX: 0.091,
      zoomY: 0.091
    },
    'Northern Felwithe': {
      height: 385,
      image: 'Nfelwithe.jpg',
      interval: 100,
      maxX: 100,
      maxY: 400,
      minX: 800,
      minY: 300,
      width: 589,
      zeroX: 109,
      zeroY: 217,
      zoomX: 0.547,
      zoomY: 0.55
    },
    'Northern Karana': {
      height: 476,
      image: 'Map_nkarana.jpg',
      interval: 1000,
      maxX: 4000,
      maxY: 2000,
      minX: 3000,
      minY: 5000,
      width: 500,
      zeroX: 263.3,
      zeroY: 135.5,
      zoomX: 0.071,
      zoomY: 0.0705
    },
    'North Qeynos': {
      height: 319,
      image: 'Zone_nqeynos.jpg',
      interval: 200,
      maxX: 400,
      maxY: 400,
      minX: 600,
      minY: 200,
      width: 458,
      zeroX: 204,
      zeroY: 189,
      zoomX: .39,
      zoomY: .39
    },
    'Oggok': {
      height: 440,
      image: 'Oggok.jpg',
      interval: 200,
      maxX: 1000,
      maxY: 800,
      minX: 400,
      minY: 400,
      width: 536,
      zeroX: 361,
      zeroY: 305,
      zoomX: .3155,
      zoomY: .315
    },
    'Paineel': {
      height: 520,
      image: 'Paineelin.jpg',
      interval: 100,
      maxX: 1000,
      maxY: 1400,
      minX: 0,
      minY: 400,
      width: 492,
      zeroX: 507,
      zeroY: 716,
      zoomX: 0.5215,
      zoomY: 0.5212
    },
    'Qeynos Hills': {
      height: 575,
      image: 'Qeynoshills.jpg',
      interval: 1000,
      maxX: 2000,
      maxY: 6000,
      minX: 2000,
      minY: 1000,
      width: 324,
      zeroX: 136,
      zeroY: 516.3,
      zoomX: 0.0945,
      zoomY: 0.094
    },
    'Rathe Mountains': {
      height: 660,
      image: 'Zone_rathemtns.jpg',
      interval: 1500,
      maxX: 3000,
      maxY: 7500,
      minX: 4500,
      minY: 3000,
      width: 490,
      zeroX: 219.5,
      zeroY: 453.5,
      zoomX: 0.0707,
      zoomY: 0.0702
    },
    'Rivervale': {
      height: 540,
      image: 'Rivervale.jpg',
      interval: 200,
      maxX: 200,
      maxY: 600,
      minX: 800,
      minY: 400,
      width: 484,
      zeroX: 85,
      zeroY: 287,
      zoomX: 0.522,
      zoomY: 0.517
    },
    'South Kaladim': {
      height: 341,
      image: 'Skaladim.jpg',
      interval: 100,
      maxX: 600,
      maxY: 500,
      minX: -500,
      minY: -200,
      width: 550,
      zeroX: 291,
      zeroY: 238,
      zoomX: 0.51,
      zoomY: 0.52
    },
    'South Qeynos': {
      height: 426,
      image: 'Zone_sqeynos.jpg',
      interval: 200,
      maxX: 200,
      maxY: 600,
      minX: -600,
      minY: -400,
      width: 423,
      zeroX: 107,
      zeroY: 259,
      zoomX: .395,
      zoomY: .39,
    },
    'Southern Felwithe': {
      height: 377,
      image: 'Sfelwithe.jpg',
      interval: 100,
      maxX: 0,
      maxY: 800,
      minX: 900,
      minY: 0,
      width: 400,
      zeroX: 155,
      zeroY: 473,
      zoomX: 0.58,
      zoomY: 0.584
    },
    'Stonebrunt Mountains': {
      height: 619,
      image: 'Map_stonebrunt_mountains.jpg',
      interval: 1000,
      maxX: 4000,
      maxY: 5000,
      minX: 4000,
      minY: 6000,
      width: 529,
      zeroX: 253.3,
      zeroY: 285.5,
      zoomX: 0.0578,
      zoomY: 0.0576
    },
    'Surefall Glade': {
      height: 539,
      image: 'Surefallglade.jpg',
      interval: 200,
      maxX: 400,
      maxY: 1000,
      minX: 800,
      minY: 800,
      width: 330,
      zeroX: 97,
      zeroY: 306,
      zoomX: 0.323,
      zoomY: 0.32
    },
    'The Hole': {
      height: 465,
      image: 'Map_thehole.jpg',
      interval: 200,
      maxX: 1200,
      maxY: 1200,
      minX: 1200,
      minY: 600,
      width: 600,
      zeroX: 292,
      zeroY: 292,
      zoomX: 0.261,
      zoomY: 0.261
    },
    'The Overthere': {
      height: 644,
      image: 'Map_overthere.jpg',
      interval: 1000,
      maxX: 4000,
      maxY: 4000,
      minX: 4000,
      minY: 4000,
      width: 600,
      zeroX: 284.5,
      zeroY: 318,
      zoomX: 0.0628,
      zoomY: 0.0628
    },
    'The Warrens': {
      height: 314,
      image: 'Warrens.jpg',
      interval: 200,
      maxX: 1200,
      maxY: 1200,
      minX: 1200,
      minY: 400,
      width: 550,
      zeroX: 263.9,
      zeroY: 222.5,
      zoomX: 0.2185,
      zoomY: 0.22
    },
    'Toxxulia Forest': {
      height: 537,
      image: 'Toxxulia.jpg',
      interval: 1000,
      maxX: 3000,
      maxY: 3000,
      minX: 2000,
      minY: 3000,
      width: 441,
      zeroX: 262.3,
      zeroY: 261.5,
      zoomX: 0.0915,
      zoomY: 0.091
    },
    'Upper Guk': {
      height: 644,
      image: 'Upperguk.jpg',
      interval: 250,
      maxX: 750,
      maxY: 1500,
      minX: 500,
      minY: 0,
      width: 450,
      zeroX: 234,
      zeroY: 564,
      zoomX: 0.324,
      zoomY: 0.323
    },
    'West Commonlands': {
      height: 284,
      image: 'Zone_westcommons.jpg',
      interval: 1000,
      maxX: 5000,
      maxY: 2000,
      minX: 2000,
      minY: 2000,
      width: 649,
      zeroX: 435.5,
      zeroY: 126.5,
      zoomX: 0.096,
      zoomY: 0.096
    },
    'Western Plains of Karana': {
      height: 422,
      image: 'Zone_westkarana.jpg',
      interval: 1000,
      maxX: 0,
      maxY: 2000,
      minX: 17000,
      minY: 5000,
      width: 1058,
      zeroX: 21.5,
      zeroY: 107,
      zoomX: 0.06375,
      zoomY: 0.0641
    }
  };

// TODO: Add support for cropping maps that have multiple maps.
// For instance, the following CSS styles show only one of the three maps for Erudin Palace:
// background-image:url(/images/Erudinpalace.jpg); background-position: 250px 0px; width: 275px; height: 272px
// Figure out how to make the Xs line up with those styles added

  /**
   * This is the data for the alternate maps for zones.  The code checks their min/max X/Y
   * properties to see if the loc(s) fit within them, and if so the alternate map will be used
   * instead.
   *
   * Since a zone can have multiple alternate maps each value in this object is an array.
   */
  var alternates = {
    'Erudin':{
      height: 564,
      image: 'Erudindocks.jpg',
      interval: 100,
      maxX: 300,
      maxY: 200,
      minX: -400,
      minY: -400,
      width: 450,
      zeroX: 122,
      zeroY: 223,
      zoomX: 0.731,
      zoomY: 0.731
    },
    'Greater Faydark': {
      height: 519,
      image: 'Kelethin.jpg',
      interval: 200,
      maxX: 1000,
      minX: -700,
      maxY: 1200,
      minY: -800,
      width: 442,
      zeroX: 237,
      zeroY: 312,
      zoomX: 0.264,
      zoomY: 0.264
    }
  }

  var locIsWithinAlternateData = function(loc, alternateData) {
    return loc.x < alternateData.maxX &&
           loc.x > alternateData.minX &&
           loc.y < alternateData.maxY &&
           loc.y > alternateData.minY;
  }
  var getZoneData = function(zoneName, locs) {
    var zoneData = zones[zoneName];
    var zoneAlternates = alternates[zoneName];
    if (!zoneAlternates) return zoneData;

    // Handle no array case
    if (!zoneAlternates.length) zoneAlternates = [zoneAlternates];

    for (var i = 0; i < zoneAlternates.length; i++) {
      var alternateData = zoneAlternates[i];
      var allLocsAreWithin = true;
      // wish I had ES6 [].every
      $.each(locs, function(i, loc) {
        allLocsAreWithin = allLocsAreWithin && locIsWithinAlternateData(loc, alternateData);
      });
      if (allLocsAreWithin) return alternateData;
    };
    return zoneData;
  };

  /**
   * Extracts all of the locs (objects with x and y properties) from a provided
   * string such as:
   * "500, 200"
   * "(200, 300), (300, 200)"
  */
  var getLocs = function(locString) {
    return locString
      //.split(/(\(? *\+?\-?\d+, *\+?\-?\d+(?: ?, ?\+?\-?\d+)?\)?)/g)
      .split(/\D*(\d+\D*,\D*\d+)\D*/g)
      .filter(function(locBit) {
        return locBit.indexOf(',') != -1;
      }).map(function(locText) {
        var match = locText.match( /\(? *(\+?\-?\d+), *(\+?\-?\d+)\)?/);
        return {x: parseFloat(match[2]), y: parseFloat(match[1]) };
      })
  }

  /**
   * Draws a red "X" on the map at the provided coordinate
   */
  var makeX = function(x, y, zone) {
    $('img[alt="' + zone.image + '"]')
      .parent()
      .css({position: 'absolute'})
      .append(
        $('<div class="x">x</div>')
          .css({
            color: 'red',
            fontSize: '2em',
            fontWeight: 'bold',
            left: (zone.zeroX || 0) + x * -1 * (zone.zoomX || 0.1),
            position: 'absolute',
            top: (zone.zeroY || 0) + y * -1 * (zone.zoomY || 0.1)
          }));
  };

  /**
   * Adds a loc map to the page (presumably in response to a user
   * mousing over a loc map link)
   */
  var addMap = function($locTd, imageName, width, height) {
    if ($('.map-wrapper').length) return;

    var imageUrl = '/images/'+ imageName;
    // Allow local files for testing purposes
    if (imageName.indexOf('file') === 0) imageUrl = imageName;

    $locTd.append(
      '<div class="map-wrapper" style="position:relative">'+
        '<img alt="' + imageName + '" ' +
             'src="' + imageUrl + '" ' +
             'width="' + width + '" ' +
             'height="'+ height + '" ' +
             'class="thumbborder" ' +
             'title="' + imageName + '">' +
      '</div>'
    );
  }

  // Define two helper functions for building new zone definitions

  // 1) Use this function to find the correct 0,0 point
  window.testZeroZero = function(zone) {
    var $locTd = $('b:contains("Location:")').parent();
    $('.x').remove();
    $('img[alt="' + zone.image + '"]').show()
    addMap($locTd, zone.image, zone.width, zone.height);
    makeX(0, 0, zone);
  };

  // 2) Use this function to generate a grid of alignment of X's
  window.testGrid = function(zone) {
    var $locTd = $('b:contains("Location:")').parent();
    $('.x').remove();
    for (var x = zone.maxX; x >= zone.minX; x -= zone.interval) {
      for (var y = zone.maxY; y >= zone.minY; y -= zone.interval) {
        addMap($locTd, zone.image, zone.width, zone.height);
        makeX(x, y, zone);
      }
    };
  }

  try {
    // Get the mob's loc(s)
    var $locTd = $('b:contains("Location:")').parent();
    var locs = getLocs($locTd.text());
    if (!locs.length) return;

    // Find the zone name
    var $zoneTd = $('b:contains("Zone:")').parent().text();
    var zoneName = $zoneTd.split('Zone:')[1].trim();

    // Do we have data for that zone's map?
    var zone = getZoneData(zoneName, locs);
    if (!zone) return;  // If not, stop here

    // Add the mouseover link
    var $link = $(' <a href="#">(Show on Map)</a>');

    // When it's moused-over, show the map
    $link
      .on('mouseover', function(e) {
        addMap($locTd, zone.image, zone.width, zone.height);
        $.each(locs, function(i, loc) {
          makeX(loc.x, loc.y, zone);
        });
      })
      .on('mouseleave', function(e) {
        if (this.wasClicked) {
          this.wasClicked = false;
        } else {
          $('.map-wrapper').remove();
        }
        return false;
      })
      .on('click', function(e) {
        if ($(e.target).text() === '(Hide Map)') {
          $(e.target).text('(Show on Map)')
          $('.map-wrapper').remove();
        } else  {
          $(e.target).text('(Hide Map)')
          addMap($locTd, zone.image, zone.width, zone.height);
          $.each(locs, function(i, loc) {
            makeX(loc.x, loc.y, zone);
          });
          this.wasClicked = true;
        }
        return false;
      });

    $locTd.append($link)
  } catch (err) {/* Didn't work, move on */}


  })();