This is an old revision of the document!
Designing Service: Using Research & Empathy to Assist Society 服務設計:透過研究與同理心創造包容性社會
Design and Change for Assistance and Pressure Alleviation of the Elderly, Stressed, and General Public 計畫如何做出改變來協助年長者及社會大眾紓解壓力
Some Website Highlights 一些網頁精彩亮點
<html loading = 'lazy'>
<head>
<title>Interactive buttons test</title> <style>
.buttons{
width: auto; height: 400px; } </style> <!--<link rel="icon" type="image/x-icon" href="./favicon.ico">--> <link rel="shortcut icon" href="#">
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/3.1.2/svg.min.js"></script> <script>
const destressingCanvas = SVG().addTo('body').size(400, 400) destressingCanvas.node.id = “button1” destressingCanvas.node.classList.add('buttons') const elderlyCanvas = SVG().addTo('body').size(400, 400) elderlyCanvas.node.id = “button2” elderlyCanvas.node.classList.add('buttons') const microCanvas = SVG().addTo('body').size(400, 400) microCanvas.node.id = “button3” microCanvas.node.classList.add('buttons') const hydraCanvas = SVG().addTo('body').size(400, 400) hydraCanvas.node.id = “button4” hydraCanvas.node.classList.add('buttons') const visualCanvas = SVG().addTo('body').size(400, 400) visualCanvas.node.id = “button5” visualCanvas.node.classList.add('buttons') const simulationCanvas = SVG().addTo('body').size(400, 400) simulationCanvas.node.id = “button6” simulationCanvas.node.classList.add('buttons') const studentsCanvas = SVG().addTo('body').size(400, 400) studentsCanvas.node.id = “button7” studentsCanvas.node.classList.add('buttons') const impressionCanvas = SVG().addTo('body').size(400, 400) impressionCanvas.node.id = “button8” put them in a HTML class impressionCanvas.node.classList.add('buttons') let allSvgs = [] let allSvgsObj = {} some notes: create a bunch of SVG canvas, and stuff different butotns in one by one. Make a function that activates buttons
function checkIfSVGjsElement(item) {
try { item.dmove(0, 0) return true } catch { return false }
}
function getAllShapes(svgArray, canvas) {
let newSvgArray = [] //console.log("svgArray: ") //console.log(svgArray) if (svgArray == undefined) { //console.log("destressingButton.children: ") //console.log(destressingButton.children()[0]) //console.log(canvas.children()[0].children()) //getAllShapes(destressingButton.children()[0].children()) //getAllShapes(destressingButton.children()[1].children()) canvas.children().forEach(e => { getAllShapes(e.children()) }) } else { svgArray.forEach(x => { if (x.type == 'g') { x.children().forEach(y => { //console.log(y) newSvgArray.push(y) }) } else if (x.type != 'defs' && x.type.includes('sodipodi') == false && checkIfSVGjsElement(x)) { //remove the css color, and replace it with the .fill() color in SVG.js //console.log(x) x.fill(x.node.style.fill) x.node.style = null; //console.log("here") //console.log(x) allSvgs.push(x) } }) } if (newSvgArray.length > 0) { getAllShapes(newSvgArray) }
}
from https://stackoverflow.com/questions/14446447/how-to-read-a-local-text-file-in-the-browser reads a text file function readTextFile(file) {
let rawFile = new XMLHttpRequest(); rawFile.open("GET", file, false); let allText; rawFile.onreadystatechange = function() { if (rawFile.readyState === 4) { if (rawFile.status === 200 || rawFile.status == 0) { allText = rawFile.responseText; //console.log(allText); } } } rawFile.send(null); return allText;
}
Change files to the format that we can use function readFile(input) { let file = input.files[0]; console.log('“file” in readFile function')
//console.log(file)
let reader = new FileReader();
reader.readAsText(file);
reader.onload = function() { //console.log(reader.result); };
reader.onerror = function() { //console.log(reader.error); }; return reader
}
code from Chat-GPT, https://chat.openai.com/chat/8884aedb-3f4d-4e14-87bf-d9cfe3223d90 function removeCamelCase(str) { Split the string into an array of words
let words = str.split(/(?=[A-Z])/);
// Remove the first word and join the remaining words with a space let result = words.slice(1).join(" ").toLowerCase();
return result;
}
put svgs into an object and use their ids as their keys function putSvgsInObject(svgArray, object, camelCase) { if (camelCase) { svgArray.forEach(e ⇒ object[removeCamelCase(e.node.id)] = e) } else { svgArray.forEach(e ⇒ object[e.node.id] = e) } } function printObject(obj) { for (const [key, value] of Object.entries(obj)) { console.log(`${key}: ${value}`)
}
}
function changeCursor(style) {
document.getElementsByTagName("body")[0].style.cursor = style
}
function displaySvgs(canvas, …files) {
//let svgXml = readTextFile(file) files.forEach(e => { canvas.svg(readTextFile(e)) }) //console.log(svgXml) //console.log(reader.result) //destressingButton.svg(reader.result) //destressingButton.svg(svgXml) getAllShapes(undefined, canvas) putSvgsInObject(allSvgs, allSvgsObj) //console.log(allSvgsObj) //console.log(allSvgs)
}
if (document.readyState === 'complete') { console.log(“hi9”) } from https://stackoverflow.com/questions/494143/creating-a-new-dom-element-from-an-html-string-using-built-in-dom-methods-or-pro function createElementFromHTML(htmlString) { var div = document.createElement('div'); div.innerHTML = htmlString.trim(); Change this to div.childNodes to support multiple top-level nodes. return div; } function makeSvgElement(directory, id){ let svgElement = createElementFromHTML(readFile(directory)) svgElement.id = id document.body.appendChild(svgElement) }
makeSvgElement(“./destressingButton.svg”, “destressingButton”) document.addEventListener('DOMContentLoaded', e ⇒ { document.appendChild(destressingButton) console.log(`Document is ready!`) })
displaySvgs(destressingCanvas, “https://renickbell.net/ed/2022service/lib/exe/fetch.php?media=destressingbutton.svg”)
displaySvgs(elderlyCanvas, “https://renickbell.net/ed/2022service/lib/exe/fetch.php?media=elderlybutton.svg”)
displaySvgs(microCanvas, “https://renickbell.net/ed/2022service/lib/exe/fetch.php?media=microbutton.svg”)
displaySvgs(hydraCanvas, “https://renickbell.net/ed/2022service/lib/exe/fetch.php?media=hydrabutton.svg”)
displaySvgs(visualCanvas, “https://renickbell.net/ed/2022service/lib/exe/fetch.php?media=visualbutton.svg”)
displaySvgs(simulationCanvas, “https://renickbell.net/ed/2022service/lib/exe/fetch.php?media=simulationbutton.svg”)
displaySvgs(studentsCanvas, “https://renickbell.net/ed/2022service/lib/exe/fetch.php?media=studentsbutton.svg”)
displaySvgs(impressionCanvas, “https://renickbell.net/ed/2022service/lib/exe/fetch.php?media=impressionbutton.svg”)
let destressingSvgs = []; let destressingSvgsObj = {};
let elderlySvgs = []; let elderlySvgsObj = {};
micro means micro-controllers let microSvgs = []; let microSvgsObj = {}; let simulationSvgs = []; let simulationSvgsObj = {}; educating public about hydra let hydraSvgs = []; let hydraSvgsObj = {};
visual cue let visualSvgs = []; let visualSvgsObj = {}; let studentsSvgs = []; let studentsSvgsObj = {}; image of the elderly (I ran out of keywords) let impressionSvgs = []; let impressionSvgsObj = {};
allSvgs.forEach(e ⇒ {
if (e.node.id.includes("destressing")) { destressingSvgs.push(e); putSvgsInObject(destressingSvgs, destressingSvgsObj, true); } else if (e.node.id.includes("elderly")) { elderlySvgs.push(e); putSvgsInObject(elderlySvgs, elderlySvgsObj, true); } else if (e.node.id.includes("micro")) { microSvgs.push(e); putSvgsInObject(microSvgs, microSvgsObj, true); } else if (e.node.id.includes("simulation")) { simulationSvgs.push(e); putSvgsInObject(simulationSvgs, simulationSvgsObj, true) } else if (e.node.id.includes("hydra")) { hydraSvgs.push(e); putSvgsInObject(hydraSvgs, hydraSvgsObj, true) } else if (e.node.id.includes("visual")) { visualSvgs.push(e); putSvgsInObject(visualSvgs, visualSvgsObj, true) } else if (e.node.id.includes("students")) { studentsSvgs.push(e); putSvgsInObject(studentsSvgs, studentsSvgsObj, true); } else if (e.node.id.includes("impression")) { impressionSvgs.push(e); putSvgsInObject(impressionSvgs, impressionSvgsObj, true); }
});
let animationDuration = 250; let buttonSize = 400;
let destressingGroup;
let descriptions = {
destressingDescription: destressingCanvas.text("Recognizing that everyone is stressed \nout, students designed and programmed \ninteractive digital images to reduce \nstress. To accomplish this, they used \nseveral JavaScript programming \nlibraries and physical computing.").move(19, 268).font({ family: 'arial', size: 20 }).opacity(0), elderlyDescription: elderlyCanvas.text("Another service that we are trying \nto provide this semester is a \nbiographical introduction of our \npartners at the Taipei Datong Elderly \nDaycare Center. These individuals \nwelcomed us and graciously shared \nstories from their lives, teaching us both \nabout what society was like in the \npast and also about some details of their \ncurrent activities and daily pursuits.").move(19, 268).font({ family: 'arial', size: 20 }).opacity(0), microDescription: microCanvas.text("We wanted to learn how to add unique \nphysical control to our stress-relieving \nimages. To accomplish this, we studied \nhow to build and program circuits which \ninvolve microcontrollers, particularly the \nArduino Uno microcontroller.").move(20, 268).font({ family: 'arial', size: 20 }).opacity(0), simulationDescription: simulationCanvas.text("A super big thanks to all our friends at \nthe Center for Innovation Taipei who \ntook valuable time from their busy \nworking schedules to help us out with \nour crazy simulations. Not only were \nthey required to wear our elderly \nsimulation suit, they had to undertake a \nseries of difficult tasks.").move(19, 268).font({ family: 'arial', size: 20 }).opacity(0), hydraDescription: hydraCanvas.text("Hydra is an image processing \nsoftware that we utilized this semester to \ncreate some interesting visual effects, \nlater utilizing it in the design of our \nde-stressing images for our elderly \nfriends.").move(19, 268).font({ family: 'arial', size: 20 }).opacity(0), visualDescriptions: visualCanvas.text("One of the services the students \ndesigned this semester was visual art \nthat could help with the alleviation of \nstress. An early step in this learning \nprocess involved the students \nexploring their own reactions to \ncertain visual stimulus, with input \ncoming from work from \nprofessional artists in the art field.").move(19, 268).font({ family: 'arial', size: 20, }).opacity(0), studentsDescription: studentsCanvas.text("This education program currently \ninvolves a small group of students. Each \nis unique and talented in their own way, \nwith different strengths and \ncontributions to our team.").move(19, 268).font({ family: 'arial', size: 20 }).opacity(0), impressionDescription: impressionCanvas.text("Among the main topics of this \nsemester's work was that of aging \nsociety and its elderly members. If we \nare to attempt to devise ideas to \nfacilitate an easier life experience for \nthese treasured members of our \ncommunity, we will need to start by \nconsidering their current role in the \nsocial group and how others perceive \nthem.").move(19, 268).font({ family: 'arial', size: 20 }).opacity(0)
}
let titles = {
destressingTitle: destressingCanvas.text("Destressing Images").move(168, 321.5).font({ family: 'arial', size: 19.5 }), elderlyTitle: elderlyCanvas.text("Elderly Biography").move(188, 321.5).font({ family: 'arial', size: 19.5 }), microTitle: microCanvas.text("Micro-controllers \nand Hydra").move(196.5, 302).font({ family: 'arial', size: 19.5, leading: '1em' }), simulationTitle: simulationCanvas.text("Elderly Simulation").move(184, 322).font({ size: 19.5, family: 'arial', }), hydraTitle: hydraCanvas.text("Educating the Public \nAbout Hydra").move(161, 302).font({ family: 'arial', size: 19.5, leading: "1em" }), visualTitle: visualCanvas.text("Perceptions \nof Visual Cues").move(215, 302).font({ family: 'arial', size: 19.5, leading: "1em" }), studentsTitle: studentsCanvas.text("About our Students").move(173.5, 322).font({ family: 'arial', size: 19.5 }), impressionTitle: impressionCanvas.text("Image of the Elderly").move(168, 321).font({ family: 'arial', size: 19.5 })
}
class Button {
constructor(name, description, title, svgsArray, svgsObj, titleShiftX, titleShiftY, descriptionShift) { this.name = name; this.description = description; this.title = title; this.svgsArray = svgsArray; this.svgsObj = svgsObj this.titleShift = { x: titleShiftX, y: titleShiftY } //descriptionShift only has one value because it is only shifting up this.descriptionShift = descriptionShift }
}
the dmove animation of titles different shifts of two lines titles and one line title, two lines titles have their special numbers distance between title and left side should be about 21px, and about 30px for the top distance let titleShifts = { destressing: { x: -150, y: -304 }, elderly: { x: -170, y: -304 }, micro: { x: -176, y: -282 }, hydra: { x: -140, y: -279.5 }, visual: { x: -195, y: -284 }, simulation: { x: -167, y: -304 }, students: { x: -152, y: -304 }, impression: { x: -150, y: -304 } } the dmove animation of descriptions this one only needs oneLine or twoLines opetions let descriptionShifts = { oneLine: -180, twoLines: -140 } —————————————————————————— /—————————————————————————— —————————————————————————— —————————————————————————— /!!!!!!!!super important here!!!!!!!!!!!!
last four numbers: title shift x, title shift y, description shift y let destressingButtonObject = new Button(“destressingButton”, descriptions.destressingDescription, titles.destressingTitle, destressingSvgs, destressingSvgsObj, titleShifts.destressing.x, titleShifts.destressing.y, descriptionShifts.oneLine) makeButton(destressingCanvas, destressingButtonObject, “https://renickbell.net/ed/2022service/doku.php?id=destressing-images”) let elderlyButtonObject = new Button(“elderlyButton”, descriptions.elderlyDescription, titles.elderlyTitle, elderlySvgs, elderlySvgsObj, titleShifts.elderly.x, titleShifts.elderly.y, descriptionShifts.oneLine) makeButton(elderlyCanvas, elderlyButtonObject, “https://renickbell.net/ed/2022service/doku.php?id=elderly-biography”) let microButtonObject = new Button(“microButton”, descriptions.microDescription, titles.microTitle, microSvgs, microSvgsObj, titleShifts.micro.x, titleShifts.micro.y, descriptionShifts.twoLines) makeButton(microCanvas, microButtonObject, “https://renickbell.net/ed/2022service/doku.php?id=arduino”) let hydraButtonObject = new Button(“hydraButton”, descriptions.hydraDescription, titles.hydraTitle, hydraSvgs, hydraSvgsObj, titleShifts.hydra.x, titleShifts.hydra.y, descriptionShifts.twoLines) makeButton(hydraCanvas, hydraButtonObject, “https://renickbell.net/ed/2022service/doku.php?id=social-innovation-center-sharing”) let visualButtonObject = new Button(“visualButton”, descriptions.visualDescriptions, titles.visualTitle, visualSvgs, visualSvgsObj, titleShifts.visual.x, titleShifts.visual.y, descriptionShifts.twoLines) makeButton(visualCanvas, visualButtonObject, “https://renickbell.net/ed/2022service/doku.php?id=art-museum”) let simulationButtonObject = new Button(“simulationButton”, descriptions.simulationDescription, titles.simulationTitle, simulationSvgs, simulationSvgsObj, titleShifts.simulation.x, titleShifts.simulation.y, descriptionShifts.oneLine) makeButton(simulationCanvas, simulationButtonObject, “https://renickbell.net/ed/2022service/doku.php?id=elderly-simulation-map”) let studentsButtonObject = new Button(“studentsButton”, descriptions.studentsDescription, titles.studentsTitle, studentsSvgs, studentsSvgsObj, titleShifts.students.x, titleShifts.students.y, descriptionShifts.oneLine) makeButton(studentsCanvas, studentsButtonObject, “https://renickbell.net/ed/2022service/doku.php?id=about-students”) let impressionButtonObject = new Button(“impressionButton”, descriptions.impressionDescription, titles.impressionTitle, impressionSvgs, impressionSvgsObj, titleShifts.impression.x, titleShifts.impression.y, descriptionShifts.oneLine) makeButton(impressionCanvas, impressionButtonObject, “https://renickbell.net/ed/2022service/doku.php?id=elderly-report”) let exampleButtonObj = { name: null, some name
description: null, //some description title: null, //some title svgsArray: null, //the somethingSvgs array of the button svgsObj: null //the somethingSvgsObj object of the button
}
function makeButton(svgCanvas, buttonObject, url) {
let titleRunner; let textBoxRunner; let backgroundRunner; let descriptionRunner; let svgsArray = buttonObject.svgsArray; let svgsObj = buttonObject.svgsObj; let buttonGroup = svgCanvas.group(); let textbox = svgsObj.textbox; let background = svgsObj.background; let image = svgsObj.image; let title = buttonObject.title; //console.log(textbox) let description = buttonObject.description; let titleShift = buttonObject.titleShift; //console.log(titleShift) //make the white box invisible background.opacity(0); //add them to a group so it is easier to move them together //buttonGroup.add(image).add(background).add(textbox).add(title).add(description) //buttonGroup.size(buttonSize, buttonSize) //buttonGroup.move(0, 0) let hitBox = svgCanvas.rect(buttonSize, buttonSize).move(0, 0).opacity(0); //title position let titleP = { x: title.x(), y: title.y() } //description position let descriptionP = { x: description.x(), y: description.y() }
let overAnimaton = true; let outAnimation = false; hitBox.on("mouseover", function() { changeCursor("pointer") if (overAnimaton) { //console.log("over") backgroundRunner = background.animate(animationDuration).opacity(0.8) textBoxRunner = textbox.animate(animationDuration).opacity(0) titleRunner = title.animate(animationDuration).dmove(titleShift.x, titleShift.y).font({ size: 36 }) descriptionRunner = description.animate(animationDuration).opacity(1).dmove(0, buttonObject.descriptionShift); outAnimation = true; } //animationTimer = setTimeout(() => {}, 0) }) hitBox.on("mouseout", function() { changeCursor("default") if (outAnimation) { //console.log("out") backgroundRunner = background.animate(animationDuration).opacity(0) textBoxRunner = textbox.animate(animationDuration).opacity(1) titleRunner = title.animate(animationDuration).move(titleP.x, titleP.y).font({ size: 19.5 }) descriptionRunner = description.animate(animationDuration).opacity(0).move(descriptionP.x, descriptionP.y) overAnimaton = false outAnimation = false let setOverAnimationToTrue = setTimeout(function() { overAnimaton = true }, 250) } //clearTimeout(animationTimer) }); hitBox.on("click", function() { window.location.href = url; });
//readFile function by: https://javascript.info/file
// Code based on: Kirill Shumilov https://jsfiddle.net/brusher/tgddv9pw/
// Everything should be ungrouped. And on the same layer. Object to path.
};
let buttonsCollection = document.getElementsByClassName(“buttons”)
let buttonsArray = […buttonsCollection]
let br = document.createElement(“br”)
let whereButtonsGo = document.getElementById(“some_website_highlights_一些網頁精彩亮點”)
whereButtonsGo.appendChild(br)
buttonsArray.forEach(i ⇒ whereButtonsGo.appendChild(i))
STEVE CODE: /* let startPoint; window.addEventListener(“touchstart”, function(e){ console.log('start',e.touches[0].clientX) startPoint=JSON.parse(JSON.stringify(new Point(e.touches[0].clientX,e.touches[0].clientY))) }) window.addEventListener(“touchend”, function(e){ console.log('end',e) if (startPoint.x<e.clientX){ console.log('swiped left',e.clientX) checkIfSwitchImageLeft(e.target) } else { console.log('swiped right') checkIfSwitchImageRight(e.target) } }) */ window.addEventListener('touchstart', handleTouchStart, false); window.addEventListener('touchmove', handleTouchMove, false); var xDown = null; var yDown = null; function getTouches(evt) { return evt.touches || browser API
evt.originalEvent.touches; // jQuery
}
function handleTouchStart(evt) {
const firstTouch = getTouches(evt)[0]; xDown = firstTouch.clientX; yDown = firstTouch.clientY;
};
let swipeCooldown=false function handleTouchMove(evt) { console.log('swipe 1')
if ( ! xDown || ! yDown ) { return; }
console.log('swipe 2')
var xUp = evt.touches[0].clientX; var yUp = evt.touches[0].clientY;
var xDiff = xDown - xUp; var yDiff = yDown - yUp; if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {/*most significant*/ if ( xDiff > 0 && swipeCooldown==false) { evt.preventDefault() console.log('swiped left') swipeCooldown=true checkIfSwitchImageLeft(evt.target) setTimeout(()=>{ swipeCooldown=false },500) } else if (swipeCooldown==false) { evt.preventDefault() console.log('swiped right') swipeCooldown=true checkIfSwitchImageRight(evt.target) setTimeout(()=>{ swipeCooldown=false },500) } } else { if ( yDiff > 0 ) { } else { } } /* reset values */ xDown = null; yDown = null;
};
swiping code by: https://stackoverflow.com/a/23230280/19515980 </script> </body> </html>