• broken image

    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

    broken image

    日帰り型

    コワーキングスペース

    お好みの空間でリモートワーク

    Dホール & テラス & 屋外で

    ※現在受付を停止しております。

    broken image

    滞在型

    ワーケーションルーム

    デスク・ベッド付きルーム

    一泊からロングステイまで

    クリエイティブな空間

    broken image

    大会議室

     

    イベント・研修などに

     

    80インチTVモニター利用可能

    broken image

    応接室(控室)

    個室で集中作業や会議に

    1時間区切りでご利用可能な

    個室スペース

    broken image

    ソファーラウンジ

    & BBQ

    暖炉を囲んでリラックス

    自由な時間を優雅に

    夜は屋外でBBQ

  •  

    Price

    素敵な一日をお過ごしください。

    完全予約制

    現在予約受付停止中

    当館ではご予約いただいた内容を会員様情報として保存しております。

     

     

     

     

    broken image

    コワーキングスペース

    ドロップイン

    3,300円

    一日料金

    9:00〜17:00

     

    1日10名様限定

    フリードリンク付き

    ※現在受付を停止しております。

    Recommended

    broken image

    ワーケーションルーム

    宿泊型ワーキングルーム

    Single 7,000円

    Twin 12,000円

    一室一泊料金

    チェックイン:10:00から

    チェックアウト:8:00まで

     

    デスク・ベッドあり

    連泊も可能

    ※現在受付を停止しております。

    broken image

    大会議室

    イベント・研修などに

    80,000円

    一日貸切り

    最大32人収容可能

    80インチTVモニター付き

    broken image

    応接室(控室)

    個室で作業・会議などに

    1,100円

    1時間料金

    当館ご利用のお客様に限り

    1時間区切りでご利用いただけます。

    broken image

    全館貸切

    法人様限定コース

    1 day40%Off

    1 week 50% Off

    1 month 60% Off

    全館内・屋外をご利用頂けるお得なコースです。

  • ご入浴・お食事

    八峰の湯(ヤッホーの湯)をご利用ください。

    broken image

    八峰の湯

    ヤッホーの湯(徒歩約1分)

    ■営業時間:11:00~21:00 通年営業 

          ※20:00受付終了

    ■休館日:

     2024年 9月4日(水) ・5日(木)

         11月6日(水) ・7日(木)

     2025年 1月8日(水) ・9日(木)

          3月5日(水) ・6日(木)

    ※2023年3月リニューアルオープン!

     

    broken image

    弊館・オプション

    事前のご予約にて承っております。

    ※施設ご利用の方限定メニューとなります。

    ※お支払いは予約時又は現地にて可能です。

    (現地の場合、現金またはクレジットカード可)

    ■お食事 

    【貸し出しセット】

      バーベキューセット 1セット3,500円

      (バーベキュー台、炭付き)

     

      癒やしの焚き火セット 1,500円

      (キャンプファイヤー台, 薪1羽, 着火剤, マシュマロ2本付き)

     

    【パーティー・ディナー】

     ケータリングの対応もお受けしております。

      ※事前にお問い合せの上、ご予約願います。
  • お問い合わせ

    ご利用に関するご質問がありましたら、
    ぜひお気軽にご連絡ください。

  • アクセス

    〒384-1103

    長野県南佐久郡小海町豊里5151-139

    (小海美術館・八峰の湯 隣り)

     

    Tel: 0267-93-2626

    Mail: info@atelier-forest.jp

     

    Google Mapへ

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    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分

  • broken image

    コテージ・貸別荘・オートキャンプ場なら

    近隣にコテージ・貸別荘・オートキャンプ場がございます。

    ㈳小海町開発公社までお問い合わせください。

    TEL:0267-93-2539