Compare commits
2 Commits
c6f0058d62
...
e9b9a04a70
Author | SHA1 | Date |
---|---|---|
Notoric | e9b9a04a70 | |
Notoric | 1bc6b50727 |
|
@ -74,7 +74,9 @@ class ShortlinkController extends Controller
|
||||||
return response()->json(['error' => 'Unauthorized'], 401);
|
return response()->json(['error' => 'Unauthorized'], 401);
|
||||||
}
|
}
|
||||||
$countrylist = (new Link_interactionController)->getCountryArray($id);
|
$countrylist = (new Link_interactionController)->getCountryArray($id);
|
||||||
return view('details', ['shortlink' => $shortlink, 'countrylist' => $countrylist]);
|
$coordinates = Link_interaction::getCoordinates($id);
|
||||||
|
$timestamps = Link_interaction::getTimes($id);
|
||||||
|
return view('details', ['shortlink' => $shortlink, 'countrylist' => $countrylist, 'coordinates' => $coordinates, 'timestamps' => $timestamps]);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return response()->json(['error' => $e->getMessage()], 404);
|
return response()->json(['error' => $e->getMessage()], 404);
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,16 +78,21 @@ class Link_interaction extends Model
|
||||||
return $link_interaction;
|
return $link_interaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTimes(string $link) {
|
public static function getTimes(string $link) {
|
||||||
$link_interaction = [];
|
$link_interaction = [];
|
||||||
$link_interaction = Link_interaction::where('link', $link)->select('created_at')->get()->toArray();
|
$link_interaction = Link_interaction::where('link', $link)->select('created_at')->get()->toArray();
|
||||||
return $link_interaction;
|
return $link_interaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCoordinates(string $link) {
|
public static function getCoordinates(string $link) {
|
||||||
$link_interaction = [];
|
$coordinates = [];
|
||||||
$link_interaction = Link_interaction::where('link', $link)->select('latitude', 'longitude')->get()->toArray();
|
$link_interaction = Link_interaction::where('link', $link)->select('latitude', 'longitude')->get()->toArray();
|
||||||
return $link_interaction;
|
foreach ($link_interaction as $interaction) {
|
||||||
|
if ($interaction['latitude'] != null && $interaction['longitude'] != null) {
|
||||||
|
array_push($coordinates, $interaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $coordinates;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
overflow-y: scroll;
|
||||||
font-family: 'Roboto', sans-serif;
|
font-family: 'Roboto', sans-serif;
|
||||||
background-color: var(--background);
|
background-color: var(--background);
|
||||||
color: white;
|
color: white;
|
||||||
|
@ -352,7 +353,7 @@ header nav a {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
background-color: #888;
|
background-color: #888;
|
||||||
width: 500%;
|
width: calc(500% + 20px);
|
||||||
transform: translateY(5px);
|
transform: translateY(5px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -364,3 +365,19 @@ a button {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#graphs {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
#graphs h2 {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map {
|
||||||
|
width: 540px;
|
||||||
|
height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
Details & Logs
|
Details & Logs
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
@section('head')
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
|
||||||
|
@endsection
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div id="banner-container" class="container">
|
<div id="banner-container" class="container">
|
||||||
<h1>Details & Logs</h1>
|
<h1>Details & Logs</h1>
|
||||||
|
@ -64,7 +68,14 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div id="graphs" class="container">
|
<div id="graphs" class="container">
|
||||||
|
<div id="map-wrapper">
|
||||||
|
<h2>Heatmap</h2>
|
||||||
|
<div id="map"></div>
|
||||||
|
</div>
|
||||||
|
<div id="timeline-wrapper">
|
||||||
|
<h2>Timeline</h2>
|
||||||
|
<canvas id="cumulativeGraph" width="540" height="400"></canvas>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="stats" class="container">
|
<div id="stats" class="container">
|
||||||
<h2>Link Clicks</h2>
|
<h2>Link Clicks</h2>
|
||||||
|
@ -87,4 +98,91 @@
|
||||||
|
|
||||||
@section('scripts')
|
@section('scripts')
|
||||||
<script src="{{ asset('js/details.js') }}"></script>
|
<script src="{{ asset('js/details.js') }}"></script>
|
||||||
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||||
|
<script src="https://unpkg.com/leaflet.heat/dist/leaflet-heat.js"></script>
|
||||||
|
<script>
|
||||||
|
var map = L.map('map').setView([50, 0], 3);
|
||||||
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
|
maxZoom: 10,
|
||||||
|
}).addTo(map);
|
||||||
|
var heat = L.heatLayer([], {
|
||||||
|
radius: 50,
|
||||||
|
blur: 20,
|
||||||
|
maxZoom: 3,
|
||||||
|
max: 5,
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
async function loadHeatmapData() {
|
||||||
|
var data = [
|
||||||
|
@foreach ($coordinates as $coordinate)
|
||||||
|
{lat:{{ $coordinate['latitude'] }}, lng:{{ $coordinate['longitude'] }}},
|
||||||
|
@endforeach
|
||||||
|
];
|
||||||
|
heat.setLatLngs(data);
|
||||||
|
}
|
||||||
|
loadHeatmapData();
|
||||||
|
</script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns"></script>
|
||||||
|
<script>
|
||||||
|
const timestamps = [
|
||||||
|
@foreach ($timestamps as $timestamp)
|
||||||
|
'{{ $timestamp['created_at'] }}',
|
||||||
|
@endforeach
|
||||||
|
];
|
||||||
|
|
||||||
|
// Function to count occurrences cumulatively
|
||||||
|
function getCumulativeCounts(timestamps) {
|
||||||
|
const counts = [];
|
||||||
|
const dateCounts = {};
|
||||||
|
timestamps.forEach((timestamp) => {
|
||||||
|
const date = new Date(timestamp).toISOString(); // Get date part only
|
||||||
|
if (dateCounts[date]) {
|
||||||
|
dateCounts[date]++;
|
||||||
|
} else {
|
||||||
|
dateCounts[date] = 1;
|
||||||
|
}
|
||||||
|
counts.push({ date: date, count: Object.values(dateCounts).reduce((a, b) => a + b, 0) });
|
||||||
|
});
|
||||||
|
return counts;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the cumulative data
|
||||||
|
const cumulativeData = getCumulativeCounts(timestamps);
|
||||||
|
|
||||||
|
// Extract dates and counts for the chart
|
||||||
|
const labels = cumulativeData.map(data => data.date);
|
||||||
|
const data = cumulativeData.map(data => data.count);
|
||||||
|
|
||||||
|
// Create the chart
|
||||||
|
const ctx = document.getElementById('cumulativeGraph').getContext('2d');
|
||||||
|
const cumulativeGraph = new Chart(ctx, {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: labels,
|
||||||
|
datasets: [{
|
||||||
|
label: 'Total Clicks',
|
||||||
|
data: data,
|
||||||
|
borderColor: 'rgba(255, 0, 80, 1)',
|
||||||
|
backgroundColor: 'rgba(255, 0, 80, 0.2)',
|
||||||
|
borderWidth: 1,
|
||||||
|
fill: true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
type: 'time',
|
||||||
|
time: {
|
||||||
|
unit: 'day'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
beginAtZero: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
@endsection
|
@endsection
|
Loading…
Reference in New Issue