434 lines
14 KiB
PHP
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: '© <a href="https://www.stadiamaps.com/" target="_blank">Stadia Maps</a> © <a href="https://openmaptiles.org/" target="_blank">OpenMapTiles</a> © <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>
|