Atelier Forest
リゾート型リモートオフィス
アトリエ・フォレスト信州
現在休館中
Atelier Forest
shinsyu
長野県南佐久郡小海町豊里5151-139
〜八ヶ岳の絶景をバックに〜
充実の
一日を
お過ごし
ください
Internet WiFi6 / Open Terrace / Event Space
Coworking Space / Long Stay Room
Lounge & Terrace
Event Hall / Relux Space / Fireplace / BBQ
One day
Coworking Space / Audio Equipment /
Meeting Facility
Long stay
Weekly Stay / Bed Room / Business floor
Amenities
Luxury services and comfort where and when you need
日帰り型
コワーキングスペース
お好みの空間でリモートワーク
Dホール & テラス & 屋外で
※現在受付を停止しております。
滞在型
ワーケーションルーム
デスク・ベッド付きルーム
一泊からロングステイまで
クリエイティブな空間
大会議室
イベント・研修などに
80インチTVモニター利用可能
応接室(控室)
個室で集中作業や会議に
1時間区切りでご利用可能な
個室スペース
ソファーラウンジ
& BBQ
暖炉を囲んでリラックス
自由な時間を優雅に
夜は屋外でBBQ
Price
素敵な一日をお過ごしください。
完全予約制
現在予約受付停止中
当館ではご予約いただいた内容を会員様情報として保存しております。
Recommended
ワーケーションルーム
宿泊型ワーキングルーム
Single 7,000円
Twin 12,000円
一室一泊料金
チェックイン:10:00から
チェックアウト:8:00まで
デスク・ベッドあり
連泊も可能
※現在受付を停止しております。
ご入浴・お食事
八峰の湯(ヤッホーの湯)をご利用ください。
弊館・オプション
事前のご予約にて承っております。
※施設ご利用の方限定メニューとなります。
※お支払いは予約時又は現地にて可能です。
(現地の場合、現金またはクレジットカード可)
■お食事
【貸し出しセット】
バーベキューセット 1セット3,500円
(バーベキュー台、炭付き)癒やしの焚き火セット 1,500円
(キャンプファイヤー台, 薪1羽, 着火剤, マシュマロ2本付き)【パーティー・ディナー】
ケータリングの対応もお受けしております。
※事前にお問い合せの上、ご予約願います。- お問い合わせご利用に関するご質問がありましたら、ぜひお気軽にご連絡ください。
アクセス
〒384-1103
(小海美術館・八峰の湯 隣り)
Tel: 0267-93-2626
Mail: info@atelier-forest.jp
Estimate commute time
See travel time and directions for places nearby
Add destination
Add destination
Add destination
Delete
Cancel
Add
Done
'use strict';
/**
* Element selectors for commutes widget.
*/
const commutesEl = {
map: document.querySelector('.map-view'),
initialStatePanel: document.querySelector('.commutes-initial-state'),
destinationPanel: document.querySelector('.commutes-destinations'),
modal: document.querySelector('.commutes-modal-container'),
};
/**
* Element selectors for commutes destination panel.
*/
const destinationPanelEl = {
addButton: commutesEl.destinationPanel.querySelector('.add-button'),
container: commutesEl.destinationPanel.querySelector('.destinations-container'),
list: commutesEl.destinationPanel.querySelector('.destination-list'),
scrollLeftButton: commutesEl.destinationPanel.querySelector('.left-control'),
scrollRightButton: commutesEl.destinationPanel.querySelector('.right-control'),
getActiveDestination: () => commutesEl.destinationPanel.querySelector('.destination.active'),
};
/**
* Element selectors for commutes modal popup.
*/
const destinationModalEl = {
title: commutesEl.modal.querySelector('h2'),
form: commutesEl.modal.querySelector('form'),
destinationInput: commutesEl.modal.querySelector('input[name="destination-address"]'),
errorMessage: commutesEl.modal.querySelector('.error-message'),
addButton: commutesEl.modal.querySelector('.add-destination-button'),
deleteButton: commutesEl.modal.querySelector('.delete-destination-button'),
editButton: commutesEl.modal.querySelector('.edit-destination-button'),
cancelButton: commutesEl.modal.querySelector('.cancel-button'),
getTravelModeInput: () => commutesEl.modal.querySelector('input[name="travel-mode"]:checked'),
};
/**
* Max number of destination allowed to be added to commutes panel.
*/
const MAX_NUM_DESTINATIONS = 10;
/**
* Bounds to bias search within ~50km distance.
*/
const BIAS_BOUND_DISTANCE = 0.5;
/**
* Hour in seconds.
*/
const HOUR_IN_SECONDS = 3600;
/**
* Minutes in seconds.
*/
const MIN_IN_SECONDS = 60;
/**
* Stroke colors for destination direction polylines for different states.
*/
const STROKE_COLORS = {
active: {
innerStroke: '#4285F4',
outerStroke: '#185ABC',
},
inactive: {
innerStroke: '#BDC1C6',
outerStroke: '#80868B',
},
};
/**
* Marker icon colors for different states.
*/
const MARKER_ICON_COLORS = {
active: {
fill: '#EA4335',
stroke: '#C5221F',
label: '#FFF',
},
inactive: {
fill: '#F1F3F4',
stroke: '#9AA0A6',
label: '#3C4043',
},
};
/**
* List of operations to perform on destinations.
*/
const DestinationOperation = {
ADD: 'ADD',
EDIT: 'EDIT',
DELETE: 'DELETE',
};
/**
* List of available commutes travel mode.
*/
const TravelMode = {
DRIVING: 'DRIVING',
TRANSIT: 'TRANSIT',
BICYCLING: 'BICYCLING',
WALKING: 'WALKING',
};
/**
* Defines instance of Commutes widget to be instantiated when Map library
* loads.
*/
function Commutes(configuration) {
let commutesMap;
let activeDestinationIndex;
let origin = configuration.mapOptions.center;
let destinations = configuration.destination || [];
let markerIndex = 0;
let lastActiveEl;
const markerIconConfig = {
path:
'M10 27c-.2 0-.2 0-.5-1-.3-.8-.7-2-1.6-3.5-1-1.5-2-2.7-3-3.8-2.2-2.8-3.9-5-3.9-8.8C1 4.9 5 1 10 1s9 4 9 8.9c0 3.9-1.8 6-4 8.8-1 1.2-1.9 2.4-2.8 3.8-1 1.5-1.4 2.7-1.6 3.5-.3 1-.4 1-.6 1Z',
fillOpacity: 1,
strokeWeight: 1,
anchor: new google.maps.Point(15, 29),
scale: 1.2,
labelOrigin: new google.maps.Point(10, 9),
};
const originMarkerIcon = {
...markerIconConfig,
fillColor: MARKER_ICON_COLORS.active.fill,
strokeColor: MARKER_ICON_COLORS.active.stroke,
};
const destinationMarkerIcon = {
...markerIconConfig,
fillColor: MARKER_ICON_COLORS.inactive.fill,
strokeColor: MARKER_ICON_COLORS.inactive.stroke,
};
const bikeLayer = new google.maps.BicyclingLayer();
const publicTransitLayer = new google.maps.TransitLayer();
initMapView();
initDestinations();
initCommutesPanel();
initCommutesModal();
/**
* Initializes map view on commutes widget.
*/
function initMapView() {
const mapOptionConfig = configuration.mapOptions;
commutesMap = new google.maps.Map(commutesEl.map, mapOptionConfig);
configuration.defaultTravelModeEnum =
parseTravelModeEnum(configuration.defaultTravelMode);
setTravelModeLayer(configuration.defaultTravelModeEnum);
createMarker(origin);
}
/**
* Initializes commutes widget with destinations info if provided with a list
* of initial destinations and update view.
*/
function initDestinations() {
if (!configuration.initialDestinations) return;
let callbackCounter = 0;
const placesService = new google.maps.places.PlacesService(commutesMap);
for (const destination of configuration.initialDestinations) {
destination.travelModeEnum = parseTravelModeEnum(destination.travelMode);
const label = getNextMarkerLabel();
const request = {
placeId: destination.placeId,
fields: ['place_id', 'geometry', 'name'],
};
placesService.getDetails(
request,
function(place) {
if (!place.geometry || !place.geometry.location) return;
const travelModeEnum =
destination.travelModeEnum || configuration.defaultTravelModeEnum;
const destinationConfig =
createDestinationConfig(place, travelModeEnum, label);
getDirections(destinationConfig).then((response) => {
if (!response) return;
destinations.push(destinationConfig);
getCommutesInfo(response, destinationConfig);
callbackCounter++;
// Update commutes panel and click event objects after getting
// direction to all destinations.
if (callbackCounter === configuration.initialDestinations.length) {
destinations.sort(function(a, b) {
return a.label < b.label ? -1 : 1;
});
let bounds = new google.maps.LatLngBounds();
for (let i = 0; i < destinations.length; i++) {
assignMapObjectListeners(destinations[i], i);
updateCommutesPanel(destinations[i], i, DestinationOperation.ADD);
bounds.union(destinations[i].bounds);
}
const lastIndex = destinations.length - 1;
handleRouteClick(destinations[lastIndex], lastIndex);
commutesMap.fitBounds(bounds);
}
});
},
() => {
console.error('Failed to retrieve places info due to ' + e);
});
}
}
/**
* Initializes the bottom panel for updating map view and displaying commutes
* info.
*/
function initCommutesPanel() {
const addCommutesButtonEls = document.querySelectorAll('.add-button');
addCommutesButtonEls.forEach(addButton => {
addButton.addEventListener('click', () => {
destinationModalEl.title.innerHTML = 'Add destination';
hideElement(destinationModalEl.deleteButton);
hideElement(destinationModalEl.editButton);
showElement(destinationModalEl.addButton);
showModal();
const travelModeEnum = configuration.defaultTravelModeEnum || TravelMode.DRIVING;
const travelModeId = travelModeEnum.toLowerCase() + '-mode';
document.forms['destination-form'][travelModeId].checked = true;
});
});
destinationPanelEl.scrollLeftButton.addEventListener(
'click', handleScrollButtonClick);
destinationPanelEl.scrollRightButton.addEventListener(
'click', handleScrollButtonClick);
destinationPanelEl.list.addEventListener('keydown', (e) => {
if (e.key === 'Enter' &&
e.target !== destinationPanelEl.getActiveDestination()) {
e.target.click();
e.preventDefault();
}
});
}
/**
* Initializes commutes modal to gathering destination inputs. Configures the
* event target listeners to update view and behaviors on the modal.
*/
function initCommutesModal() {
const boundConfig = {
north: origin.lat + BIAS_BOUND_DISTANCE,
south: origin.lat - BIAS_BOUND_DISTANCE,
east: origin.lng + BIAS_BOUND_DISTANCE,
west: origin.lng - BIAS_BOUND_DISTANCE,
};
const destinationFormReset = function() {
destinationModalEl.destinationInput.classList.remove('error');
destinationModalEl.errorMessage.innerHTML = '';
destinationModalEl.form.reset();
destinationToAdd = null;
};
const autocompleteOptions = {
bounds: boundConfig,
fields: ['place_id', 'geometry', 'name'],
};
const autocomplete = new google.maps.places.Autocomplete(
destinationModalEl.destinationInput, autocompleteOptions);
let destinationToAdd;
autocomplete.addListener('place_changed', () => {
const place = autocomplete.getPlace();
if (!place.geometry || !place.geometry.location) {
return;
} else {
destinationToAdd = place;
destinationModalEl.getTravelModeInput().focus();
}
destinationModalEl.destinationInput.classList.remove('error');
destinationModalEl.errorMessage.innerHTML = '';
});
destinationModalEl.addButton.addEventListener('click', () => {
const isValidInput = validateDestinationInput(destinationToAdd);
if (!isValidInput) return;
const selectedTravelMode = destinationModalEl.getTravelModeInput().value;
addDestinationToList(destinationToAdd, selectedTravelMode);
destinationFormReset();
hideModal();
});
destinationModalEl.editButton.addEventListener('click', () => {
const destination = {...destinations[activeDestinationIndex]};
const selectedTravelMode = destinationModalEl.getTravelModeInput().value;
const isSameDestination =
destination.name === destinationModalEl.destinationInput.value;
const isSameTravelMode = destination.travelModeEnum === selectedTravelMode;
if (isSameDestination && isSameTravelMode) {
hideModal();
return;
}
if (!isSameDestination) {
const isValidInput = validateDestinationInput(destinationToAdd);
if (!isValidInput) return;
destination.name = destinationToAdd.name;
destination.place_id = destinationToAdd.place_id;
destination.url = generateMapsUrl(destinationToAdd, selectedTravelMode);
}
if (!isSameTravelMode) {
destination.travelModeEnum = selectedTravelMode;
destination.url = generateMapsUrl(destination, selectedTravelMode);
}
destinationFormReset();
getDirections(destination)
.then((response) => {
if (!response) return;
const currentIndex = activeDestinationIndex;
// Remove current active direction before replacing it with updated
// routes.
removeDirectionsFromMapView(destination);
destinations[activeDestinationIndex] = destination;
getCommutesInfo(response, destination);
assignMapObjectListeners(destination, activeDestinationIndex);
updateCommutesPanel(
destination, activeDestinationIndex, DestinationOperation.EDIT);
handleRouteClick(destination, activeDestinationIndex);
const newEditButton = destinationPanelEl.list.children
.item(activeDestinationIndex)
.querySelector('.edit-button');
newEditButton.focus();
})
.catch((e) => console.error('Editing directions failed due to ' + e));
hideModal();
});
destinationModalEl.cancelButton.addEventListener('click', () => {
destinationFormReset();
hideModal();
});
destinationModalEl.deleteButton.addEventListener('click', () => {
removeDirectionsFromMapView(destinations[activeDestinationIndex]);
updateCommutesPanel(
destinations[activeDestinationIndex], activeDestinationIndex,
DestinationOperation.DELETE);
activeDestinationIndex = undefined;
destinationFormReset();
let elToFocus;
if (destinations.length) {
const lastIndex = destinations.length - 1;
handleRouteClick(destinations[lastIndex], lastIndex);
elToFocus = destinationPanelEl.getActiveDestination();
} else {
elToFocus = commutesEl.initialStatePanel.querySelector('.add-button');
}
hideModal(elToFocus);
});
window.onmousedown = function(event) {
if (event.target === commutesEl.modal) {
destinationFormReset();
hideModal();
}
};
commutesEl.modal.addEventListener('keydown', (e) => {
switch(e.key) {
case 'Enter':
if (e.target === destinationModalEl.cancelButton ||
e.target === destinationModalEl.deleteButton) {
return;
}
if (destinationModalEl.addButton.style.display !== 'none') {
destinationModalEl.addButton.click();
} else if (destinationModalEl.editButton.style.display !== 'none') {
destinationModalEl.editButton.click();
}
break;
case "Esc":
case "Escape":
hideModal();
break;
default:
return;
}
e.preventDefault();
});
// Trap focus in the modal so that tabbing on the last interactive element
// focuses on the first, and shift-tabbing on the first interactive element
// focuses on the last.
const firstInteractiveElement = destinationModalEl.destinationInput;
const lastInteractiveElements = [
destinationModalEl.addButton,
destinationModalEl.editButton,
];
firstInteractiveElement.addEventListener(
'keydown', handleFirstInteractiveElementTab);
for (const el of lastInteractiveElements) {
el.addEventListener('keydown', handleLastInteractiveElementTab);
}
function handleFirstInteractiveElementTab(event) {
if (event.key === 'Tab' && event.shiftKey) {
for (const el of lastInteractiveElements) {
if (el.style.display !== 'none') {
event.preventDefault();
el.focus();
return;
}
}
}
}
function handleLastInteractiveElementTab(event) {
if (event.key === 'Tab' && !event.shiftKey) {
event.preventDefault();
firstInteractiveElement.focus();
}
}
}
/**
* Checks if destination input is valid and ensure no duplicate places or more
* than max number places are added.
*/
function validateDestinationInput(destinationToAdd) {
let errorMessage;
let isValidInput = false;
if (!destinationToAdd) {
errorMessage = 'No details available for destination input';
} else if (destinations.length > MAX_NUM_DESTINATIONS) {
errorMessage =
'Cannot add more than ' + MAX_NUM_DESTINATIONS + ' destinations';
} else if (
destinations &&
destinations.find(
destination =>
destination.place_id === destinationToAdd.place_id)) {
errorMessage = 'Destination is already added';
} else {
isValidInput = true;
}
if (!isValidInput) {
destinationModalEl.errorMessage.innerHTML = errorMessage;
destinationModalEl.destinationInput.classList.add('error');
}
return isValidInput;
}
/**
* Removes polylines and markers of currently active directions.
*/
function removeDirectionsFromMapView(destination) {
destination.polylines.innerStroke.setMap(null);
destination.polylines.outerStroke.setMap(null);
destination.marker.setMap(null);
}
/**
* Generates destination card template, attach event target listeners, and
* adds template to destination list depending on the operations:
* - add new destination card template to the end of the list on add.
* - replace destination card template for current selected on edit.
* - do nothing on default or delete.
*/
function buildDestinationCardTemplate(
destination, destinationIdx, destinationOperation) {
let editButtonEl;
switch (destinationOperation) {
case DestinationOperation.ADD:
destinationPanelEl.list.insertAdjacentHTML(
'beforeend',
'
' +
generateDestinationTemplate(destination) + '
');
const destinationContainerEl = destinationPanelEl.list.lastElementChild;
destinationContainerEl.addEventListener('click', () => {
handleRouteClick(destination, destinationIdx);
});
editButtonEl = destinationContainerEl.querySelector('.edit-button');
destinationPanelEl.container.scrollLeft =
destinationPanelEl.container.scrollWidth;
break;
case DestinationOperation.EDIT:
const activeDestinationContainerEl =
destinationPanelEl.getActiveDestination().parentElement;
activeDestinationContainerEl.innerHTML = generateDestinationTemplate(destination);
activeDestinationContainerEl.addEventListener('click', () => {
handleRouteClick(destination, destinationIdx);
});
editButtonEl = activeDestinationContainerEl.querySelector('.edit-button');
break;
case DestinationOperation.DELETE:
default:
}
editButtonEl.addEventListener('click', () => {
destinationModalEl.title.innerHTML = 'Edit destination';
destinationModalEl.destinationInput.value = destination.name;
showElement(destinationModalEl.deleteButton);
showElement(destinationModalEl.editButton);
hideElement(destinationModalEl.addButton);
showModal();
const travelModeId = destination.travelModeEnum.toLowerCase() + '-mode';
document.forms['destination-form'][travelModeId].checked = true;
// Update the autocomplete widget as if it was user input.
destinationModalEl.destinationInput.dispatchEvent(new Event('input'));
});
}
/**
* Updates view of commutes panel depending on the operation:
* - build/update destination template if add or edit.
* - remove destination from destination list and rebuild template.
*/
function updateCommutesPanel(
destination, destinationIdx, destinationOperation) {
switch (destinationOperation) {
case DestinationOperation.ADD:
hideElement(commutesEl.initialStatePanel);
showElement(commutesEl.destinationPanel);
// fall through
case DestinationOperation.EDIT:
buildDestinationCardTemplate(
destination, destinationIdx, destinationOperation);
break;
case DestinationOperation.DELETE:
destinations.splice(destinationIdx, 1);
destinationPanelEl.list.innerHTML = '';
for (let i = 0; i < destinations.length; i++) {
buildDestinationCardTemplate(
destinations[i], i, DestinationOperation.ADD);
assignMapObjectListeners(destinations[i], i);
}
default:
}
if (!destinations.length) {
showElement(commutesEl.initialStatePanel, commutesEl.initialStatePanel);
hideElement(commutesEl.destinationPanel);
activeDestinationIndex = undefined;
return;
}
destinationPanelEl.container.addEventListener('scroll', handlePanelScroll);
destinationPanelEl.container.dispatchEvent(new Event('scroll'));
}
/**
* Adds new destination to the list and get directions and commutes info.
*/
function addDestinationToList(destinationToAdd, travelModeEnum) {
const destinationConfig =
createDestinationConfig(destinationToAdd, travelModeEnum);
const newDestinationIndex = destinations.length;
getDirections(destinationConfig)
.then((response) => {
if (!response) return;
destinations.push(destinationConfig);
getCommutesInfo(response, destinationConfig);
assignMapObjectListeners(destinationConfig, newDestinationIndex);
updateCommutesPanel(
destinationConfig, newDestinationIndex, DestinationOperation.ADD);
handleRouteClick(destinationConfig, newDestinationIndex);
destinationPanelEl.addButton.focus();
})
.catch((e) => console.error('Adding destination failed due to ' + e));
}
/**
* Returns a new marker label on each call. Marker labels are the capital
* letters of the alphabet in order.
*/
function getNextMarkerLabel() {
const markerLabels = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const label = markerLabels[markerIndex];
markerIndex = (markerIndex + 1) % markerLabels.length;
return label;
}
/**
* Creates a destination config object from the given data. The label argument
* is optional; a new label will be generated if not provided.
*/
function createDestinationConfig(destinationToAdd, travelModeEnum, label) {
return {
name: destinationToAdd.name,
place_id: destinationToAdd.place_id,
label: label || getNextMarkerLabel(),
travelModeEnum: travelModeEnum,
url: generateMapsUrl(destinationToAdd, travelModeEnum),
};
}
/**
* Gets directions to destination from origin, add route to map view, and
* update commutes panel with distance and directions info.
*/
function getDirections(destination) {
const request = {
origin: origin,
destination: {'placeId': destination.place_id},
travelMode: destination.travelModeEnum,
unitSystem: configuration.distanceMeasurementType === 'METRIC' ?
google.maps.UnitSystem.METRIC : google.maps.UnitSystem.IMPERIAL,
};
const directionsService = new google.maps.DirectionsService();
return directionsService.route(request).then(response => {
return response;
});
}
/**
* Adds route polyline, marker, and commutes info to map and destinations
* list.
*/
function getCommutesInfo(directionResponse, destination) {
if (!directionResponse) return;
const path = directionResponse.routes[0].overview_path;
const bounds = directionResponse.routes[0].bounds;
const directionLeg = directionResponse.routes[0].legs[0];
const destinationLocation = directionLeg.end_location;
const distance = directionLeg.distance.text;
const duration = convertDurationValueAsString(directionLeg.duration.value);
const innerStroke = new google.maps.Polyline({
path: path,
strokeColor: STROKE_COLORS.inactive.innerStroke,
strokeOpacity: 1.0,
strokeWeight: 3,
zIndex: 10
});
const outerStroke = new google.maps.Polyline({
path: path,
strokeColor: STROKE_COLORS.inactive.outerStroke,
strokeOpacity: 1.0,
strokeWeight: 6,
zIndex: 1
});
const marker = createMarker(destinationLocation, destination.label);
innerStroke.setMap(commutesMap);
outerStroke.setMap(commutesMap);
destination.distance = distance;
destination.duration = duration;
destination.marker = marker;
destination.polylines = {innerStroke, outerStroke};
destination.bounds = bounds;
}
/**
* Assigns event target listeners to map objects of corresponding destination
* index.
*/
function assignMapObjectListeners(destination, destinationIdx) {
google.maps.event.clearListeners(destination.marker, 'click');
google.maps.event.addListener(destination.marker, 'click', () => {
handleRouteClick(destination, destinationIdx);
destinationPanelEl.list.querySelectorAll('.destination')[destinationIdx].focus();
});
google.maps.event.addListener(destination.marker, 'mouseover', () => {
changeMapObjectStrokeWeight(destination, true);
});
google.maps.event.addListener(destination.marker, 'mouseout', () => {
changeMapObjectStrokeWeight(destination, false);
});
for (const strokeLine in destination.polylines) {
google.maps.event.clearListeners(destination.polylines[strokeLine], 'click');
google.maps.event.clearListeners(destination.polylines[strokeLine], 'mouseover');
google.maps.event.addListener(destination.polylines[strokeLine], 'click', () => {
handleRouteClick(destination, destinationIdx);
destinationPanelEl.list.querySelectorAll('.destination')[destinationIdx].focus();
});
google.maps.event.addListener(destination.polylines[strokeLine], 'mouseover', () => {
changeMapObjectStrokeWeight(destination, true);
});
google.maps.event.addListener(destination.polylines[strokeLine], 'mouseout', () => {
changeMapObjectStrokeWeight(destination, false);
});
}
}
/**
* Generates the Google Map url for direction from origin to destination with
* corresponding travel mode.
*/
function generateMapsUrl(destination, travelModeEnum) {
let googleMapsUrl = 'https://www.google.com/maps/dir/?api=1';
googleMapsUrl += `&origin=${origin.lat},${origin.lng}`;
googleMapsUrl += '&destination=' + encodeURIComponent(destination.name) +
'&destination_place_id=' + destination.place_id;
googleMapsUrl += '&travelmode=' + travelModeEnum.toLowerCase();
return googleMapsUrl;
}
/**
* Handles changes to destination polyline and map icon stroke weight.
*/
function changeMapObjectStrokeWeight(destination, mouseOver) {
const destinationMarkerIcon = destination.marker.icon;
if (mouseOver) {
destination.polylines.outerStroke.setOptions({strokeWeight: 8});
destinationMarkerIcon.strokeWeight = 2;
destination.marker.setIcon(destinationMarkerIcon);
}
else {
destination.polylines.outerStroke.setOptions({strokeWeight: 6});
destinationMarkerIcon.strokeWeight = 1;
destination.marker.setIcon(destinationMarkerIcon);
}
}
/**
* Handles route clicks. Originally active routes are set to inactive
* states. Newly selected route's map polyline/marker objects and destination
* template are assigned active class styling and coloring.
*/
function handleRouteClick(destination, destinationIdx) {
if (activeDestinationIndex !== undefined) {
// Set currently active stroke to inactive
destinations[activeDestinationIndex].polylines.innerStroke.setOptions(
{strokeColor: STROKE_COLORS.inactive.innerStroke, zIndex: 2});
destinations[activeDestinationIndex].polylines.outerStroke.setOptions(
{strokeColor: STROKE_COLORS.inactive.outerStroke, zIndex: 1});
// Set current active marker to grey
destinations[activeDestinationIndex].marker.setIcon(
destinationMarkerIcon);
destinations[activeDestinationIndex].marker.label.color =
MARKER_ICON_COLORS.inactive.label;
// Remove styling of current active destination.
const activeDestinationEl = destinationPanelEl.getActiveDestination();
if (activeDestinationEl) {
activeDestinationEl.classList.remove('active');
}
}
activeDestinationIndex = destinationIdx;
setTravelModeLayer(destination.travelModeEnum);
// Add active class
const newDestinationEl = destinationPanelEl.list.querySelectorAll(
'.destination')[destinationIdx];
newDestinationEl.classList.add('active');
// Scroll into view
newDestinationEl.scrollIntoView({behavior: 'smooth', block: 'center'});
// Make line active
destination.polylines.innerStroke.setOptions(
{strokeColor: STROKE_COLORS.active.innerStroke, zIndex: 101});
destination.polylines.outerStroke.setOptions(
{strokeColor: STROKE_COLORS.active.outerStroke, zIndex: 99});
destination.marker.setIcon(originMarkerIcon);
destination.marker.label.color = '#ffffff';
commutesMap.fitBounds(destination.bounds);
}
/**
* Generates new marker based on location and label.
*/
function createMarker(location, label) {
const isOrigin = label === undefined ? true : false;
const markerIconConfig = isOrigin ? originMarkerIcon : destinationMarkerIcon;
const labelColor = isOrigin ? MARKER_ICON_COLORS.active.label :
MARKER_ICON_COLORS.inactive.label;
const labelText = isOrigin ? '●' : label;
const mapOptions = {
position: location,
map: commutesMap,
label: {
text: labelText,
fontFamily: 'Arial, sans-serif',
color: labelColor,
fontSize: '16px',
},
icon: markerIconConfig
};
if (isOrigin) {
mapOptions.label.className += ' origin-pin-label';
mapOptions.label.fontSize = '20px';
}
const marker = new google.maps.Marker(mapOptions);
return marker;
}
/**
* Returns a TravelMode enum parsed from the input string, or null if no match is found.
*/
function parseTravelModeEnum(travelModeString) {
switch (travelModeString) {
case 'DRIVING':
return TravelMode.DRIVING;
case 'BICYCLING':
return TravelMode.BICYCLING;
case 'PUBLIC_TRANSIT':
return TravelMode.TRANSIT;
case 'WALKING':
return TravelMode.WALKING;
default:
return null;
}
}
/**
* Sets map layer depending on the chosen travel mode.
*/
function setTravelModeLayer(travelModeEnum) {
switch (travelModeEnum) {
case TravelMode.BICYCLING:
publicTransitLayer.setMap(null);
bikeLayer.setMap(commutesMap);
break;
case TravelMode.TRANSIT:
bikeLayer.setMap(null);
publicTransitLayer.setMap(commutesMap);
break;
default:
publicTransitLayer.setMap(null);
bikeLayer.setMap(null);
}
}
/**
* Convert time from durationValue in seconds into readable string text.
*/
function convertDurationValueAsString(durationValue) {
if (!durationValue) {
return '';
}
if (durationValue < MIN_IN_SECONDS) {
return '<1 min';
}
if (durationValue > HOUR_IN_SECONDS * 10) {
return '10+ hours';
}
const hours = Math.floor(durationValue / HOUR_IN_SECONDS);
const minutes = Math.floor(durationValue % HOUR_IN_SECONDS / 60);
const hoursString = hours > 0 ? hours + ' h' : '';
const minutesString = minutes > 0 ? minutes + ' min' : '';
const spacer = hoursString && minutesString ? ' ' : '';
return hoursString + spacer + minutesString;
}
/**
* Shows the destination modal window, saving a reference to the currently
* focused element so that focus can be restored by hideModal().
*/
function showModal() {
lastActiveEl = document.activeElement;
showElement(commutesEl.modal, destinationModalEl.destinationInput);
}
/**
* Hides the destination modal window, setting focus to focusEl if provided.
* If no argument is passed, focus is restored to where it was when
* showModal() was called.
*/
function hideModal(focusEl) {
hideElement(commutesEl.modal, focusEl || lastActiveEl);
}
}
/**
* Hides a DOM element and optionally focuses on focusEl.
*/
function hideElement(el, focusEl) {
el.style.display = 'none';
if (focusEl) focusEl.focus();
}
/**
* Shows a DOM element that has been hidden and optionally focuses on focusEl.
*/
function showElement(el, focusEl) {
el.style.display = 'flex';
if (focusEl) focusEl.focus();
}
/**
* Event handler function for scroll buttons.
*/
function handleScrollButtonClick(e) {
const multiplier = 1.25;
const direction = e.target.dataset.direction;
const cardWidth = destinationPanelEl.list.firstElementChild.offsetWidth;
destinationPanelEl.container.scrollBy(
{left: (direction * cardWidth * multiplier), behavior: 'smooth'});
}
/**
* Event handler on scroll to add scroll buttons only if scroll width is larger
* than width. Hide scroll buttons if scrolled to the start or end of the panel.
*/
function handlePanelScroll() {
const position = destinationPanelEl.container.scrollLeft;
const scrollWidth = destinationPanelEl.container.scrollWidth;
const width = destinationPanelEl.container.offsetWidth;
if (scrollWidth > width) {
if (position === 0) {
destinationPanelEl.scrollLeftButton.classList.remove('visible');
} else {
destinationPanelEl.scrollLeftButton.classList.add('visible');
}
if (Math.ceil(position + width) >= scrollWidth) {
destinationPanelEl.scrollRightButton.classList.remove('visible');
} else {
destinationPanelEl.scrollRightButton.classList.add('visible');
}
}
}
/**
* Generates new destination template based on destination info properties.
*/
function generateDestinationTemplate(destination) {
const travelModeIconTemplate = '';
return `
${travelModeIconTemplate}
${destination.distance}
${destination.label}
To
${destination.name}
${destination.duration}
aria-label="Link to directions in Google Maps">
Edit
`;
}
const CONFIGURATION = {
"defaultTravelMode": "DRIVING",
"distanceMeasurementType": "IMPERIAL",
"mapOptions": {"center":{"lat":36.0599048,"lng":138.4420431},"fullscreenControl":true,"mapTypeControl":false,"streetViewControl":false,"zoom":14,"zoomControl":true,"maxZoom":20,"mapId":""},
"mapsApiKey": "YOUR_API_KEY_HERE"
};
function initMap() {
new Commutes(CONFIGURATION);
}
自動車をご利用の場合:
東京都練馬ICより上信越自動車道を経由2時間30分
中部横断道 八千穂高原ICより車で20分鉄道をご利用の場合:
JR小海線 松原湖駅より車で8分
Copyright © 2021 アトリエ・フォレスト信州 | Atelier Forest Shinsyu.