This repository has been archived on 2026-05-13. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
RebolusyonMap/index.php
T
2026-05-13 23:25:30 +08:00

434 lines
14 KiB
PHP

<?php
include "connect.php";
$char_sql = "SELECT * FROM characters";
$char_result = mysqli_query($conn, $char_sql);
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Rebolusyon - Interactive Map and Timeline</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/vis-timeline@latest/standalone/umd/vis-timeline-graph2d.min.js"></script> <!-- VisTimeline JS -->
<link href="https://unpkg.com/vis-timeline@latest/styles/vis-timeline-graph2d.min.css" rel="stylesheet" type="text/css" /> <!-- VisTimeline CSS -->
<link href="dist/css/bootstrap.css" rel="stylesheet" type="text/css" /> <!-- Bootstrap CSS -->
<link rel="stylesheet" href="fontawesome/css/font-awesome.min.css"> <!-- FontAwesome v4 CSS -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="" /> <!-- Leaflet CSS -->
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script> <!-- Leaflet JS -->
<style type="text/css">
html, body, .container-fluid {
height: 100%;
}
#visualization {
font-size: 14px;
}
.vis-minor {
font-size: 12px;
}
.vis-item-content {
}
.test1 {
background-color: rgba(255, 0, 0, 0.2)
}
.test2 {
background-color: rgba(0, 255, 0, 0.2)
}
.test3 {
background-color: rgba(0, 0, 255, 0.2)
}
.txt14px {
font-size: 14px;
}
.indent15px{
text-indent: 15px;
}
#map {
/* min-width: 500px;*/
width: 100%;
min-height: 500px;
height: 100%;
}
/* width */
::-webkit-scrollbar {
width: 5px;
}
/* Track */
::-webkit-scrollbar-track {
background: #f1f1f1;
}
/* Handle */
::-webkit-scrollbar-thumb {
background: #888;
}
/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
background: #555;
}
</style>
</head>
<body>
<script type="text/javascript" src="dist/js/bootstrap.bundle.js"></script> <!-- Bootstrap JS -->
<div class="container-fluid d-flex flex-column">
<div class="row">
<h2 class="text-center">Rebolusyon</h2>
<span class="text-center">Interactive Map and Timeline</span>
<hr>
</div>
<div class="row flex-fill">
<div class="col-xxl-3 col-xl-3 col-lg-3 col-md-4 d-flex flex-column">
<div class="collapse" id="myCollapsible">
<div class="card text-bg-light mb-3 txt14px" id="rebolcardcontent" style="overflow-y: scroll; max-height:475px;">
<div class="card-body">
<h5 class="card-title rebol">Welcome!</h5>
<p class="card-text">entry message welcome</p>
</div>
</div>
</div>
</div>
<div class="col-xxl-7 col-xl-6 col-lg-6 col-md-8 d-flex flex-column">
<div id="map">
</div>
</div>
<div class="col-xxl-2 col-xl-3 col-lg-3 col-md-12 d-flex flex-column">
<div class="card">
<div class="card-body txt14px">
Select characters to show on timeline:
<br><br>
<ul class="list-group">
<?php
if(mysqli_num_rows($char_result) > 0) {
while ($row = mysqli_fetch_assoc($char_result)) {
$charid = $row["char_id"];
$char_name = $row["firstname"] . " " . $row["lastname"];
$checkbox_id = "chbx_char_" . $row["char_id"];
$onchangefunc = "testadd('" . $charid . "','" . $checkbox_id . "')";
echo '<li class="list-group-item input-group-sm">';
echo '<input class="form-check-input me-1" type="checkbox" value="" id="' . $checkbox_id . '" onchange="' . $onchangefunc . '">';
echo '<label class="form-check-label stretched-link txt14px" for="' . $checkbox_id . '">' . $char_name . '</label>';
echo '</li>';
}
} else {
echo "No characters";
}
?>
</ul>
</div>
</div>
</div>
</div>
<div class="row px-3">
<div class="card">
<div class="card-body txt14px">
Timeline Controls:
<button type="button" class="btn btn-sm" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Show All" id="fit">
<i class="fa fa-expand" aria-hidden="true" ></i>
</button>
<button type="button" class="btn btn-sm" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Zoom In" id="zoomIn">
<i class="fa fa-search-plus" aria-hidden="true"></i>
</button>
<button type="button" class="btn btn-sm" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Zoom Out" id="zoomOut">
<i class="fa fa-search-minus" aria-hidden="true"></i>
</button>
<button type="button" class="btn btn-sm" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Move Left"id="moveLeft">
<i class="fa fa-arrow-left" aria-hidden="true"></i>
</button>
<button type="button" class="btn btn-sm" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Move Right" id="moveRight">
<i class="fa fa-arrow-right" aria-hidden="true"></i>
</button>
<button class="btn btn-sm" onclick="openCard('event', '2')">
Test button
</button>
<!-- <button class="btn btn-sm" onclick="opencloseCollapse()">
Test button
</button> -->
<br />
<hr>
<div id="visualization"></div>
<div id="log"></div>
</div>
</div>
</div>
</div>
<!-- ---------------------------Timeline Data----------------------------- -->
<script type="text/javascript">
var cardopened = false;
var prev_card_id = "initial_card_id"; //prevents same card from reopening (id)
var prev_card_type = "welcome_card_id"; //prevents same card from reopening (type)
//Open Welcome card
opencloseCollapse();
//Initialize Tooltips
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
// Create Groups
var groups = new vis.DataSet();
// Create a DataSet (allows two way data-binding)
var items = new vis.DataSet();
// DOM element where the Timeline will be attached
var container = document.getElementById('visualization');
// Configuration for the Timeline
var options = {
width: '100%',
minHeight: '100px',
maxHeight: '250px',
min: new Date(1800, 1, 1), // lower limit of visible range
max: new Date(2000, 1, 1), // upper limit of visible range
zoomMin: 1000 * 60 * 60 * 24, // one day in milliseconds
// stack: false,
template: (itemData, element, data) => {
if (data.isCluster) {
return `<span class="cluster-header"></span><div> ${data.items.length} items </div>`;
}
else {
return `<div>${data.content}</div>`;
}
},
cluster: {
titleTemplate: "Cluster containing {count} events. Zoom in to see the individual events.",
maxItems: 2,
},
groupHeightMode: 'auto',
groupTemplate: function (group) {
var container = document.createElement("div");
var span = document.createElement("span");
var someparams = "'char','" + group.id + "'"
span.innerHTML = '<input type = "image" src="img/' + group.filename + '" onclick="openCard(' + someparams + ')" />'
container.insertAdjacentElement("beforeEnd", span);
return container;
}
};
// Create a Timeline
var timeline = new vis.Timeline(container, items, groups, options);
timeline.setGroups(groups);
//showall from start to end
document.getElementById("fit").onclick = function () {
timeline.fit();
};
//focus on selected item, open event card, and add location marker
timeline.on("doubleClick", function (properties) {
var selection = timeline.getSelection();
timeline.focus(selection);
var getselect = items.get(selection);
console.log(getselect[0]);
openCard('event', getselect[0].id);
addMarker(getselect[0].marker_coord, getselect[0].location_name);
});
//set timeline movement
function move(percentage) {
var range = timeline.getWindow();
var interval = range.end - range.start;
timeline.setWindow({
start: range.start.valueOf() - interval * percentage,
end: range.end.valueOf() - interval * percentage,
});
}
// attach events to the navigation buttons
document.getElementById("zoomIn").onclick = function () {
timeline.zoomIn(1);
};
document.getElementById("zoomOut").onclick = function () {
timeline.zoomOut(1);
};
document.getElementById("moveLeft").onclick = function () {
move(0.5);
};
document.getElementById("moveRight").onclick = function () {
move(-0.5);
};
function testadd(groupid, chbxid){
var yocheckbox = document.getElementById(chbxid);
if (yocheckbox.checked == true) {
add_char_group(groupid);
add_char_events(groupid);
} else {
deletechar(groupid);
}
}
//Add Character Group dynamically via Ajax
function add_char_group(groupid){
$.ajax({ //create an ajax request to addgroup.php
url:"addgroup.php",
method:"POST",
data:{id:groupid},
dataType:"JSON",
success: function(chardata){
groups.add(chardata);
}
})
}
//Add Character items on timeline and unhide group
function add_char_events(groupid){
$.ajax({ //create an ajax request to addgroup.php
url:"addevents.php",
method:"POST",
data:{id:groupid},
dataType:"JSON",
success: function(eventdata){
var result = JSON.parse(JSON.stringify(eventdata, null, 2));
items.add(result);
timeline.fit();
}
})
}
//test get info from specific items
function testselect(){
var getselect = items.get({
fields: ['id'],
filter: function (item) {
return (item.group == "jrizal");
}
})
}
//Remove Character items on timeline and hide group
function deletechar(groupid){
var getselect = items.get({
fields: ['id'],
filter: function (item) {
return (item.group == groupid);
}
})
items.remove(getselect);
groups.remove(groupid);
timeline.redraw();
}
//Bootstrap Collapse function called via javascript function
function openCard(content_type, content_id){
if (cardopened == false) { //if card is closed, update card contents immediately
updatecardcontents(content_type, content_id);
opencloseCollapse();
}
if (cardopened == true) {
if (prev_card_id != content_id) { //condition prevents reopening of the same card
opencardinstruction(content_type, content_id);
} else if (prev_card_id == content_id && prev_card_type != content_type) {
opencardinstruction(content_type, content_id);
}
}
}
//Open Card Instruction
function opencardinstruction(content_type, content_id){
opencloseCollapse();
setTimeout(function(){
updatecardcontents(content_type, content_id);
}, 400);
setTimeout(function(){
opencloseCollapse();
}, 500);
}
//Update contents in card
function updatecardcontents(content_type, content_id){
if (content_type == 'char') {
var getcharcontents = groups.get(content_id);
// document.getElementById("rebolcardcontent").innerHTML = "<h5 class='card-title rebol'>Char page</h5><div class='d-flex justify-content-center'><div class='spinner-border' role='status'></div></div>";
document.getElementById("rebolcardcontent").innerHTML = "<img src='img/card_img/" + getcharcontents.filename + "' class='card-img-top' alt=''><div class='card-body'><h5 class='card-title'>" + getcharcontents.content + "</h5><span class='text-secondary'>" + getcharcontents.title + "</span><br><span class='text-secondary'>" + getcharcontents.birth + " - " + getcharcontents.death + " (" + getcharcontents.age + " yrs old)</span><hr>" + getcharcontents.desc + "</div>";
}
if (content_type == "event"){
var geteventcontents = items.get(content_id);
var date_raw = new Date(geteventcontents.start_raw);
var date_formatted = formattedDate = new Intl.DateTimeFormat("en-US", { year: "numeric", month: "short", day: "2-digit",}).format(date_raw);
document.getElementById("rebolcardcontent").innerHTML = "<div class='card-body'><h5 class='card-title rebol'>" + geteventcontents.content + "</h5><h6>" + date_formatted + " - " + geteventcontents.location_name + "</h6>" + geteventcontents.desc + "</div>";
}
prev_card_id = content_id;
prev_card_type = content_type;
}
//Bootsrap Collapse toggle
function opencloseCollapse(){
var collapseElementList = [].slice.call(document.querySelectorAll('.collapse'))
var collapseList = collapseElementList.map(function (collapseEl) {
return new bootstrap.Collapse(collapseEl)
})
}
//Bootstrap Collapse trigger event after transition to shown
var myCollapsible = document.getElementById('myCollapsible')
myCollapsible.addEventListener('shown.bs.collapse', function () {
cardopened = true;
})
//Bootstrap Collapse trigger event after transition to hidden
var myCollapsible = document.getElementById('myCollapsible')
myCollapsible.addEventListener('hidden.bs.collapse', function () {
cardopened = false;
})
</script>
<!-- ---------------------------Leaflet Data----------------------------- -->
<script type="text/javascript">
console.log(L);
const map = L.map('map');
map.setView([14.5982,120.9718], 10);
L.tileLayer('https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}{r}.{ext}', {
minZoom: 0,
maxZoom: 16,
attribution: '&copy; <a href="https://www.stadiamaps.com/" target="_blank">Stadia Maps</a> &copy; <a href="https://openmaptiles.org/" target="_blank">OpenMapTiles</a> &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
ext: 'png'
}).addTo(map);
// L.marker([14.187234288690352, 121.12581741607673],{
// title: "Calamba",
// }).addTo(map);
function addMarker(marker_coord, location_name){
// console.log(marker_coord);
L.marker((marker_coord).split(','),{
title: location_name,
}).addTo(map);
// L.marker((marker_coord).split(',')).addTo(map);
map.flyTo((marker_coord).split(','));
}
</script>
</body>
</html>