Initial commit
137
.gitignore
vendored
@ -1,130 +1,11 @@
|
||||
# Logs
|
||||
logs
|
||||
.DS_Store
|
||||
node_modules
|
||||
.yo-rc.json
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
gulptasks/upload.js
|
||||
downloads/*
|
||||
.eslintignore
|
||||
.eslintrc
|
||||
.tern-project
|
||||
dist/*
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
101
README.md
@ -1,4 +1,99 @@
|
||||
# blackdesert-somethinglovely-map
|
||||
Famme's BDO Tools - somethinglovely.net
|
||||
|
||||
For source, check back tomorrow!
|
||||
# Famme's BDO Tools
|
||||
|
||||
### somethinglovely.net by Famme (Discord: fffam)
|
||||
|
||||
An interactive map for Black Desert Online. The website has been sunset as a result of not being in a position to stay current with game updates.
|
||||
|
||||
Horses, crates & tradepack tools are just embeds for the following jsfiddle pages:
|
||||
|
||||
* **Horse Calculator:** https://jsfiddle.net/fffam/k5z99cus/embedded/result/
|
||||
* **Crate Calculator:** https://jsfiddle.net/fffam/8Ldoz5wz/embedded/result/
|
||||
* **Tradepack Reference:** https://jsfiddle.net/fffam/pL6us4kd/embedded/result/
|
||||
|
||||
All code & original assets are to be considered MIT-licensed (images within `horses` & `icons` are copyright Pearl Abyss Corp). You may use any of the code, or rehost the website in its entirety.
|
||||
|
||||
<hr>
|
||||
|
||||
## Installation
|
||||
|
||||
* Download the map tiles https://mega.nz/file/ThJA3BRD#KD-6R8Lm8d9MRZsl21BSe2HMrlpi72B9iMIKcRsoTs8 (100MB)
|
||||
* Host map tiles somewhere.
|
||||
* Clone repo
|
||||
* `npm install`
|
||||
* Search project for somethinglovely.net and replace with your own path to where your map tiles are being served from
|
||||
* If serving to the public, put it behind a cache (CloudFlare free tier works fine).
|
||||
|
||||
To run locally:
|
||||
|
||||
* `gulp`
|
||||
|
||||
To build (into dist folder):
|
||||
|
||||
* `gulp build`
|
||||
|
||||
## Updating data
|
||||
|
||||
The data is all in [data.json](src/data.json). Nodes are listed in custom object format, all other layers are in standard GeoJSON FeatureCollection format. Should all be pretty obvious once prettified.
|
||||
|
||||
## Updating map tiles
|
||||
|
||||
https://mega.nz/file/7t5yBTpb#kG8wK4gp6JKZf4W-qreqPQ8l9m0RdaowxDHBLk0rV8o (3.9GB) and https://mega.nz/file/b4pz3CBD#Fr9EWgL77kpCe2Iteai0lZhuS36YTJKaUt1NLw5f0BI (58KB).
|
||||
|
||||
#### Time estimates:
|
||||
|
||||
* 5 mins work
|
||||
* 1 hour wait to extract tiles
|
||||
* 10 mins work (more if you need to install WSL/bash)
|
||||
* 6 hour wait to convert to giant singular map png
|
||||
* 30 mins to combine in photoshop
|
||||
* 2 hour to split into leaflet tiles
|
||||
|
||||
#### Steps:
|
||||
|
||||
1. Download latest PAZ files (i.e. just patch game)
|
||||
2. Get paz_browser from BDO Data/PazExtractor and put it in BDO paz folder
|
||||
3. Run it and Search > mapdata_realexplore then extract mapdata_realexplore.xml and mapdata_realexplore2.xml
|
||||
4. Run it and extract `rader*.dds` (search `rader*.dds`, then press A to select all)
|
||||
5. Wait for extraction to finish (ETA: 60 minutes, set an alert)
|
||||
6. Put all of the dds map tiles into a folder called 'rader'
|
||||
7. Copy the 5 radar script files (radar-combine.sh, radar-combine-fast.sh, radar-convert.sh, radar-getbounds.js and radar-sort.js) into the folder above 'rader'
|
||||
8. In linux (probably WSL - https://docs.microsoft.com/en-us/windows/wsl/install-win10), make sure imagemagick is installed (sudo apt-get update followed by sudo apt-get install imagemagick)
|
||||
9. Increase the width/height/disk/memory limits in the ImageMagick policy.xml (probably in /etc/ImageMagick-6/). Change width/height from 16KP to 256KP. Change Memory from 256MiB to 16GiB. Change Disk to 16GiB.
|
||||
|
||||
10. Create the empty folders alongside rader:
|
||||
* rader-sorted
|
||||
* rader-slices
|
||||
|
||||
11. Put the blank.png in the same folder as radar-sort.sh
|
||||
|
||||
12. In bash, run the scripts in the following order (or chain execute them with &&):
|
||||
`radar-convert.sh` (converts the dds texture files to png. ETA: 20m)
|
||||
`radar-sort.sh` (copies the png tiles to a folder with new names that are 0-indexed.) ETA: 30m)
|
||||
`radar-combine-fast.sh` (uses imagemagick's montage to stitch the tiles together. ETA: 4 hours, run it overnight)
|
||||
**NOTES:**
|
||||
radar-getbounds.js is just to check the map grid bounds
|
||||
radar-combine-fast.sh is slow, but its just faster than the other version because it combines the tiles in strips as an intermediate step
|
||||
|
||||
13. Open Map (Combined).psb in photoshop
|
||||
|
||||
14. With the `map_{DATE}` layer selected, go Layer > Smart Objects > Relink to File and select the new map.png that was created from step 11. The original linked image path will probably be broken by default.
|
||||
|
||||
15. Adjust the layer mask for the `map` layer, and for the Ocean Overlay layer to make the map look good. Then save the file (Ctrl-S), then also export the file as a 100% JPEG (File > Save a Copy... > Select JPEG) and save as map.jpg
|
||||
|
||||
16. Run the slicer script to convert to leaflet map tiles:
|
||||
`./magick-slicer.sh map.jpg`
|
||||
|
||||
17. [OPTIONAL BUT ADVISED] Once sliced, optimise the filesizes of the tiles (using ImageOptim on OSX or an equivalent tool on Linux/Win)
|
||||
`find ./Map_files -type f -iname \*jpg -print0 | xargs -0 -t -n 100 /Applications/ImageOptim\ 2.app/Contents/MacOS/ImageOptim`
|
||||
|
||||
18. compress the files into a tarball
|
||||
`mv ./Map_files tiles-new`
|
||||
`tar -zcvf tiles-new.tar.gz tiles-new`
|
||||
|
||||
19. Upload tarbarll to server, then ssh into server and unpack the tarball
|
||||
`scp tiles-new.tar.gz username@somethinglovely.net:/home/www/somethinglovely.net/bdo`
|
||||
`tar xzvf tiles-new.tar.gz`
|
||||
|
||||
20. swap the old tiles for the new ones
|
||||
`mv tiles2 tiles2-old && mv tiles-new tiles2`
|
||||
121
crates/index.html
Normal file
@ -0,0 +1,121 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>📦 Crate Calculator — Famme's BDO Tools</title>
|
||||
<meta name="description" content="Black Desert Online crate calculator">
|
||||
<link rel="icon" type="image/png" href="../map/static/favicon.png">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0,minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
|
||||
<style>
|
||||
@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,700|Open+Sans+Condensed:300,700);
|
||||
html {
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 11px;
|
||||
}
|
||||
html, body { margin: 0; padding: 0 }
|
||||
#menu {
|
||||
background: #b71c1c;
|
||||
color: #FFF;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 54px;
|
||||
display: flex;
|
||||
}
|
||||
h1,h2 {
|
||||
display: inline-block;
|
||||
font-size: 1.2rem;
|
||||
margin: 0rem 0.5rem 0;
|
||||
padding: 0;
|
||||
font-weight: 400;
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
h1 {
|
||||
font-weight: 700;
|
||||
position: absolute;
|
||||
top: 9px;
|
||||
}
|
||||
h2 {
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
font-size: 1.1rem;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.back {
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
margin: 0;
|
||||
display: inline-block;
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 1rem;
|
||||
font-weight: normal;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
text-decoration: none;
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.back:hover {
|
||||
border-color: rgba(255, 255, 255, 0.85);
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
.intro {
|
||||
flex: 0 1 280px;
|
||||
padding: 1.1rem;
|
||||
}
|
||||
.links {
|
||||
flex: 1 1 50%;
|
||||
background: #263238;
|
||||
padding: 1.1rem 2rem;
|
||||
}
|
||||
.link {
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
margin: 0 1rem 0 0;
|
||||
display: inline-block;
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 1rem;
|
||||
font-weight: normal;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
text-decoration: none;
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.link:hover {
|
||||
border: 1px solid rgba(255, 255, 255, 0.4);
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
.link.selected {
|
||||
font-weight: 700;
|
||||
border-color: #FFF;
|
||||
color: #263238;
|
||||
background: #FFF;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
<iframe width="100%" height="1200" src="//jsfiddle.net/fffam/8Ldoz5wz/embedded/result/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
|
||||
<div id="menu">
|
||||
<div class="intro">
|
||||
<a class="back" href="/bdo/">← <span>Return to Map</span></a>
|
||||
<h1>Famme's BDO Tools</h1>
|
||||
<h2>Trading Tools</h2>
|
||||
</div>
|
||||
<div class="links">
|
||||
<a href="/bdo/crates" class="link selected">Crate Calculator</a>
|
||||
<a href="/bdo/tradepacks" class="link">Trade Pack Reference</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
149
gulpfile.js
Normal file
@ -0,0 +1,149 @@
|
||||
var gulp = require('gulp');
|
||||
var runSequence = require('run-sequence');
|
||||
var webpack = require('webpack');
|
||||
var notify = require('gulp-notify');
|
||||
var rm = require('rimraf');
|
||||
var imagemin = require('gulp-imagemin');
|
||||
var scsslint = require('gulp-scss-lint');
|
||||
|
||||
//http://www.browsersync.cn/docs/recipes/
|
||||
var browserSync = require('browser-sync').create();
|
||||
var reload = browserSync.reload;
|
||||
var src = './src/';
|
||||
var dest = './dist/';
|
||||
var homepage = 'index.html';
|
||||
|
||||
var config = {
|
||||
src: src,
|
||||
dest: dest,
|
||||
webServer: {
|
||||
server: './dist',
|
||||
index: homepage,
|
||||
port: 3000,
|
||||
logLevel: 'debug',
|
||||
logPrefix: 'JHW',
|
||||
open: true,
|
||||
files: [dest + '/*.js', './index.html']
|
||||
},
|
||||
scss: {
|
||||
src: src + '**/*.scss'
|
||||
},
|
||||
script: {
|
||||
entry: {
|
||||
'entry': src + 'main.js'
|
||||
},
|
||||
output: {
|
||||
path: dest, //js
|
||||
filename: 'bundle.js'
|
||||
},
|
||||
sourceMap: true,
|
||||
watch: src + '**/*.js'
|
||||
},
|
||||
html: {
|
||||
watchHome: homepage,
|
||||
watchAll: src + '**/*.html'
|
||||
}
|
||||
}
|
||||
|
||||
var webpackConfig = require('./webpack.config')(config);
|
||||
gulp.task('webpack', function(cb) {
|
||||
webpack(webpackConfig, function(err, stats) {
|
||||
if (err) {
|
||||
handleErrors();
|
||||
console.error(stats);
|
||||
}
|
||||
if (stats.compilation.errors.length) {
|
||||
console.error(stats.compilation.errors[0].toString());
|
||||
}
|
||||
cb();
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('img:dev', ['clean'], function() {
|
||||
return gulp.src([src + '/images/**'])
|
||||
.pipe(watch())
|
||||
.pipe(reload());
|
||||
});
|
||||
|
||||
gulp.task('img', ['clean'], function() {
|
||||
return gulp.src([src + '/images/**'])
|
||||
.pipe(imagemin())
|
||||
.pipe(gulp.dest(dest + '/images'));
|
||||
});
|
||||
|
||||
function handleErrors() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
notify.onError({
|
||||
title: 'compile error',
|
||||
message: '<%= error.message %>'
|
||||
}).apply(this, args);
|
||||
this.emit('end');
|
||||
}
|
||||
|
||||
gulp.task('web-server', ['build'],function() {
|
||||
browserSync.init(config.webServer);
|
||||
});
|
||||
|
||||
gulp.task('watch', ['web-server'], function() {
|
||||
gulp.watch(config.script.watch, ['webpack']).on('change', reload);
|
||||
gulp.watch(config.scss.src, ['webpack']).on('change', reload);
|
||||
gulp.watch(config.src + '/**/*.vue', ['webpack']).on('change', reload);
|
||||
gulp.watch(config.html.watchHome, ['html']).on('change', reload);
|
||||
gulp.watch(config.html.watchAll, ['html']).on('change', reload);
|
||||
});
|
||||
|
||||
gulp.task('scss-lint', function() {
|
||||
return gulp.src(src+'**/*.scss')
|
||||
.pipe(scsslint({
|
||||
'config': 'scsslint.yml',
|
||||
}));
|
||||
});
|
||||
|
||||
gulp.task('static', function() {
|
||||
return gulp.src([src + 'static/**'])
|
||||
.pipe(gulp.dest(dest + 'static'));
|
||||
});
|
||||
|
||||
gulp.task('datajson', function() {
|
||||
return gulp.src([src + 'data.json'])
|
||||
.pipe(gulp.dest(dest));
|
||||
});
|
||||
|
||||
gulp.task('gatheringdata', function() {
|
||||
return gulp.src([src + 'gathering/**'])
|
||||
.pipe(gulp.dest(dest + 'gathering'));
|
||||
});
|
||||
|
||||
gulp.task('icons', function() {
|
||||
return gulp.src([src + 'icons/**'])
|
||||
.pipe(gulp.dest(dest + 'icons'));
|
||||
});
|
||||
|
||||
gulp.task('html', function() {
|
||||
return gulp.src([src + '**/*.html'])
|
||||
.pipe(gulp.dest(dest));
|
||||
});
|
||||
|
||||
gulp.task('clean', function(next) {
|
||||
rm(dest, function() {
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('default', ['watch']);
|
||||
gulp.task('run', ['watch']);
|
||||
|
||||
gulp.task('build', function(callback) {
|
||||
runSequence('clean', 'img', 'webpack', 'static', 'datajson', 'gatheringdata', 'icons', 'html',callback);
|
||||
});
|
||||
|
||||
gulp.task( 'download-images', function() {
|
||||
var data = require('./scripts/download-images');
|
||||
});
|
||||
|
||||
// Require extra gulp tasks
|
||||
try {
|
||||
require('./gulptasks/upload.js')(gulp);
|
||||
} catch(err) {
|
||||
// Don't error if we don't have extra tasks, they're only for deploy right now
|
||||
}
|
||||
BIN
horses/img/1A.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
horses/img/1B.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
horses/img/2A.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
horses/img/2B.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
horses/img/2C.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
horses/img/2D.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
horses/img/3A.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
horses/img/3B.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
horses/img/3C.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
horses/img/3D.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
horses/img/3E.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
horses/img/3F.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
horses/img/4A.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
horses/img/4B.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
horses/img/4C.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
horses/img/4D.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
horses/img/4E.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
horses/img/4F.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
horses/img/4G.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
horses/img/4H.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
horses/img/4I.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
horses/img/4J.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
horses/img/4K.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
horses/img/4L.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
horses/img/4M.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
horses/img/4N.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
horses/img/4O.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
horses/img/4P.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
horses/img/4Q.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
horses/img/5A.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
horses/img/5B.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
horses/img/5C.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
horses/img/5D.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
horses/img/5E.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
horses/img/5F.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
horses/img/5G.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
horses/img/5H.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
horses/img/5I.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
horses/img/5J.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
horses/img/5K.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
horses/img/5L.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
horses/img/5M.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
horses/img/5N.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
horses/img/5O.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
horses/img/6A.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
horses/img/6B.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
horses/img/6C.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
horses/img/6D.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
horses/img/6E.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
horses/img/6F.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
horses/img/6G.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
horses/img/6H.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
horses/img/6I.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
horses/img/6J.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
horses/img/6K.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
horses/img/6L.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
horses/img/6M.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
horses/img/6N.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
horses/img/6O.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
horses/img/6P.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
horses/img/6Q.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
horses/img/6R.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
horses/img/6S.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
horses/img/6T.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
horses/img/6U.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
horses/img/7A.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
horses/img/7B.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
horses/img/7C.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
horses/img/7D.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
horses/img/7E.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
horses/img/7G.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
horses/img/7H.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
horses/img/7I.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
horses/img/7J.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
horses/img/8A.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
horses/img/8B.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
horses/img/8C.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
horses/img/8D.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
horses/img/8E.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
horses/img/9A.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
horses/img/9A2.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
horses/img/9B.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
horses/img/9C.png
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
117
horses/index.html
Normal file
@ -0,0 +1,117 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>🐎 Horse Calculator — Famme's BDO Tools</title>
|
||||
<meta name="description" content="Black Desert Online horse breeding calculator">
|
||||
<link rel="icon" type="image/png" href="../map/static/favicon.png">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0,minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
|
||||
<style>
|
||||
@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,700|Open+Sans+Condensed:300,700);
|
||||
html {
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 11px;
|
||||
}
|
||||
html, body { margin: 0; padding: 0 }
|
||||
#menu {
|
||||
background: #b71c1c;
|
||||
color: #FFF;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 54px;
|
||||
display: flex;
|
||||
}
|
||||
h1,h2 {
|
||||
display: inline-block;
|
||||
font-size: 1.2rem;
|
||||
margin: 0rem 0.5rem 0;
|
||||
padding: 0;
|
||||
font-weight: 400;
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
h1 {
|
||||
font-weight: 700;
|
||||
position: absolute;
|
||||
top: 9px;
|
||||
}
|
||||
h2 {
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
font-size: 1.1rem;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.back {
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
margin: 0;
|
||||
display: inline-block;
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 1rem;
|
||||
font-weight: normal;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
text-decoration: none;
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.back:hover {
|
||||
border-color: rgba(255, 255, 255, 0.85);
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
.intro {
|
||||
flex: 0 1 280px;
|
||||
padding: 1.1rem;
|
||||
}
|
||||
.links {
|
||||
flex: 1 1 50%;
|
||||
background: #263238;
|
||||
padding: 1.1rem 2rem;
|
||||
}
|
||||
.link {
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
margin: 0 1rem 0 0;
|
||||
display: inline-block;
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 1rem;
|
||||
font-weight: normal;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
text-decoration: none;
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.link:hover {
|
||||
border: 1px solid rgba(255, 255, 255, 0.4);
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
.link.selected {
|
||||
font-weight: 700;
|
||||
border-color: #FFF;
|
||||
color: #263238;
|
||||
background: #FFF;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
<iframe width="100%" height="1200" src="//jsfiddle.net/fffam/k5z99cus/embedded/result/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
|
||||
<div id="menu">
|
||||
<div class="intro">
|
||||
<a class="back" href="/bdo/">← <span>Return to Map</span></a>
|
||||
<h1>Famme's BDO Tools</h1>
|
||||
<h2>Horse Calculator</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
15591
package-lock.json
generated
Normal file
80
package.json
Normal file
@ -0,0 +1,80 @@
|
||||
{
|
||||
"name": "mwBlog",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"main": "bundle.js",
|
||||
"scripts": {
|
||||
"test": "echo \\\"Error: no test specified\\\" && exit 1",
|
||||
"start": "export NODE_ENV=\"dev\" ; gulp watch",
|
||||
"clean": "export NODE_ENV=\"dev\" ; gulp clean",
|
||||
"webpack": "export NODE_ENV=\"production\" ; gulp webpack",
|
||||
"build": "export NODE_ENV=\"production\" ; gulp build",
|
||||
"deploy": "export NODE_ENV=\"production\" ; gulp deploy",
|
||||
"download-images": "export NODE_ENV=\"dev\" ; gulp download-images"
|
||||
},
|
||||
"dependencies": {
|
||||
"clipboard-js": "^0.3.6",
|
||||
"d3": "^3.5.17",
|
||||
"eventemitter3": "^2.0.3",
|
||||
"js-cookie": "^2.2.0",
|
||||
"js-cookies": "^1.0.4",
|
||||
"leaflet": "^1.2.0",
|
||||
"riot-route": "^2.5.0",
|
||||
"vue": "^1.0.28",
|
||||
"vue-resource": "^0.7.0",
|
||||
"vue-router": "^0.7.10",
|
||||
"vue-simple-store": "^1.0.0",
|
||||
"whatwg-fetch": "^1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"async": "^2.6.0",
|
||||
"autoprefixer": "^6.7.7",
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-eslint": "^6.0.4",
|
||||
"babel-loader": "^6.4.1",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"browser-sync": "^2.23.1",
|
||||
"cheerio": "^0.20.0",
|
||||
"concat": "^1.0.3",
|
||||
"css-loader": "^0.23.1",
|
||||
"csswring": "^4.0.0",
|
||||
"eslint": "~2.2.0",
|
||||
"eslint-loader": "^1.9.0",
|
||||
"eslint-plugin-html": "^1.7.0",
|
||||
"extract-text-webpack-plugin": "^1.0.1",
|
||||
"file-loader": "^0.8.5",
|
||||
"firebase": "^3.9.0",
|
||||
"gulp": "^3.9.0",
|
||||
"gulp-imagemin": "~2.4.0",
|
||||
"gulp-jshint": "^2.1.0",
|
||||
"gulp-load-plugins": "^1.5.0",
|
||||
"gulp-notify": "^2.2.0",
|
||||
"gulp-scss-lint": "^0.4.0",
|
||||
"html-loader": "^0.4.5",
|
||||
"html-webpack-plugin": "^2.30.1",
|
||||
"jquery": "^2.1.4",
|
||||
"jshint": "^2.9.5",
|
||||
"jshint-loader": "^0.8.4",
|
||||
"map-stream": "0.0.6",
|
||||
"node-libs-browser": "^1.1.1",
|
||||
"node-sass": "^3.13.1",
|
||||
"postcss-loader": "^0.8.0",
|
||||
"rimraf": "~2.5.0",
|
||||
"run-sequence": "^1.2.1",
|
||||
"sass-loader": "^3.1.2",
|
||||
"source-map-loader": "^0.1.6",
|
||||
"style-loader": "^0.13.2",
|
||||
"url-loader": "^0.5.9",
|
||||
"vinyl-ftp": "^0.6.1",
|
||||
"vue-html-loader": "^1.2.4",
|
||||
"vue-loader": "^8.7.0",
|
||||
"vue-style-loader": "^1.0.0",
|
||||
"webpack": "^1.15.0",
|
||||
"webpack-dev-server": "^1.16.5",
|
||||
"webpack-stream": "^3.2.0",
|
||||
"webpack-subresource-integrity": "^1.1.0-rc.2"
|
||||
}
|
||||
}
|
||||
253
scsslint.yml
Normal file
@ -0,0 +1,253 @@
|
||||
# Default application configuration that all configurations inherit from.
|
||||
|
||||
scss_files: "**/*.scss"
|
||||
plugin_directories: ['.scss-linters']
|
||||
|
||||
# List of gem names to load custom linters from (make sure they are already
|
||||
# installed)
|
||||
plugin_gems: []
|
||||
|
||||
# Default severity of all linters.
|
||||
severity: warning
|
||||
|
||||
linters:
|
||||
BangFormat:
|
||||
enabled: true
|
||||
space_before_bang: true
|
||||
space_after_bang: false
|
||||
|
||||
BemDepth:
|
||||
enabled: false
|
||||
max_elements: 1
|
||||
|
||||
BorderZero:
|
||||
enabled: true
|
||||
convention: none # or `zero`
|
||||
|
||||
ChainedClasses:
|
||||
enabled: false
|
||||
|
||||
ColorKeyword:
|
||||
enabled: true
|
||||
|
||||
ColorVariable:
|
||||
enabled: false
|
||||
|
||||
Comment:
|
||||
enabled: true
|
||||
style: silent
|
||||
|
||||
DebugStatement:
|
||||
enabled: true
|
||||
|
||||
DeclarationOrder:
|
||||
enabled: true
|
||||
|
||||
DisableLinterReason:
|
||||
enabled: false
|
||||
|
||||
DuplicateProperty:
|
||||
enabled: true
|
||||
|
||||
ElsePlacement:
|
||||
enabled: true
|
||||
style: same_line # or 'new_line'
|
||||
|
||||
EmptyLineBetweenBlocks:
|
||||
enabled: false
|
||||
ignore_single_line_blocks: true
|
||||
|
||||
EmptyRule:
|
||||
enabled: true
|
||||
|
||||
ExtendDirective:
|
||||
enabled: false
|
||||
|
||||
FinalNewline:
|
||||
enabled: true
|
||||
present: true
|
||||
|
||||
HexLength:
|
||||
enabled: true
|
||||
style: short # or 'long'
|
||||
|
||||
HexNotation:
|
||||
enabled: true
|
||||
style: uppercase # or 'uppercase'
|
||||
|
||||
HexValidation:
|
||||
enabled: true
|
||||
|
||||
IdSelector:
|
||||
enabled: false
|
||||
|
||||
ImportantRule:
|
||||
enabled: false
|
||||
|
||||
ImportPath:
|
||||
enabled: true
|
||||
leading_underscore: false
|
||||
filename_extension: false
|
||||
|
||||
Indentation:
|
||||
enabled: true
|
||||
allow_non_nested_indentation: false
|
||||
character: 'tab' # or 'tab'
|
||||
width: 1
|
||||
|
||||
LeadingZero:
|
||||
enabled: false
|
||||
style: exclude_zero # or 'include_zero'
|
||||
|
||||
MergeableSelector:
|
||||
enabled: true
|
||||
force_nesting: true
|
||||
|
||||
NameFormat:
|
||||
enabled: true
|
||||
allow_leading_underscore: true
|
||||
convention: hyphenated_lowercase # or 'camel_case', or 'snake_case', or a regex pattern
|
||||
|
||||
NestingDepth:
|
||||
enabled: false
|
||||
max_depth: 3
|
||||
ignore_parent_selectors: false
|
||||
|
||||
PlaceholderInExtend:
|
||||
enabled: true
|
||||
|
||||
PrivateNamingConvention:
|
||||
enabled: false
|
||||
prefix: _
|
||||
|
||||
PropertyCount:
|
||||
enabled: false
|
||||
include_nested: false
|
||||
max_properties: 10
|
||||
|
||||
PropertySortOrder:
|
||||
enabled: false
|
||||
ignore_unspecified: false
|
||||
min_properties: 2
|
||||
separate_groups: false
|
||||
|
||||
PropertySpelling:
|
||||
enabled: true
|
||||
extra_properties: []
|
||||
disabled_properties: []
|
||||
|
||||
PropertyUnits:
|
||||
enabled: true
|
||||
global: [
|
||||
'ch', 'em', 'ex', 'rem', # Font-relative lengths
|
||||
'cm', 'in', 'mm', 'pc', 'pt', 'px', 'q', # Absolute lengths
|
||||
'vh', 'vw', 'vmin', 'vmax', # Viewport-percentage lengths
|
||||
'deg', 'grad', 'rad', 'turn', # Angle
|
||||
'ms', 's', # Duration
|
||||
'Hz', 'kHz', # Frequency
|
||||
'dpi', 'dpcm', 'dppx', # Resolution
|
||||
'%'] # Other
|
||||
properties: {}
|
||||
|
||||
PseudoElement:
|
||||
enabled: true
|
||||
|
||||
QualifyingElement:
|
||||
enabled: true
|
||||
allow_element_with_attribute: true
|
||||
allow_element_with_class: true
|
||||
allow_element_with_id: false
|
||||
|
||||
SelectorDepth:
|
||||
enabled: false
|
||||
max_depth: 3
|
||||
|
||||
SelectorFormat:
|
||||
enabled: false
|
||||
convention: hyphenated_lowercase # or 'strict_BEM', or 'hyphenated_BEM', or 'snake_case', or 'camel_case', or a regex pattern
|
||||
|
||||
Shorthand:
|
||||
enabled: true
|
||||
allowed_shorthands: [1, 2, 3, 4]
|
||||
|
||||
SingleLinePerProperty:
|
||||
enabled: true
|
||||
allow_single_line_rule_sets: true
|
||||
|
||||
SingleLinePerSelector:
|
||||
enabled: false
|
||||
|
||||
SpaceAfterComma:
|
||||
enabled: false
|
||||
style: one_space # or 'no_space', or 'at_least_one_space'
|
||||
|
||||
SpaceAfterPropertyColon:
|
||||
enabled: true
|
||||
style: one_space # or 'no_space', or 'at_least_one_space', or 'aligned'
|
||||
|
||||
SpaceAfterPropertyName:
|
||||
enabled: true
|
||||
|
||||
SpaceAfterVariableColon:
|
||||
enabled: false
|
||||
style: one_space # or 'no_space', 'at_least_one_space' or 'one_space_or_newline'
|
||||
|
||||
SpaceAfterVariableName:
|
||||
enabled: true
|
||||
|
||||
SpaceAroundOperator:
|
||||
enabled: true
|
||||
style: one_space # or 'at_least_one_space', or 'no_space'
|
||||
|
||||
SpaceBeforeBrace:
|
||||
enabled: true
|
||||
style: space # or 'new_line'
|
||||
allow_single_line_padding: false
|
||||
|
||||
SpaceBetweenParens:
|
||||
enabled: true
|
||||
spaces: 0
|
||||
|
||||
StringQuotes:
|
||||
enabled: false
|
||||
style: single_quotes # or double_quotes
|
||||
|
||||
TrailingSemicolon:
|
||||
enabled: true
|
||||
|
||||
TrailingWhitespace:
|
||||
enabled: true
|
||||
|
||||
TrailingZero:
|
||||
enabled: false
|
||||
|
||||
TransitionAll:
|
||||
enabled: false
|
||||
|
||||
UnnecessaryMantissa:
|
||||
enabled: true
|
||||
|
||||
UnnecessaryParentReference:
|
||||
enabled: false
|
||||
|
||||
UrlFormat:
|
||||
enabled: true
|
||||
|
||||
UrlQuotes:
|
||||
enabled: true
|
||||
|
||||
VariableForProperty:
|
||||
enabled: false
|
||||
properties: []
|
||||
|
||||
VendorPrefix:
|
||||
enabled: true
|
||||
identifier_list: base
|
||||
additional_identifiers: []
|
||||
excluded_identifiers: []
|
||||
|
||||
ZeroUnit:
|
||||
enabled: true
|
||||
|
||||
Compass::*:
|
||||
enabled: false
|
||||
71
src/App.scss
Normal file
@ -0,0 +1,71 @@
|
||||
@import "./common";
|
||||
@import "./MapIcons";
|
||||
|
||||
*, *:before, *:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
html {
|
||||
font-size: 12px;
|
||||
}
|
||||
body {
|
||||
@include font-normal;
|
||||
font-style: normal;
|
||||
font-size: 12px;
|
||||
background: #222;
|
||||
-webkit-overflow-scrolling: auto;
|
||||
}
|
||||
a {
|
||||
color: $color-text-link;
|
||||
}
|
||||
#map.leaflet-container {
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
}
|
||||
body,html,#app {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#panels {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
z-index: 100000;
|
||||
|
||||
pointer-events: none;
|
||||
|
||||
width: 24rem;
|
||||
|
||||
flex-flow: column;
|
||||
display: flex;
|
||||
transition: margin-left 0.5s;
|
||||
margin-left: 0;
|
||||
|
||||
&>* {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.panel-group {
|
||||
flex: 1;
|
||||
flex-flow: column;
|
||||
display: flex;
|
||||
|
||||
pointer-events: none;
|
||||
&>* {
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&.minimized {
|
||||
margin-left: -24rem;
|
||||
}
|
||||
}
|
||||
|
||||
#panes {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
flex-flow: row;
|
||||
}
|
||||
440
src/App.vue
Normal file
@ -0,0 +1,440 @@
|
||||
<template>
|
||||
<div>
|
||||
<map-view v-ref:map :is-node-planner-active="isNodePlannerActive"></map-view>
|
||||
<div id="panes">
|
||||
<menu-pane :active="selectedPane == 'menu'" v-ref:menupane></menu-pane>
|
||||
<node-planner-pane v-ref:nodeplannerpane v-if="isNodePlannerActive && isNodePlannerEnabled" :active="selectedPane == 'nodeplanner'"></node-planner-pane>
|
||||
<component v-ref:detailpane :is="currentDetailPane" keep-alive :active="selectedPane == 'detail'" :item-id="currentDetailItemId"></component>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue';
|
||||
import router from 'riot-route';
|
||||
import NodePathCalculator from './misc/NodePathCalculator.js';
|
||||
import NodePlanner from './misc/NodePlanner.js';
|
||||
|
||||
import MapView from './components/MapView.vue';
|
||||
import MenuPane from './components/panes/MenuPane.vue';
|
||||
import InfoPane from './components/panes/InfoPane.vue';
|
||||
import NodePlannerPane from './components/panes/NodePlannerPane.vue';
|
||||
|
||||
import NodeInfoPane from './components/panes/NodeInfoPane.vue';
|
||||
import LevellingAreaInfoPane from './components/panes/LevellingAreaInfoPane.vue';
|
||||
import VillaInfoPane from './components/panes/VillaInfoPane.vue';
|
||||
import WorldBossInfoPane from './components/panes/WorldBossInfoPane.vue';
|
||||
import FishingHotspotInfoPane from './components/panes/FishingHotspotInfoPane.vue';
|
||||
import SeaRegionInfoPane from './components/panes/SeaRegionInfoPane.vue';
|
||||
import GoldenChestInfoPane from './components/panes/GoldenChestInfoPane.vue';
|
||||
|
||||
export default {
|
||||
|
||||
name: 'App',
|
||||
|
||||
data: function() {
|
||||
return {
|
||||
appTitle: 'Map — Famme\'s BDO Tools',
|
||||
selectedPane: 'menu',
|
||||
currentDetailPane: '',
|
||||
currentDetailItemId: null,
|
||||
isNodePlannerEnabled: false,
|
||||
isNodePlannerActive: false,
|
||||
isReady: false
|
||||
};
|
||||
},
|
||||
|
||||
components: {
|
||||
|
||||
MapView,
|
||||
MenuPane,
|
||||
InfoPane,
|
||||
NodeInfoPane,
|
||||
NodePlannerPane,
|
||||
|
||||
LevellingAreaInfoPane,
|
||||
VillaInfoPane,
|
||||
WorldBossInfoPane,
|
||||
FishingHotspotInfoPane,
|
||||
SeaRegionInfoPane,
|
||||
GoldenChestInfoPane
|
||||
},
|
||||
|
||||
ready: function() {
|
||||
this.$action('mapdata:load');
|
||||
this.$action('filters:loadStateFromBrowserStorage');
|
||||
|
||||
let devmode = window.location && window.location.hash && (window.location.hash.indexOf('devmode') > -1);
|
||||
if( devmode ) {
|
||||
this.isNodePlannerEnabled = true;
|
||||
}
|
||||
|
||||
this.router = router;
|
||||
|
||||
// Determine if the query string contains the show parameter
|
||||
// for which nodes to display
|
||||
this.setStateFromQueryString( this.router.query() );
|
||||
|
||||
// this.route('/node/'+id, '', true])
|
||||
this.router('/node/*', (nodeid) => {
|
||||
if( this.isReady ) return; // Only use routes on load
|
||||
let matchedNode = this.getNodeFromUrlPath(nodeid);
|
||||
matchedNode && this.selectNode(matchedNode);
|
||||
});
|
||||
|
||||
// Route for linking directly to layers
|
||||
this.router('/layer/(.*)', (layernames) => {
|
||||
var layers = layernames.split(',');
|
||||
for( var i in this.state.filters ) {
|
||||
if( i !== 'gathering' ) {
|
||||
this.state.filters[i].active = false;
|
||||
}
|
||||
}
|
||||
for( var i in layers ) {
|
||||
// Is this a gathering filter?
|
||||
if( layers[i].indexOf(':') && layers[i].indexOf('gathering') === 0 ) {
|
||||
var layerparts = layers[i].split(':');
|
||||
if(layerparts.length !== 3) {
|
||||
continue;
|
||||
}
|
||||
this.state.filters['gathering'][layerparts[1]][layerparts[2]].active = true;
|
||||
|
||||
// Normal filters
|
||||
} else if( this.state.filters[layers[i]] ) {
|
||||
this.state.filters[layers[i]].active = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Match data layers
|
||||
this.router('/*/*', (layername,id) => {
|
||||
if( this.isReady ) return; // Only use routes on load
|
||||
let matchedFeature = this.getDataLayerFeatureFromUrlPath(layername,id);
|
||||
matchedFeature && this.selectDataLayerFeature(layername,matchedFeature);
|
||||
});
|
||||
|
||||
this.$watch('state.mapdata.ready', (c) => {
|
||||
this.nodePlanner = new NodePlanner(this.state.mapdata.nodes);
|
||||
this.router.exec();
|
||||
this.router.stop();
|
||||
this.isReady = true;
|
||||
this.nodePathCalculator = new NodePathCalculator(this.state.mapdata.nodes);
|
||||
this.nodePlanner = new NodePlanner(this.state.mapdata.nodes);
|
||||
this.nodePlanner.on('plan-changed', () => {
|
||||
this.$broadcast('nodeplanner-plan-changed', {plan:this.nodePlanner.plan, planner: this.nodePlanner} );
|
||||
this.isNodePlannerActive = true;
|
||||
});
|
||||
this.$broadcast('node-data-ready');
|
||||
});
|
||||
|
||||
// Link horses filter to elephants filter
|
||||
this.$watch('state.filters.horses.active', (c) => {
|
||||
this.state.filters.elephants.active = c;
|
||||
});
|
||||
|
||||
// Link all of the hunting filters
|
||||
this.$watch('state.filters.hunting.active', (c) => {
|
||||
this.state.filters.whales.active = c;
|
||||
this.state.filters.bluewhales.active = c;
|
||||
this.state.filters.crocodiles.active = c;
|
||||
this.state.filters.khalks.active = c;
|
||||
});
|
||||
|
||||
// Did we just activate the node planner?
|
||||
// If so, make it the focussed panel
|
||||
this.$watch('isNodePlannerActive', (c) => {
|
||||
if( this.isNodePlannerActive ) {
|
||||
this.selectedPane = 'nodeplanner';
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
events: {
|
||||
'marker-clicked': function (msg,a) {
|
||||
switch(msg.type) {
|
||||
case 'node':
|
||||
this.selectNode(msg.id,true,false);
|
||||
break;
|
||||
case 'feature':
|
||||
this.selectDataLayerFeature(msg.layer,msg.id,true,false);
|
||||
break;
|
||||
default:
|
||||
// Not setup for anything other than nodes yet
|
||||
}
|
||||
this.$broadcast('marker-clicked',msg);
|
||||
return true;
|
||||
},
|
||||
'search-suggestion-clicked': function (msg) {
|
||||
if( msg.isDataLayer || msg.isDataLayerOutput ) {
|
||||
this.selectDataLayerFeature(msg.type,msg.id,true,true);
|
||||
} else {
|
||||
this.selectNode(msg == 'node' ? msg.id : msg.node.id,true,true);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
'search-suggestion-hovered': function (msg) {
|
||||
if( msg.isDataLayer || msg.isDataLayerOutput ) {
|
||||
this.pingDataLayerFeature(msg.type,msg.id);
|
||||
} else {
|
||||
this.pingNode(msg.type == 'node' ? msg.id : msg.node.id);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
'node-link-clicked': function (id) {
|
||||
this.selectNode(id,true,true);
|
||||
return true;
|
||||
},
|
||||
'zoom-map-to-coordinates': function (coords) {
|
||||
this.zoomMapToCoords(coords);
|
||||
return true;
|
||||
},
|
||||
'detail-pane-closed': function() {
|
||||
this.currentDetailPane = null;
|
||||
this.selectedPane = 'menu';
|
||||
this.$refs.menupane.activatePane();
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
isBeta() {
|
||||
let document = window.document;
|
||||
if( document && document.location && document.location.href ) {
|
||||
return ((document.location.pathname.indexOf('bdobeta')>-1) || (document.location.hostname == 'localhost'));
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
setStateFromQueryString: function(query) {
|
||||
|
||||
// Should we turn off all layers by default?
|
||||
if( query.hidedefaults ) {
|
||||
for( var i in this.state.filters ) {
|
||||
this.state.filters[i].active = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Which layers should we turn on?
|
||||
if( query.filters ) {
|
||||
try {
|
||||
let queryParts = query.filters.split('|');
|
||||
for( var i in queryParts ) {
|
||||
if( this.state.filters[queryParts[i]] ) {
|
||||
this.state.filters[queryParts[i]].active = true;
|
||||
} else {
|
||||
// Search through the gathering filters to see if one matches
|
||||
for( var gatheringCategory in this.state.filters['gathering'] ) {
|
||||
// It matches the category
|
||||
if( this.state.filters['gathering'][gatheringCategory].slug == queryParts[i] ) {
|
||||
for( var j in this.state.filters['gathering'][gatheringCategory].items ) {
|
||||
this.state.filters['gathering'][gatheringCategory].items[j].active = true;
|
||||
}
|
||||
} else {
|
||||
for( var j in this.state.filters['gathering'][gatheringCategory].items ) {
|
||||
if( this.state.filters['gathering'][gatheringCategory].items[j].slug == queryParts[i] ) {
|
||||
this.state.filters['gathering'][gatheringCategory].items[j].active = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
// Just use default filters
|
||||
}
|
||||
}
|
||||
|
||||
if( query.latlng ) {
|
||||
this.$refs.map.zoomMapToCoords( query.latlng.split('|').map( (a) => a * 1 ) );
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
routeTo: function(title, ...urlparts) {
|
||||
if( urlparts && urlparts.length ) {
|
||||
if( title ) {
|
||||
this.router('/'+urlparts.join('/'),title + ' — ' + this.appTitle,true);
|
||||
} else {
|
||||
this.router('/'+urlparts.join('/'),this.appTitle,true);
|
||||
}
|
||||
} else {
|
||||
this.router('/',this.appTitle,true);
|
||||
}
|
||||
},
|
||||
|
||||
getNodeFromUrlPath: function(urlPathPart) {
|
||||
if( this.state.mapdata.nodes[urlPathPart] ) {
|
||||
return this.state.mapdata.nodes[urlPathPart];
|
||||
} else {
|
||||
// Find by slug
|
||||
for( let id in this.state.mapdata.nodes ) {
|
||||
if( this.state.mapdata.nodes[id].slug && this.state.mapdata.nodes[id].slug == urlPathPart ) {
|
||||
return this.state.mapdata.nodes[urlPathPart];
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
getLinkInfoForNode: function(id) {
|
||||
if( this.state.mapdata.nodes[id] ) {
|
||||
return {
|
||||
id: id,
|
||||
name: this.state.mapdata.nodes[id].name,
|
||||
slug: this.state.mapdata.nodes[id].slug || id
|
||||
};
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
getDataLayerFeatureFromUrlPath: function(layerName,urlPathPart) {
|
||||
if( this.state.mapdata.layers[layerName] && this.state.mapdata.layers[layerName].features ) {
|
||||
let features = this.state.mapdata.layers[layerName].features;
|
||||
for( var i in features ) {
|
||||
if(
|
||||
(features[i].id && features[i].id == urlPathPart) ||
|
||||
(features[i].properties && features[i].properties.slug && features[i].properties.slug == urlPathPart)
|
||||
) {
|
||||
return features[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
getLinkInfoForDataLayerFeature: function(layerName,id) {
|
||||
|
||||
if( this.state.mapdata.layers[layerName] && this.state.mapdata.layers[layerName].features ) {
|
||||
let features = this.state.mapdata.layers[layerName].features;
|
||||
for( var i in features ) {
|
||||
if( features[i].id && features[i].id == id ) {
|
||||
let title = (features[i].properties && features[i].properties.name) ? features[i].properties.name : null;
|
||||
return {
|
||||
id: id,
|
||||
name: title,
|
||||
slug: (features[i].properties && features[i].properties.slug) ? features[i].properties.slug : features[i].id
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
selectNode: function(idOrNodeObj,ping=false,zoom=true) {
|
||||
|
||||
// Get the ID
|
||||
if( idOrNodeObj.id ) {
|
||||
idOrNodeObj = idOrNodeObj.id;
|
||||
}
|
||||
|
||||
let linkInfo = this.getLinkInfoForNode(idOrNodeObj);
|
||||
if( linkInfo ) {
|
||||
this.routeTo( linkInfo.name, 'node', linkInfo.slug );
|
||||
} else {
|
||||
// Node doesn't exist
|
||||
return;
|
||||
}
|
||||
|
||||
this.$refs.map.selectNode(idOrNodeObj,ping,zoom);
|
||||
this.currentDetailItemId = idOrNodeObj;
|
||||
this.currentDetailPane = 'NodeInfoPane';
|
||||
this.selectedPane = 'detail';
|
||||
},
|
||||
|
||||
selectDataLayerFeature: function(type,id,ping=false,zoom=true) {
|
||||
console.log('[App]','selectDataLayerFeature',type,id);
|
||||
if( id.id ) {
|
||||
id = id.id;
|
||||
}
|
||||
|
||||
// If we are selecting the elephant layer, ensure horses filter is enabled too
|
||||
if( type == 'elephants' ) {
|
||||
this.state.filters.horses.active = true;
|
||||
}
|
||||
|
||||
// If we are selecting a hunting feature, toggle on the hunting layer
|
||||
if( type == 'whales' || type == 'bluewhales' || type == 'crocodiles' || type == 'khalks' ) {
|
||||
this.state.filters.hunting.active = true;
|
||||
}
|
||||
|
||||
let linkInfo = this.getLinkInfoForDataLayerFeature(type,id);
|
||||
if( linkInfo ) {
|
||||
this.$refs.map.selectDataLayerFeature(type,id,ping,zoom);
|
||||
this.routeTo( linkInfo.name, type, linkInfo.slug );
|
||||
} else {
|
||||
// Data layer feature doesn't exist
|
||||
return;
|
||||
}
|
||||
|
||||
// Is this a data layer that has a detail panel?
|
||||
switch( type ) {
|
||||
case 'levellingareas':
|
||||
this.currentDetailPane = 'LevellingAreaInfoPane';
|
||||
this.currentDetailItemId = id;
|
||||
this.selectedPane = 'detail';
|
||||
break;
|
||||
case 'villas':
|
||||
this.currentDetailPane = 'VillaInfoPane';
|
||||
this.currentDetailItemId = id;
|
||||
this.selectedPane = 'detail';
|
||||
break;
|
||||
case 'worldbosses':
|
||||
this.currentDetailPane = 'WorldBossInfoPane';
|
||||
this.currentDetailItemId = id;
|
||||
this.selectedPane = 'detail';
|
||||
break;
|
||||
case 'fishinghotspots':
|
||||
this.currentDetailPane = 'FishingHotspotInfoPane';
|
||||
this.currentDetailItemId = id;
|
||||
this.selectedPane = 'detail';
|
||||
break;
|
||||
case 'searegions':
|
||||
this.currentDetailPane = 'SeaRegionInfoPane';
|
||||
this.currentDetailItemId = id;
|
||||
this.selectedPane = 'detail';
|
||||
break;
|
||||
case 'goldenchests':
|
||||
this.currentDetailPane = 'GoldenChestInfoPane';
|
||||
this.currentDetailItemId = id;
|
||||
this.selectedPane = 'detail';
|
||||
break;
|
||||
|
||||
default:
|
||||
// No detail pane
|
||||
}
|
||||
},
|
||||
|
||||
registerCustomDataLayer: function( url, name, properties ) {
|
||||
console.log('[App] Registering custom data layer:', name, url);
|
||||
Vue.set(
|
||||
this.state.filters.custom,
|
||||
url,
|
||||
{ url: url, active: true, loaded: true, name: name, properties: properties }
|
||||
);
|
||||
},
|
||||
|
||||
pingNode: function(idOrNodeObj) {
|
||||
let id = idOrNodeObj;
|
||||
if( idOrNodeObj.id ) {
|
||||
idOrNodeObj = idOrNodeObj.id;
|
||||
}
|
||||
this.$refs.map.pingNode(idOrNodeObj);
|
||||
},
|
||||
|
||||
pingDataLayerFeature: function(type,id) {
|
||||
this.$refs.map.pingDataLayerFeature(type,id);
|
||||
},
|
||||
|
||||
zoomMapToCoords: function(coords) {
|
||||
this.$refs.map.zoomMapToCoords(coords);
|
||||
setTimeout( () => {
|
||||
this.$refs.map.pingCoords(coords);
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
</script>
|
||||
<style src="./App.scss" lang="sass"></style>
|
||||
212
src/MapIcons.scss
Normal file
5
src/VueFilters.js
Normal file
@ -0,0 +1,5 @@
|
||||
import Vue from 'vue';
|
||||
|
||||
Vue.filter('to-css-class', function (value) {
|
||||
return value.replace(/\s/g,'-');
|
||||
});
|
||||
91
src/common.scss
Normal file
@ -0,0 +1,91 @@
|
||||
//@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,700|Open+Sans+Condensed:300,700);
|
||||
@import url(https://fonts.googleapis.com/css?family=Roboto+Condensed:300,700|Roboto:400,700);
|
||||
|
||||
$color-red-50: #FFEBEE;
|
||||
$color-red-100: #FFCDD2;
|
||||
$color-red-200: #EF9A9A;
|
||||
$color-red-300: #E57373;
|
||||
$color-red-400: #EF5350;
|
||||
$color-red-500: #F44336;
|
||||
$color-red-600: #E53935;
|
||||
$color-red-700: #D32F2F;
|
||||
$color-red-800: #C62828;
|
||||
$color-red-900: #B71C1C;
|
||||
|
||||
$color-primary: $color-red-500;
|
||||
$color-primary-700: $color-red-700;
|
||||
$color-accent: #00E676;
|
||||
|
||||
$color-text: rgba(0,0,0,0.87);
|
||||
$color-text-2: rgba(0,0,0,0.54);
|
||||
$color-text-3: rgba(0,0,0,0.38);
|
||||
$color-text-4: rgba(0,0,0,0.18);
|
||||
$color-text-on-primary: #FFF;
|
||||
$color-text-on-accent: #FFF;
|
||||
$color-text-link: #2196F3;
|
||||
|
||||
$color-divider: rgba(0,0,0,0.12);
|
||||
$color-grey-50: #FAFAFA;
|
||||
$color-grey-100: #F5F5F5;
|
||||
$color-grey-200: #EEE;
|
||||
$color-grey-300: #E0E0E0;
|
||||
$color-grey-400: #DBDBDB;
|
||||
$color-grey-500: #9E9E9E;
|
||||
$color-grey-600: #757575;
|
||||
$color-grey-700: #616161;
|
||||
$color-grey-800: #424242;
|
||||
$color-grey-900: #212121;
|
||||
|
||||
$color-message-background: #263238;
|
||||
$color-message-text: rgba(255,255,255,0.54);
|
||||
$color-message-text-link: rgba(255,255,255,0.87);
|
||||
|
||||
$menu-padding: 1rem;
|
||||
$pane-width: 25rem;
|
||||
|
||||
@mixin font-normal() {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-weight: 400;
|
||||
}
|
||||
@mixin font-bold() {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-weight: 700;
|
||||
}
|
||||
@mixin font-condensed() {
|
||||
font-family: 'Roboto Condensed', sans-serif;
|
||||
font-weight: 300;
|
||||
}
|
||||
@mixin font-condensed-bold() {
|
||||
font-family: 'Roboto Condensed', sans-serif;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.ui-button {
|
||||
//border: 1px solid rgba(0,0,0,1);
|
||||
border: none;
|
||||
display: inline-block;
|
||||
padding: 0.5rem 1rem;
|
||||
background: $color-red-700;
|
||||
border-radius: 3px;
|
||||
color: $color-text-on-primary;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: $color-text-on-primary;
|
||||
//border-color: $color-red-500;
|
||||
background-color: $color-red-500;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
//border-color: $color-red-500;
|
||||
background-color: $color-red-700;
|
||||
}
|
||||
|
||||
&:active {
|
||||
outline: none;
|
||||
color: $color-text-on-primary;
|
||||
//border-color: $color-red-500;
|
||||
background-color: $color-red-800;
|
||||
}
|
||||
}
|
||||
485
src/components/MapView.scss
Normal file
@ -0,0 +1,485 @@
|
||||
@import "../common";
|
||||
@import "../MapIcons";
|
||||
@import "../vendor/leaflet.rrose.css";
|
||||
|
||||
circle {
|
||||
stroke: none;
|
||||
fill: #1E88E5;
|
||||
}
|
||||
|
||||
.leaflet-interactive {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.leaflet-right {
|
||||
//right: 26rem !important;
|
||||
}
|
||||
|
||||
@mixin map-icon($name, $width:36px, $height:47px, $shape:'circle', $offsety:8px) {
|
||||
.icon {
|
||||
width: $width;
|
||||
height: $height;
|
||||
background-size: $width $height;
|
||||
margin-top: -$height + 6px + $offsety;
|
||||
margin-left: -$width/2 + 6;
|
||||
}
|
||||
|
||||
&.Bank,&.Forest,&.Mushrooms,&.Mine,&.Fishing,&.Farm,&.Specialties {
|
||||
h3 {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover h3 {
|
||||
//display: block !important;
|
||||
}
|
||||
|
||||
.z1 &,.z2 &,.z3 &,.z4 & {
|
||||
h3 {
|
||||
@if $name == 'City' {
|
||||
display: block;
|
||||
} @else {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: $width*0.5;
|
||||
height: $height*0.5;
|
||||
background-size: $width*0.5 $height*0.5;
|
||||
margin-top: -$height*0.5 + 6px + ($offsety*0.5);
|
||||
margin-left: -($width*0.5)/2 + 6;
|
||||
}
|
||||
}
|
||||
.z5 & {
|
||||
.icon {
|
||||
width: $width*0.75;
|
||||
height: $height*0.75;
|
||||
background-size: $width*0.75 $height*0.75;
|
||||
margin-top: -$height*0.75 + 6px + ($offsety*0.75);
|
||||
margin-left: -($width*0.75)/2 + 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#map {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.leaflet-container {
|
||||
background: #222;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.leaflet-marker-icon {
|
||||
|
||||
// If the marker is part of node network, don't show it grayscale
|
||||
&.marker--nodeplanner-unselected {
|
||||
.icon {
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
}
|
||||
&.marker--nodeplanner-selected {
|
||||
.icon {
|
||||
filter: grayscale(0);
|
||||
}
|
||||
.contrib {
|
||||
background: #ffe605;
|
||||
}
|
||||
}
|
||||
|
||||
// Text label
|
||||
&.label {
|
||||
|
||||
pointer-events: none;
|
||||
|
||||
span {
|
||||
margin-left: -5rem;
|
||||
width: 10rem;
|
||||
text-align: center;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
color: #FFF;
|
||||
font-size: 1.25rem;
|
||||
text-shadow: rgba(0,0,0,1) 0 0 2px,rgba(0,0,0,1) 0 0 2px,rgba(0,0,0,1) 0 0 2px,rgba(0,0,0,1) 0 0 2px;
|
||||
}
|
||||
|
||||
&.label-for-data-layer-feaure {
|
||||
span {
|
||||
font-size: 0.7rem;
|
||||
line-height: 1.3;
|
||||
font-weight: normal;
|
||||
|
||||
.z5 &,.z6 &,.z7 & {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.label-on-data-layer-searegions {
|
||||
span {
|
||||
pointer-events: none;
|
||||
margin-left: -7.5rem;
|
||||
width: 15rem;
|
||||
text-shadow: none;
|
||||
opacity:0.85;
|
||||
color: #E3F2FD;
|
||||
font-size: 1rem;
|
||||
.z5 &,.z6 &,.z7 & {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.label-next-area {
|
||||
span {
|
||||
color: $color-primary;
|
||||
margin-left: -5rem;
|
||||
width: 10rem;
|
||||
font-size: 0.8rem;
|
||||
|
||||
.z5 &,.z6 &,.z7 & {
|
||||
margin-left: -10rem;
|
||||
width: 20rem;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
h3 {
|
||||
@include font-normal;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin-left: -4rem;
|
||||
text-align: center;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1rem;
|
||||
width: 9rem;
|
||||
color: #FFF;
|
||||
text-shadow: rgba(0,0,0,1) 0 0 3px,rgba(0,0,0,1) 0 0 3px,rgba(0,0,0,1) 0 0 3px,rgba(0,0,0,1) 0 0 3px;
|
||||
}
|
||||
.contrib {
|
||||
text-align: center;
|
||||
color: #000;
|
||||
background: #FFF;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
text-overflow: clip;
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
left: -6px;
|
||||
border-radius: 16px;
|
||||
font-size: 0.7rem;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
border: 2px solid rgba(0,0,0,0.9);
|
||||
padding-bottom: 4px;
|
||||
box-shadow: rgba(0,0,0,0.2) 0 1px 2px;
|
||||
}
|
||||
.detail {
|
||||
color: #FFF;
|
||||
width: 7rem;
|
||||
margin-left: -3.5rem;
|
||||
font-size: 0.8rem;
|
||||
text-align: left;
|
||||
text-shadow: rgba(0,0,0,1) 0 0 2px,rgba(0,0,0,1) 0 0 2px,rgba(0,0,0,1) 0 0 2px,rgba(0,0,0,1) 0 0 2px;
|
||||
|
||||
b {
|
||||
display: block;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
|
||||
.secondary {
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 4px;
|
||||
margin-bottom: -5px;
|
||||
background: #222;
|
||||
border: 1px solid #000;
|
||||
}
|
||||
}
|
||||
|
||||
// Hide contribution when zoomed out far
|
||||
.z1 &,.z2 &,.z3 &,.z3 & {
|
||||
&:hover {
|
||||
i.contrib {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
i.contrib {
|
||||
display: none;
|
||||
}
|
||||
.detail {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Hide titles when zoomed out
|
||||
.z1 &,.z2 &,.z3 &,.z4 & {
|
||||
h3 {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.City {
|
||||
@include map-icon('City', 42px, 53px, 'square');
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
.icon {
|
||||
@include map-icon-city();
|
||||
}
|
||||
}
|
||||
&.Town {
|
||||
@include map-icon('Town', 42px, 53px, 'square');
|
||||
.icon {
|
||||
@include map-icon-town();
|
||||
}
|
||||
}
|
||||
&.Gateway {
|
||||
@include map-icon('Gateway', 36px, 47px, 'square');
|
||||
.icon {
|
||||
@include map-icon-gateway();
|
||||
}
|
||||
}
|
||||
&.Trading-Post {
|
||||
@include map-icon('Trading-Post', 42px, 53px);
|
||||
.icon {
|
||||
@include map-icon-trading-post();
|
||||
}
|
||||
}
|
||||
&.Connection {
|
||||
@include map-icon('Connection', 42px, 43px);
|
||||
.icon {
|
||||
@include map-icon-connection();
|
||||
}
|
||||
}
|
||||
&.Dangerous {
|
||||
@include map-icon('Dangerous', 45px, 50px, 'triangle');
|
||||
.icon {
|
||||
@include map-icon-dangerous();
|
||||
}
|
||||
}
|
||||
&.Bank {
|
||||
@include map-icon('Bank');
|
||||
color: #F0AF00;
|
||||
.icon {
|
||||
@include map-icon-bank();
|
||||
}
|
||||
}
|
||||
&.Forest {
|
||||
@include map-icon('Forest');
|
||||
color: #81C784;
|
||||
.icon {
|
||||
@include map-icon-forest();
|
||||
}
|
||||
}
|
||||
&.Mushrooms {
|
||||
@include map-icon('Mushrooms');
|
||||
color: #CE93D8;
|
||||
.icon {
|
||||
@include map-icon-mushrooms();
|
||||
}
|
||||
}
|
||||
&.Mine {
|
||||
@include map-icon('Mine');
|
||||
color: #90A4AE;
|
||||
.icon {
|
||||
@include map-icon-mine();
|
||||
}
|
||||
}
|
||||
&.Fishing {
|
||||
@include map-icon('Fishing');
|
||||
color: #4FC3F7;
|
||||
.icon {
|
||||
@include map-icon-fishing();
|
||||
}
|
||||
}
|
||||
&.Farm {
|
||||
@include map-icon('Farm');
|
||||
color: #FFF176;
|
||||
.icon {
|
||||
@include map-icon-farm();
|
||||
}
|
||||
}
|
||||
&.Specialty {
|
||||
@include map-icon('Specialty');
|
||||
color: #4CAF50;
|
||||
.icon {
|
||||
@include map-icon-specialty();
|
||||
}
|
||||
}
|
||||
|
||||
&.marker-trader, &.marker-trader-imperial, &.marker-trader-smuggler {
|
||||
.icon {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
margin-left: -8px;
|
||||
margin-top: -8px;
|
||||
|
||||
.z1 &,.z2 &,.z3 &,.z4 & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.marker-trader .icon {
|
||||
@include map-icon-trader;
|
||||
}
|
||||
&.marker-trader-imperial .icon {
|
||||
@include map-icon-trader-yellow;
|
||||
}
|
||||
&.marker-trader-smuggler .icon {
|
||||
@include map-icon-trader-red;
|
||||
}
|
||||
|
||||
&.marker-npc {
|
||||
.icon {
|
||||
@include map-icon-tiny-person;
|
||||
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin-left: -7px;
|
||||
margin-top: -7px;
|
||||
|
||||
.z1 &,.z2 &,.z3 &,.z4 & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#currentLatLng {
|
||||
background: rgba(0,0,0,0.7);
|
||||
color: #FFF;
|
||||
font-size: 0.8rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 400;
|
||||
|
||||
transition: background-color 300ms ease-in;
|
||||
cursor: pointer;
|
||||
&.copied {
|
||||
transition: background-color 0ms ease-in;
|
||||
background-color: rgb(43, 198, 101);
|
||||
}
|
||||
}
|
||||
|
||||
.leaflet-rrose {
|
||||
pointer-events: none;
|
||||
|
||||
.leaflet-rrose-content {
|
||||
min-width: 12rem;
|
||||
background: #FFF;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.leaflet-rrose-content-wrapper {
|
||||
border-radius: none;
|
||||
box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.leaflet-rrose-content-wrapper,
|
||||
.leaflet-rrose-tip {
|
||||
background: #FFF;
|
||||
box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: 0.5rem 1rem;
|
||||
h2 { margin: 0; font-size: 1rem; line-height: 1.2rem; }
|
||||
h3 { margin: 0; font-size: 0.9rem; color: $color-text-2; }
|
||||
.cp {
|
||||
line-height: 1.2rem;
|
||||
color: #888;
|
||||
float: right;
|
||||
margin: 0 0 0 0.5rem;
|
||||
b {
|
||||
color: #555;
|
||||
}
|
||||
}
|
||||
}
|
||||
.body {
|
||||
padding: 0.5rem 1rem;
|
||||
background: $color-grey-100;
|
||||
p { margin: 0; font-size: 0.9rem; }
|
||||
ul, li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: block;
|
||||
}
|
||||
h5 {
|
||||
font-weight: normal;
|
||||
color: $color-text-2;
|
||||
margin: 0.25rem 0 0.5rem;
|
||||
}
|
||||
ul {
|
||||
font-size: 0.8rem;
|
||||
li {
|
||||
img {
|
||||
width: 16px;
|
||||
margin: 0 0.25rem -4px 0;
|
||||
}
|
||||
b {
|
||||
font-weight: normal;
|
||||
}
|
||||
&.primary b {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
& + h5 {
|
||||
border-top: 1px solid $color-divider;
|
||||
margin-top: 0.5rem;
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
// .footer {
|
||||
//
|
||||
// }
|
||||
|
||||
.has-header-content {
|
||||
.body {
|
||||
border-top: 1px solid $color-divider;
|
||||
}
|
||||
}
|
||||
|
||||
.map-tooltip {
|
||||
.originnode {
|
||||
border-bottom: 1px solid $color-divider;
|
||||
padding-bottom: 0.25rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
.drops {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.drop--rarity-green {
|
||||
color: rgb(15, 133, 45);
|
||||
}
|
||||
.drop--rarity-blue {
|
||||
color: rgb(0, 79, 233);
|
||||
}
|
||||
.drop--rarity-yellow {
|
||||
color: rgb(242, 174, 0);
|
||||
}
|
||||
.drop--rarity-orange {
|
||||
color: rgb(255, 69, 0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
1498
src/components/MapView.vue
Normal file
43
src/components/common/DataLayerFishIcon.vue
Normal file
@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<img v-bind:src="fishIconSrc" class="icon datalayer small icon-{{type}}">
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import markerIcons from '../../markers';
|
||||
import fishlist from '../../fishlist';
|
||||
|
||||
export default {
|
||||
|
||||
name: 'DataLayerFishIcon',
|
||||
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
fishType: {
|
||||
type: String,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
fishIconSrc: function() {
|
||||
if( !this.fishType ) {
|
||||
return '';
|
||||
}
|
||||
var fishIdx = 16;
|
||||
for( var i in fishlist ) {
|
||||
if( fishlist[i] == this.fishType ) {
|
||||
fishIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
var marker = markerIcons[this.type+'-'+fishIdx];
|
||||
return marker.options.iconRetinaUrl;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
</script>
|
||||
4
src/components/common/DataLayerIcon.scss
Normal file
@ -0,0 +1,4 @@
|
||||
@import "../../common";
|
||||
@import "../../MapIcons";
|
||||
|
||||
@include small-icon-classes;
|
||||