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);
|
||||
}
|
||||
$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) {
|
||||
return response()->json(['error' => $e->getMessage()], 404);
|
||||
}
|
||||
|
|
|
@ -78,16 +78,21 @@ class Link_interaction extends Model
|
|||
return $link_interaction;
|
||||
}
|
||||
|
||||
public function getTimes(string $link) {
|
||||
public static function getTimes(string $link) {
|
||||
$link_interaction = [];
|
||||
$link_interaction = Link_interaction::where('link', $link)->select('created_at')->get()->toArray();
|
||||
return $link_interaction;
|
||||
}
|
||||
|
||||
public function getCoordinates(string $link) {
|
||||
$link_interaction = [];
|
||||
public static function getCoordinates(string $link) {
|
||||
$coordinates = [];
|
||||
$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 {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
overflow-y: scroll;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
background-color: var(--background);
|
||||
color: white;
|
||||
|
@ -352,7 +353,7 @@ header nav a {
|
|||
display: flex;
|
||||
height: 1px;
|
||||
background-color: #888;
|
||||
width: 500%;
|
||||
width: calc(500% + 20px);
|
||||
transform: translateY(5px);
|
||||
}
|
||||
}
|
||||
|
@ -363,4 +364,20 @@ a button {
|
|||
align-self: center;
|
||||
font-size: 0.8em;
|
||||
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
|
||||
@endsection
|
||||
|
||||
@section('head')
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div id="banner-container" class="container">
|
||||
<h1>Details & Logs</h1>
|
||||
|
@ -64,7 +68,14 @@
|
|||
</form>
|
||||
</div>
|
||||
<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 id="stats" class="container">
|
||||
<h2>Link Clicks</h2>
|
||||
|
@ -87,4 +98,91 @@
|
|||
|
||||
@section('scripts')
|
||||
<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
|
Loading…
Reference in New Issue