├── LICENSE.txt
├── README.md
├── index.html
├── marketDisplay.css
└── marketExplorer.js
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Portions of marketExplorer are taken from https://github.com/jimpurbrick/crestexplorerjs/blob/master/crestexplorer.js, where they are under the MIT and GPL2 licenses.
2 |
3 |
4 | For everything else:
5 |
6 | Copyright (c) 2015 Steve Anderson
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in
16 | all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This is a fairly basic viewer for Eve's Market data, from CREST.
2 |
3 | You'll need to register an application on https://developers.eveonline.com/ with the callback url pointing at the directory you put this in (or at whatever you rename index.html to)
4 | You'll also need to update the clientid to your applications id, and update the callback url
5 |
6 |
7 |
8 | This depends on xdr.js (I got mine from https://raw.githubusercontent.com/jaubourg/ajaxHooks/master/src/xdr.js) and moment.js (http://momentjs.com/) to be in the same directory
9 |
10 |
11 | I have a copy up and running at: https://www.fuzzwork.co.uk/market/viewer2/
12 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
42 |
43 |
44 | Select a region
45 |
46 |
47 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
Sellers
58 |
59 |
60 | Station Volume Price Expiration
61 |
62 |
63 |
64 |
65 |
66 |
67 |
Buyers
68 |
69 |
70 | Station Volume Min Volume Price Range Expiration
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/marketDisplay.css:
--------------------------------------------------------------------------------
1 | body
2 | {
3 | font: 1em "Trebuchet MS",sans-serif;
4 | background: black url(https://community.eveonline.com/bitmaps/interface/community/bg.jpg) top right no-repeat;
5 | background-attachment: fixed;
6 | color: rgb(200,200,200);
7 | height:100%;
8 | width:100%;
9 | }
10 | html {
11 | min-height:100%;/* make sure it is at least as tall as the viewport */
12 | width:100%;
13 | position:relative
14 | }
15 |
16 | ul
17 | {
18 | list-style-type: none;
19 | }
20 |
21 | li {
22 | display:block;
23 | }
24 |
25 | .groupLink
26 | {
27 | padding:2px;
28 | margin:2px;
29 | background-color: rgba(83, 83, 83, 0.95);
30 | border: 0 solid black;
31 | border-bottom:1px;
32 | border-top:1px;
33 | }
34 |
35 |
36 | .marketgroupmain
37 | {
38 | position:fixed;
39 | width:98%;
40 | height:97%;
41 | margin: 5px;
42 | padding:5px;
43 | background-color: rgba(43, 43, 43, 0.95);
44 | border-radius: 2px;
45 | }
46 |
47 | #login-window {
48 | display: inline-block;
49 | border: 2px solid;
50 | border-radius: 25px;
51 | border-color: rgb(20,20,20);
52 | padding:10px;
53 | background-color: rgba(43, 43, 43, 0.95);
54 | }
55 | #login {
56 | color: rgb(200,200,200);
57 | }
58 | .marketgroupdiv {
59 | position:relative;
60 | overflow-x: hidden;
61 | overflow-y: auto;
62 | max-height:90%;
63 | width:25%;
64 | max-width:25%
65 | }
66 |
67 | .marketdisplaydiv {
68 | position:absolute;
69 | overflow: auto;
70 | max-height:90%;
71 | width:70%;
72 | max-width:70%;
73 | left:26%;
74 | top:3%;
75 | padding-left:5px;
76 | }
77 |
--------------------------------------------------------------------------------
/marketExplorer.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Sections of code from https://github.com/jimpurbrick/crestexplorerjs
3 | * Copyright 2012, CCP (http://www.ccpgames.com)
4 | * Dual licensed under the MIT or GPL Version 2 licenses.
5 | * http://www.opensource.org/licenses/mit-license.php
6 | * http://www.opensource.org/licenses/GPL-2.0
7 | *
8 | * All other code is under the MIT license.
9 | *
10 | */
11 |
12 |
13 | var endpoints;
14 | var regions=Array();
15 | var marketGroups;
16 | var currentRegion;
17 | var currentGroup;
18 |
19 | (function ($, window, document) {
20 |
21 | "use strict";
22 |
23 | // Configuration parameters
24 | var redirectUri = "https://www.fuzzwork.co.uk/market/viewer2/";
25 | var clientId = "f8c9bd2520064883ba1af73fafc1e486"; // OAuth client id
26 | var csrfTokenName = clientId + "csrftoken";
27 | var hashTokenName = clientId + "hash";
28 | var scopes = "publicData";
29 | var baseURL = "https://crest-tq.eveonline.com";
30 |
31 |
32 |
33 |
34 | // Show error message in main data pane.
35 | function displayError(error) {
36 | $("#data").children().replaceWith("
" + error + " ");
37 | }
38 |
39 | // Request uri and render as HTML.
40 | function render(uri) {
41 | if (uri.indexOf("http") !== 0) {
42 | displayError("Addresses must be absolute");
43 | return;
44 | }
45 | $.getJSON(uri, function(data, status, xhr) {
46 | $("#data").children().replaceWith(buildElement(data));
47 | bindLinks();
48 | });
49 | }
50 |
51 | function loadEndpoints() {
52 | $.getJSON(baseURL,function(data,status,xhr) {
53 | window.endpoints=data;
54 | loadRegions();
55 | loadMarketGroups();
56 | });
57 |
58 | }
59 |
60 | function loadRegions() {
61 |
62 | $.getJSON(window.endpoints["regions"].href,function(data,status,xhr) {
63 | $.each(data['items'],function(index,value){
64 | if (!value.name.match('.-R00')) {
65 | window.regions[value.name]=value.href;
66 | $("#regionSelector").append("
"+value.name+" ");
67 | }
68 | });
69 | $("#regionSelect").show();
70 | });
71 |
72 | }
73 |
74 | function loadMarketGroups() {
75 | $.getJSON(window.endpoints["marketGroups"].href,function(data,status,xhr) {
76 | marketGroups=data.items;
77 | $.map(marketGroups,function(group){
78 | if (typeof group.parentGroup === 'undefined') {
79 | $("#marketGroups").append("
"+group.name+" ");
80 | }
81 | }
82 | );
83 | $('.groupLink').click(function(event){event.stopPropagation();openSubGroup(event.target);});
84 | $("#marketgroupmain").show();
85 | });
86 |
87 |
88 | }
89 |
90 | function openSubGroup(group)
91 | {
92 | var node;
93 | var itemcount=0;
94 | if ($(group).children('ul').length>0) {
95 | $(group).children('ul').toggle();
96 | } else {
97 | $(group).append('
');
98 | node=$(group).children('ul');
99 | $.map(marketGroups,function(subgroup){
100 | if (typeof subgroup.parentGroup != 'undefined' && subgroup.parentGroup.href === group.dataset.cresthref) {
101 | node.append("
"+subgroup.name+" ");
102 | }
103 | if (subgroup.href === group.dataset.cresthref) {
104 | $.getJSON(subgroup.types.href,function(data,status,xhr) {
105 | $.map(data.items,function(item){
106 | if (item.marketGroup.href== group.dataset.cresthref) {
107 | node.append("
"+item.type.name+"");
108 | itemcount++;
109 | }
110 | });
111 | console.log(itemcount);
112 | if (itemcount>0) {
113 | console.log('items only');
114 | $('.itemLink').click(function(event){event.stopPropagation();openItem(event.target);});
115 | }
116 | });
117 | }
118 | });
119 | }
120 | }
121 |
122 | function openItem(item)
123 | {
124 | var buytable;
125 | var selltable;
126 | $('#MarketDisplay').show();
127 | console.log(item.dataset.cresthref);
128 | $.getJSON(item.dataset.cresthref,function(data,status,xhr) {
129 | $('#itemDescription').html(data.name+"
"+data.description);
130 | });
131 | if (typeof currentRegion != 'undefined') {
132 | buytable=$('#buy').DataTable();
133 | buytable.rows().remove();
134 | selltable=$('#sell').DataTable();
135 | selltable.rows().remove();
136 | $.getJSON(currentRegion.marketBuyOrders.href+'?type='+item.dataset.cresthref,function(data,status,xhr) {
137 | $.map(data.items,function(item){
138 | buytable.row.add([item.location.name,$.number(item.volume_str),item.minVolume_str,$.number(item.price,2),item.range,moment(item.issued).add(item.duration,'days').format("YYYY-MM-DD HH:mm")]);
139 | });
140 | buytable.draw();
141 |
142 | })
143 | $.getJSON(currentRegion.marketSellOrders.href+'?type='+item.dataset.cresthref,function(data,status,xhr) {
144 | $.map(data.items,function(item){
145 | selltable.row.add([item.location.name,$.number(item.volume_str),$.number(item.price,2),moment(item.issued).add(item.duration,'days').format("YYYY-MM-DD HH:mm")]);
146 | });
147 | selltable.draw();
148 | });
149 | } else {
150 | alert('Set a region to get data');
151 | }
152 |
153 | }
154 |
155 | function setLanguage() {
156 | var cookieok=confirm("This needs a cookie");
157 | if (cookieok){
158 | if ($("#language").val()=="Default") {
159 | $.cookie('market-language',null);
160 | } else {
161 | $.cookie('market-language',$("#language").val());
162 | }
163 | }
164 | }
165 |
166 | function loadRegionData() {
167 | $.getJSON($("#regionSelector").val(),function(data,status,xhr) {
168 | currentRegion=data;
169 | });
170 | }
171 |
172 |
173 | // Send Oauth token request on login, reset ajax Authorization header on logout.
174 | function onClickLogin(evt) {
175 | evt.preventDefault();
176 | var command = $("#login").text();
177 | if (command === "Login to Start Browsing the Market") {
178 |
179 | // Store CSRF token and current location as cookie
180 | var csrfToken = uuidGen();
181 | $.cookie(csrfTokenName, csrfToken);
182 | $.cookie(hashTokenName, window.location.hash);
183 |
184 | // No OAuth token, request one from the OAuth authentication endpoint
185 | window.location = "https://login.eveonline.com/oauth/authorize/" +
186 | "?response_type=token" +
187 | "&client_id=" + clientId +
188 | "&scope=" + scopes +
189 | "&redirect_uri=" + redirectUri +
190 | "&state=" + csrfToken;
191 |
192 | } else {
193 | ajaxSetup(false);
194 | loginSetup(false);
195 | }
196 | }
197 |
198 | // Extract value from oauth formatted hash fragment.
199 | function extractFromHash(name, hash) {
200 | var match = hash.match(new RegExp(name + "=([^&]+)"));
201 | return !!match && match[1];
202 | }
203 |
204 | // Generate an RFC4122 version 4 UUID
205 | function uuidGen() {
206 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
207 | var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
208 | return v.toString(16);
209 | });
210 | }
211 |
212 | function ajaxSetup(token) {
213 | var headers = {
214 | "Accept": "application/json, charset=utf-8"
215 | };
216 | if (token) {
217 | headers.Authorization = "Bearer " + token;
218 | }
219 | if ($.cookie('market-language')) {
220 | headers['Accept-Language'] = $.cookie('market-language');
221 | }
222 | $.ajaxSetup({
223 | accepts: "application/json, charset=utf-8",
224 | crossDomain: true,
225 | type: "GET",
226 | dataType: "json",
227 | headers: headers,
228 | error: function (xhr, status, error) {
229 | displayError(error);
230 | }
231 | });
232 | }
233 |
234 | function loginSetup(token) {
235 | $("#login").click(onClickLogin);
236 | }
237 |
238 | $(document).ready(function() {
239 |
240 | var hash = window.location.hash;
241 | var token = extractFromHash("access_token", hash);
242 | $('#buy').DataTable({
243 | "paging": false,
244 | "scrollY": "40%",
245 | "bFilter": false,
246 | "bInfo": false,
247 | "bAutoWidth": false,
248 | "bSortClasses": false,
249 | "bDeferRender": false,
250 | "sDom": 'C<"clear">lfrtip',
251 | "order":[[3,"desc"]],
252 | "columnDefs": [
253 | { className: "dt-left"},
254 | { className: "dt-right"},
255 | { className: "dt-right"},
256 | { className: "dt-right"},
257 | { className: "dt-right"},
258 | { className: "dt-right"}
259 | ]
260 |
261 | });
262 | $('#sell').DataTable({
263 | "paging": false,
264 | "scrollY": "40%",
265 | "bFilter": false,
266 | "bInfo": false,
267 | "bAutoWidth": false,
268 | "bSortClasses": false,
269 | "bDeferRender": false,
270 | "sDom": 'C<"clear">lfrtip',
271 | "order":[[2,"asc"]],
272 | "columnDefs": [
273 | { className: "dt-left"},
274 | { className: "dt-right"},
275 | { className: "dt-right"},
276 | { className: "dt-right"},
277 | { className: "dt-right"}
278 | ]
279 | });
280 |
281 | $("#MarketDisplay").hide();
282 |
283 | if (token) {
284 | ajaxSetup(token);
285 | // Check CSRF token in state matches token saved in cookie
286 | if(extractFromHash("state", hash) !== $.cookie(csrfTokenName)) {
287 | displayError("CSRF token mismatch");
288 | return;
289 | }
290 |
291 | // Restore hash.
292 | window.location.hash = $.cookie(hashTokenName);
293 |
294 | // Delete cookies.
295 | $.cookie(csrfTokenName, null);
296 | $.cookie(hashTokenName, null);
297 | $("#login-window").hide();
298 | loadEndpoints();
299 | } else {
300 | $("#regionSelect").hide();
301 | $(".marketgroupmain").hide();
302 | }
303 |
304 | loginSetup(token);
305 | $("#regionSelector").change(function() {
306 | loadRegionData();
307 | })
308 | $("#language").change(function() {
309 | setLanguage();
310 | })
311 | });
312 |
313 |
314 | }($, window, document)); // End crestexplorerjs
315 |
--------------------------------------------------------------------------------