<!DOCTYPE html>
<html prefix="og: http://ogp.me/ns#" lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>escapegame-2022/tsubasa/blender_three.js/OrbitControls.js at master - SKIP/escapegame-2022</title>
    <meta property="og:title" content="escapegame-2022/tsubasa/blender_three.js/OrbitControls.js at master - SKIP/escapegame-2022" />
    <meta property="og:type" content="object" />
    <meta property="og:url" content="http://localhost:8880/SKIP/escapegame-2022/blob/master/tsubasa/blender_three.js/OrbitControls.js" />
    
    
      <meta property="og:image" content="https://www.yatex.org/gitbucket/SKIP/_avatar" />
      
    
    <link rel="icon" href="https://www.yatex.org/gitbucket/assets/common/images/gitbucket.png?20240601154850" type="image/vnd.microsoft.icon" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/google-fonts/css/source-sans-pro.css?20240601154850" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/bootstrap-3.4.1/css/bootstrap.min.css?20240601154850" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/octicons-4.4.0/octicons.min.css?20240601154850" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/bootstrap-datetimepicker-4.17.44/css/bootstrap-datetimepicker.min.css?20240601154850" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/colorpicker/css/bootstrap-colorpicker.min.css?20240601154850" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/color-themes-for-google-code-prettify/github-v2.min.css?20240601154850" type="text/css" rel="stylesheet"/>
    <link href="https://www.yatex.org/gitbucket/assets/vendors/facebox/facebox.css?20240601154850" rel="stylesheet"/>
    <link href="https://www.yatex.org/gitbucket/assets/vendors/AdminLTE-2.4.2/css/AdminLTE.min.css?20240601154850" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/AdminLTE-2.4.2/css/skins/skin-green-light.min.css?20240601154850" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/font-awesome-4.7.0/css/font-awesome.min.css?20240601154850" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/jquery-ui/jquery-ui.min.css?20240601154850" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/jquery-ui/jquery-ui.structure.min.css?20240601154850" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/jquery-ui/jquery-ui.theme.min.css?20240601154850" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/common/css/gitbucket.css?20240601154850" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/tipped/tipped.css?20240601154850" rel="stylesheet">
    <script src="https://www.yatex.org/gitbucket/assets/vendors/jquery/jquery-3.5.1.min.js?20240601154850"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/jquery-ui/jquery-ui.min.js?20240601154850"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/dropzone/dropzone.min.js?20240601154850"></script>
    <script src="https://www.yatex.org/gitbucket/assets/common/js/validation.js?20240601154850"></script>
    <script src="https://www.yatex.org/gitbucket/assets/common/js/gitbucket.js?20240601154850"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/bootstrap-3.4.1/js/bootstrap.min.js?20240601154850"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/bootstrap3-typeahead/bootstrap3-typeahead.min.js?20240601154850"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/bootstrap-datetimepicker-4.17.44/js/moment.min.js?20240601154850"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/bootstrap-datetimepicker-4.17.44/js/bootstrap-datetimepicker.min.js?20240601154850"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/colorpicker/js/bootstrap-colorpicker.min.js?20240601154850"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/google-code-prettify/prettify.js?20240601154850"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/elastic/jquery.elastic.source.js?20240601154850"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/facebox/facebox.js?20240601154850"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/jquery-hotkeys/jquery.hotkeys.js?20240601154850"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/jquery-textcomplete-1.8.4/jquery.textcomplete.min.js?20240601154850"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/tipped/tipped.min.js?20240601154850"></script>
    
      <meta name="go-import" content="www.yatex.org/gitbucket/SKIP/escapegame-2022 git https://www.yatex.org/gitbucket/git/SKIP/escapegame-2022.git" />
    
    <script src="https://www.yatex.org/gitbucket/assets/vendors/AdminLTE-2.4.2/js/adminlte.min.js?20240601154850" type="text/javascript"></script>
    
      <style type="text/css">.content, .sidebar, .skin-green-light div.main-sidebar {
  background:  #efe;
}</style>
    
  </head>
  <body class="skin-green-light page-load sidebar-mini ">
    <div class="wrapper">
      <header class="main-header">
        <a href="https://www.yatex.org/gitbucket/" class="logo">
          <span class="logo-mini"><img src="https://www.yatex.org/gitbucket/assets/common/images/gitbucket.svg?20240601154850" alt="GitBucket" /></span>
          <span class="logo-lg">
            <img src="https://www.yatex.org/gitbucket/assets/common/images/gitbucket.svg?20240601154850" alt="GitBucket" />
            <span class="header-title strong">GitBucket</span>
          </span>
        </a>
        <nav class="navbar navbar-static-top" role="navigation">
          <!-- Sidebar toggle button-->
          
            <a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button" title="Toggle navigation">
              <span class="sr-only">Toggle navigation</span>
            </a>
          
          
            <form id="search" action="https://www.yatex.org/gitbucket/search" method="GET" class="pc navbar-form navbar-left" role="search">
              <div class="form-group">
                <input type="text" name="query" id="navbar-search-input" class="form-control" placeholder="Find a repository" aria-label="Search"/>
              </div>
            </form>
            <ul class="pc nav navbar-nav">
              <li><a href="https://www.yatex.org/gitbucket/dashboard/pulls">Pull requests</a></li>
              <li><a href="https://www.yatex.org/gitbucket/dashboard/issues">Issues</a></li>
              
                
                  <li><a href="https://www.yatex.org/gitbucket/gist">Snippets</a></li>
                
              
            </ul>
          
          <div class="navbar-custom-menu">
            <ul class="nav navbar-nav">
              
                <li class="dropdown notifications-menu">
                  <a class="dropdown-toggle menu" data-toggle="dropdown" href="#" aria-label="Create new…">
                    <i class="octicon octicon-plus" style="color: black;"></i><span class="caret" style="color: black; vertical-align: middle;"></span>
                  </a>
                  <ul class="dropdown-menu pull-right" style="width: auto;">
                    <li>
                      <ul class="menu">
                        
                          <li><a href="https://www.yatex.org/gitbucket/new">New repository</a></li>
                        
                        <li><a href="https://www.yatex.org/gitbucket/groups/new">New group</a></li>
                      </ul>
                    </li>
                  </ul>
                </li>
                <li class="dropdown notifications-menu">
                  <a class="dropdown-toggle menu" data-toggle="dropdown" href="#" data-toggle="tooltip" data-placement="bottom" title="Signed is as j2311">
                    <img src="https://www.gravatar.com/avatar/6887b4acd79bba29f3b92ca6ba6a6d17?s=16&d=retro&r=g" class="avatar-mini" style="width: 16px; height: 16px;"
     alt="@j2311" /><span class="caret" style="color: black; vertical-align: middle;"></span>
                  </a>
                  <ul class="dropdown-menu pull-right" style="width: auto;">
                    <li>
                      <ul class="menu">
                        <li><a href="https://www.yatex.org/gitbucket/j2311">Your profile</a></li>
                        <li><a href="https://www.yatex.org/gitbucket/j2311/_edit">Account settings</a></li>
                        
                        <li><a href="https://www.yatex.org/gitbucket/signout">Sign out</a></li>
                      </ul>
                    </li>
                  </ul>
                </li>
              
            </ul>
          </div>
        </nav>
      </header>
      
  


<div class="main-sidebar">
  <div class="sidebar">
    <ul class="sidebar-menu">
      
  <li class = "menu-item-hover active">
    
      <a href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022">
        <i class="menu-icon octicon octicon-code"></i>
        <span>Files</span>
        
      </a>
    
  </li>

      
        
  <li class = "menu-item-hover ">
    
      <a href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/branches">
        <i class="menu-icon octicon octicon-git-branch"></i>
        <span>Branches</span>
        
          <span class="pull-right-container"><span class="label label-primary pull-right">1</span></span>
        
      </a>
    
  </li>

      
      
  <li class = "menu-item-hover ">
    
      <a href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/releases">
        <i class="menu-icon octicon octicon-tag"></i>
        <span>Releases</span>
        
      </a>
    
  </li>

      
        
  <li class = "menu-item-hover ">
    
      <a href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/issues">
        <i class="menu-icon octicon octicon-issue-opened"></i>
        <span>Issues</span>
        
      </a>
    
  </li>

        
  <li class = "menu-item-hover ">
    
      <a href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/pulls">
        <i class="menu-icon octicon octicon-git-pull-request"></i>
        <span>Pull requests</span>
        
      </a>
    
  </li>

        
  <li class = "menu-item-hover ">
    
      <a href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/issues/labels">
        <i class="menu-icon octicon octicon-tag"></i>
        <span>Labels</span>
        
      </a>
    
  </li>

        
  <li class = "menu-item-hover ">
    
      <a href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/issues/priorities">
        <i class="menu-icon octicon octicon-flame"></i>
        <span>Priorities</span>
        
      </a>
    
  </li>

        
  <li class = "menu-item-hover ">
    
      <a href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/issues/milestones">
        <i class="menu-icon octicon octicon-milestone"></i>
        <span>Milestones</span>
        
      </a>
    
  </li>

      
      
        
  <li class = "menu-item-hover ">
    
      <a href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/wiki">
        <i class="menu-icon octicon octicon-book"></i>
        <span>Wiki</span>
        
      </a>
    
  </li>

      
      
      
    </ul>
  </div>
</div>
<div class="content-wrapper">
  <div class="content body clearfix">
    <div class="headbar">
      <div class="container">
        

        
        <div class="head">
          <div class="pull-right">
            
              
  <div class="btn-group" >
    <button class="dropdown-toggle btn btn-default btn-sm" data-toggle="dropdown">
      
        
        <span class="strong"
              >
          Not watching
        </span>
      
      <span class="caret"></span>
    </button>
    <ul class="dropdown-menu pull-right">
      
      
  
    <li>
      <a href="#" class="watch" data-id="watching">
        
  <i class="octicon"></i>

        <span class="notification-label strong">Watching</span>
        <div class="muted small">Notify all conversations.</div>
      </a>
    </li>
  
    <li>
      <a href="#" class="watch" data-id="not_watching">
        
  <i class="octicon octicon-check"></i>

        <span class="notification-label strong">Not watching</span>
        <div class="muted small">Notify when participating.</div>
      </a>
    </li>
  
    <li>
      <a href="#" class="watch" data-id="ignoring">
        
  <i class="octicon"></i>

        <span class="notification-label strong">Ignoring</span>
        <div class="muted small">Never notify.</div>
      </a>
    </li>
  

    </ul>
  </div>
  


<script>
$(function(){
  $('a.watch').click(function(){
    var selected = $(this);
    var notification = selected.data('id');
    $.post('https://www.yatex.org/gitbucket/SKIP/escapegame-2022/watch',
      { notification : notification },
      function(){
        $('a.watch i.octicon-check').removeClass('octicon-check');
        $('a.watch[data-id=' + notification + '] i').addClass('octicon-check');

        // Update button label
        var label = selected.find('span.notification-label').text().trim();
        selected.parents('div.btn-group').find('button>span.strong').text(label);
      }
    );
    return false;
  });
});
</script>

            
            
              
                <a class="btn btn-default btn-sm" href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/fork" rel="facebox">
                  <span class="strong"><i class="octicon octicon-repo-forked"></i>Fork</span><span class="muted">: 7</span>
                </a>
              
            
            <form id="fork-form" method="post" action="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/fork" style="display: none;">
              <input type="hidden" name="account" value="j2311"/>
            </form>
          </div>
          
  
    <i class="mega-octicon octicon-repo"></i>
  


          <a href="https://www.yatex.org/gitbucket/SKIP">SKIP</a> / <a href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022" class="strong">escapegame-2022</a>

          
            
          
        </div>
      </div>
    </div>
    
    <style>
      .prettyprint {
        tab-size: 8
      }
    </style>
    <div class="head">
      <div class="pull-right hide-if-blame"><div class="btn-group">
        <a href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/blob/7a630f0bef6ef4e4fa22f5c34a655f7c38f16adc/tsubasa/blender_three.js/OrbitControls.js" data-hotkey="y" style="display: none;">Transfer to URL with SHA</a>
        <a href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/find/master" class="btn btn-sm btn-default" data-hotkey="t">Find file</a>
      </div></div>
      <div class="line-age-legend">
        <span>Newer</span>
        <ol>
            <li class="heat1"></li>
            <li class="heat2"></li>
            <li class="heat3"></li>
            <li class="heat4"></li>
            <li class="heat5"></li>
            <li class="heat6"></li>
            <li class="heat7"></li>
            <li class="heat8"></li>
            <li class="heat9"></li>
            <li class="heat10"></li>
        </ol>
        <span>Older</span>
      </div>
      <div id="branchCtrlWrapper" style="display:inline;">
      
  <div class="btn-group" style="min-width: 200px;">
    <button class="dropdown-toggle btn btn-default btn-sm" data-toggle="dropdown">
      
        
          <span class="muted">branch:</span>
        
        <span class="strong"
              style="display:inline-block; vertical-align:bottom; overflow-x:hidden; max-width:200px; text-overflow:ellipsis">
          master
        </span>
      
      <span class="caret"></span>
    </button>
    <ul class="dropdown-menu">
      
      
  <li>
    <ul class="nav nav-tabs">
      <li class="active" id="branch-control-tab-branches"><a href="javascript:void(0);" class="nav-item" id="nav-item-branches">Branches</a></li>
      <li id="branch-control-tab-tags"><a href="javascript:void(0);" class="nav-item" id="nav-item-tags">Tags</a></li>
      <li><button id="branch-control-close" class="pull-right">&times</button></li>
    </ul>
    <li>
      <input id="branch-control-input" type="text" class="form-control input-sm dropdown-filter-input"/>
    </li>
    
        
          <li><a href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/blob/master/tsubasa/blender_three.js/OrbitControls.js">
  <i class="octicon octicon-check"></i>
 master</a></li>
        
      
    
  </li>

    </ul>
  </div>
  


<script>
  $(function(){
    $('#branch-control-input').parent().click(function(e) {
      e.stopPropagation();
    });

    $('#branch-control-close').click(function() {
      $('[data-toggle="dropdown"]').parent().removeClass('open');
    });

    $('#branch-control-input').keyup(function() {
      updateBranchControlListFilter();
    });

    

    $('.btn-group').click(function() {
      $('#branch-control-input').val('');
      //$('.dropdown-menu li').show();
      $('#create-branch').hide();
    });

    $('#nav-item-branches').click(function(e) {
      e.stopPropagation();
      updateBranchControlList('branches');
    });

    $('#nav-item-tags').click(function(e) {
      e.stopPropagation();
      updateBranchControlList('tags');
    });

    function updateBranchControlList(active) {
      if (active == 'branches') {
        $('li#branch-control-tab-branches').addClass('active');
        $('li#branch-control-tab-tags').removeClass('active');

        $('li.branch-control-item-branch').show();
        $('li.branch-control-item-branch > a').addClass('active');

        $('li.branch-control-item-tag').hide();
        $('li.branch-control-item-tag > a').removeClass('active');
        
          $('#branch-control-input').attr('placeholder', 'Find branch ...');
        
      } else if (active == 'tags') {
        $('li#branch-control-tab-branches').removeClass('active');
        $('li#branch-control-tab-tags').addClass('active');

        $('li.branch-control-item-branch').hide();
        $('li.branch-control-item-branch > a').removeClass('active');

        $('li.branch-control-item-tag').show();
        $('li.branch-control-item-tag > a').addClass('active');
        $('#branch-control-input').attr('placeholder', 'Find tag ...');
      }
      updateBranchControlListFilter();
    }

    function updateBranchControlListFilter() {
      const inputVal = $('#branch-control-input').val();
      $.each($('#branch-control-input').parent().parent().find('a.active').not('.nav-item'), function(index, elem) {
        if (!inputVal || !elem.text.trim() || elem.text.trim().toLowerCase().indexOf(inputVal.toLowerCase()) >= 0) {
          $(elem).parent().show();
        } else {
          $(elem).parent().hide();
        }
      });
      if ($('li#branch-control-tab-branches.active').length > 0) {
        
      }
    }

    // Initialize the branch control list
    updateBranchControlList('branches');
  });
</script>

      </div>
      <a href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/tree/master">escapegame-2022</a> /
      
        
          <a href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/tree/master/tsubasa">tsubasa</a> /
        
      
        
          <a href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/tree/master/tsubasa/blender_three.js">blender_three.js</a> /
        
      
        
          OrbitControls.js
        
      
      
    </div>
    <div class="box-header" style="line-height: 28px;">
      <img src="https://www.gravatar.com/avatar/96a94f732f7c0250e2958855bb031406?s=20&d=retro&r=g" class="avatar-mini" style="width: 20px; height: 20px;"
     alt="@tsubasa" />
      tsubasa
      <span class="muted">
  <span data-toggle="tooltip" title="2022-12-06 14:38:48">
    
      on 6 Dec 2022
    
  </span>

</span>
      <span class="label label-default">26 KB</span>
      <a href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/commit/7a630f0bef6ef4e4fa22f5c34a655f7c38f16adc" class="commit-message">add</a>
      <div class="btn-group pull-right">
        <a class="btn btn-sm btn-default" href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/raw/7a630f0bef6ef4e4fa22f5c34a655f7c38f16adc/tsubasa/blender_three.js/OrbitControls.js">Raw</a>
        
          <a class="btn btn-sm btn-default blame-action" href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/blame/7a630f0bef6ef4e4fa22f5c34a655f7c38f16adc/tsubasa/blender_three.js/OrbitControls.js"
            data-url="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/get-blame/7a630f0bef6ef4e4fa22f5c34a655f7c38f16adc/tsubasa/blender_three.js/OrbitControls.js" data-repository="https://www.yatex.org/gitbucket/SKIP/escapegame-2022">Blame</a>
        
        <a class="btn btn-sm btn-default" href="https://www.yatex.org/gitbucket/SKIP/escapegame-2022/commits/master/tsubasa/blender_three.js/OrbitControls.js">History</a>
        
        
      </div>
    </div>
    
      
        
          <div class="box-content-bottom">
            <pre class="prettyprint linenums blob  no-renderable  ">( function () {

	// This set of controls performs orbiting, dollying (zooming), and panning.
	// Unlike TrackballControls, it maintains the &quot;up&quot; direction object.up (+Y by default).
	//
	//    Orbit - left mouse / touch: one-finger move
	//    Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
	//    Pan - right mouse, or left mouse + ctrl/meta/shiftKey, or arrow keys / touch: two-finger move

	const _changeEvent = {
		type: &#x27;change&#x27;
	};
	const _startEvent = {
		type: &#x27;start&#x27;
	};
	const _endEvent = {
		type: &#x27;end&#x27;
	};
	class OrbitControls extends THREE.EventDispatcher {

		constructor( object, domElement ) {

			super();
			this.object = object;
			this.domElement = domElement;
			this.domElement.style.touchAction = &#x27;none&#x27;; // disable touch scroll

			// Set to false to disable this control
			this.enabled = true;

			// &quot;target&quot; sets the location of focus, where the object orbits around
			this.target = new THREE.Vector3();

			// How far you can dolly in and out ( PerspectiveCamera only )
			this.minDistance = 0;
			this.maxDistance = Infinity;

			// How far you can zoom in and out ( OrthographicCamera only )
			this.minZoom = 0;
			this.maxZoom = Infinity;

			// How far you can orbit vertically, upper and lower limits.
			// Range is 0 to Math.PI radians.
			this.minPolarAngle = 0; // radians
			this.maxPolarAngle = Math.PI; // radians

			// How far you can orbit horizontally, upper and lower limits.
			// If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ], with ( max - min &lt; 2 PI )
			this.minAzimuthAngle = - Infinity; // radians
			this.maxAzimuthAngle = Infinity; // radians

			// Set to true to enable damping (inertia)
			// If damping is enabled, you must call controls.update() in your animation loop
			this.enableDamping = false;
			this.dampingFactor = 0.05;

			// This option actually enables dollying in and out; left as &quot;zoom&quot; for backwards compatibility.
			// Set to false to disable zooming
			this.enableZoom = true;
			this.zoomSpeed = 1.0;

			// Set to false to disable rotating
			this.enableRotate = true;
			this.rotateSpeed = 1.0;

			// Set to false to disable panning
			this.enablePan = true;
			this.panSpeed = 1.0;
			this.screenSpacePanning = true; // if false, pan orthogonal to world-space direction camera.up
			this.keyPanSpeed = 7.0; // pixels moved per arrow key push

			// Set to true to automatically rotate around the target
			// If auto-rotate is enabled, you must call controls.update() in your animation loop
			this.autoRotate = false;
			this.autoRotateSpeed = 2.0; // 30 seconds per orbit when fps is 60

			// The four arrow keys
			this.keys = {
				LEFT: &#x27;ArrowLeft&#x27;,
				UP: &#x27;ArrowUp&#x27;,
				RIGHT: &#x27;ArrowRight&#x27;,
				BOTTOM: &#x27;ArrowDown&#x27;
			};

			// Mouse buttons
			this.mouseButtons = {
				LEFT: THREE.MOUSE.ROTATE,
				MIDDLE: THREE.MOUSE.DOLLY,
				RIGHT: THREE.MOUSE.PAN
			};

			// Touch fingers
			this.touches = {
				ONE: THREE.TOUCH.ROTATE,
				TWO: THREE.TOUCH.DOLLY_PAN
			};

			// for reset
			this.target0 = this.target.clone();
			this.position0 = this.object.position.clone();
			this.zoom0 = this.object.zoom;

			// the target DOM element for key events
			this._domElementKeyEvents = null;

			//
			// public methods
			//

			this.getPolarAngle = function () {

				return spherical.phi;

			};

			this.getAzimuthalAngle = function () {

				return spherical.theta;

			};

			this.getDistance = function () {

				return this.object.position.distanceTo( this.target );

			};

			this.listenToKeyEvents = function ( domElement ) {

				domElement.addEventListener( &#x27;keydown&#x27;, onKeyDown );
				this._domElementKeyEvents = domElement;

			};

			this.saveState = function () {

				scope.target0.copy( scope.target );
				scope.position0.copy( scope.object.position );
				scope.zoom0 = scope.object.zoom;

			};

			this.reset = function () {

				scope.target.copy( scope.target0 );
				scope.object.position.copy( scope.position0 );
				scope.object.zoom = scope.zoom0;
				scope.object.updateProjectionMatrix();
				scope.dispatchEvent( _changeEvent );
				scope.update();
				state = STATE.NONE;

			};

			// this method is exposed, but perhaps it would be better if we can make it private...
			this.update = function () {

				const offset = new THREE.Vector3();

				// so camera.up is the orbit axis
				const quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) );
				const quatInverse = quat.clone().invert();
				const lastPosition = new THREE.Vector3();
				const lastQuaternion = new THREE.Quaternion();
				const twoPI = 2 * Math.PI;
				return function update() {

					const position = scope.object.position;
					offset.copy( position ).sub( scope.target );

					// rotate offset to &quot;y-axis-is-up&quot; space
					offset.applyQuaternion( quat );

					// angle from z-axis around y-axis
					spherical.setFromVector3( offset );
					if ( scope.autoRotate &amp;&amp; state === STATE.NONE ) {

						rotateLeft( getAutoRotationAngle() );

					}

					if ( scope.enableDamping ) {

						spherical.theta += sphericalDelta.theta * scope.dampingFactor;
						spherical.phi += sphericalDelta.phi * scope.dampingFactor;

					} else {

						spherical.theta += sphericalDelta.theta;
						spherical.phi += sphericalDelta.phi;

					}

					// restrict theta to be between desired limits

					let min = scope.minAzimuthAngle;
					let max = scope.maxAzimuthAngle;
					if ( isFinite( min ) &amp;&amp; isFinite( max ) ) {

						if ( min &lt; - Math.PI ) min += twoPI; else if ( min &gt; Math.PI ) min -= twoPI;
						if ( max &lt; - Math.PI ) max += twoPI; else if ( max &gt; Math.PI ) max -= twoPI;
						if ( min &lt;= max ) {

							spherical.theta = Math.max( min, Math.min( max, spherical.theta ) );

						} else {

							spherical.theta = spherical.theta &gt; ( min + max ) / 2 ? Math.max( min, spherical.theta ) : Math.min( max, spherical.theta );

						}

					}

					// restrict phi to be between desired limits
					spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) );
					spherical.makeSafe();
					spherical.radius *= scale;

					// restrict radius to be between desired limits
					spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) );

					// move target to panned location

					if ( scope.enableDamping === true ) {

						scope.target.addScaledVector( panOffset, scope.dampingFactor );

					} else {

						scope.target.add( panOffset );

					}

					offset.setFromSpherical( spherical );

					// rotate offset back to &quot;camera-up-vector-is-up&quot; space
					offset.applyQuaternion( quatInverse );
					position.copy( scope.target ).add( offset );
					scope.object.lookAt( scope.target );
					if ( scope.enableDamping === true ) {

						sphericalDelta.theta *= 1 - scope.dampingFactor;
						sphericalDelta.phi *= 1 - scope.dampingFactor;
						panOffset.multiplyScalar( 1 - scope.dampingFactor );

					} else {

						sphericalDelta.set( 0, 0, 0 );
						panOffset.set( 0, 0, 0 );

					}

					scale = 1;

					// update condition is:
					// min(camera displacement, camera rotation in radians)^2 &gt; EPS
					// using small-angle approximation cos(x/2) = 1 - x^2 / 8

					if ( zoomChanged || lastPosition.distanceToSquared( scope.object.position ) &gt; EPS || 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) &gt; EPS ) {

						scope.dispatchEvent( _changeEvent );
						lastPosition.copy( scope.object.position );
						lastQuaternion.copy( scope.object.quaternion );
						zoomChanged = false;
						return true;

					}

					return false;

				};

			}();
			this.dispose = function () {

				scope.domElement.removeEventListener( &#x27;contextmenu&#x27;, onContextMenu );
				scope.domElement.removeEventListener( &#x27;pointerdown&#x27;, onPointerDown );
				scope.domElement.removeEventListener( &#x27;pointercancel&#x27;, onPointerCancel );
				scope.domElement.removeEventListener( &#x27;wheel&#x27;, onMouseWheel );
				scope.domElement.removeEventListener( &#x27;pointermove&#x27;, onPointerMove );
				scope.domElement.removeEventListener( &#x27;pointerup&#x27;, onPointerUp );
				if ( scope._domElementKeyEvents !== null ) {

					scope._domElementKeyEvents.removeEventListener( &#x27;keydown&#x27;, onKeyDown );

				}

				//scope.dispatchEvent( { type: &#x27;dispose&#x27; } ); // should this be added here?

			};

			//
			// internals
			//

			const scope = this;
			const STATE = {
				NONE: - 1,
				ROTATE: 0,
				DOLLY: 1,
				PAN: 2,
				TOUCH_ROTATE: 3,
				TOUCH_PAN: 4,
				TOUCH_DOLLY_PAN: 5,
				TOUCH_DOLLY_ROTATE: 6
			};
			let state = STATE.NONE;
			const EPS = 0.000001;

			// current position in spherical coordinates
			const spherical = new THREE.Spherical();
			const sphericalDelta = new THREE.Spherical();
			let scale = 1;
			const panOffset = new THREE.Vector3();
			let zoomChanged = false;
			const rotateStart = new THREE.Vector2();
			const rotateEnd = new THREE.Vector2();
			const rotateDelta = new THREE.Vector2();
			const panStart = new THREE.Vector2();
			const panEnd = new THREE.Vector2();
			const panDelta = new THREE.Vector2();
			const dollyStart = new THREE.Vector2();
			const dollyEnd = new THREE.Vector2();
			const dollyDelta = new THREE.Vector2();
			const pointers = [];
			const pointerPositions = {};
			function getAutoRotationAngle() {

				return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;

			}

			function getZoomScale() {

				return Math.pow( 0.95, scope.zoomSpeed );

			}

			function rotateLeft( angle ) {

				sphericalDelta.theta -= angle;

			}

			function rotateUp( angle ) {

				sphericalDelta.phi -= angle;

			}

			const panLeft = function () {

				const v = new THREE.Vector3();
				return function panLeft( distance, objectMatrix ) {

					v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix
					v.multiplyScalar( - distance );
					panOffset.add( v );

				};

			}();
			const panUp = function () {

				const v = new THREE.Vector3();
				return function panUp( distance, objectMatrix ) {

					if ( scope.screenSpacePanning === true ) {

						v.setFromMatrixColumn( objectMatrix, 1 );

					} else {

						v.setFromMatrixColumn( objectMatrix, 0 );
						v.crossVectors( scope.object.up, v );

					}

					v.multiplyScalar( distance );
					panOffset.add( v );

				};

			}();

			// deltaX and deltaY are in pixels; right and down are positive
			const pan = function () {

				const offset = new THREE.Vector3();
				return function pan( deltaX, deltaY ) {

					const element = scope.domElement;
					if ( scope.object.isPerspectiveCamera ) {

						// perspective
						const position = scope.object.position;
						offset.copy( position ).sub( scope.target );
						let targetDistance = offset.length();

						// half of the fov is center to top of screen
						targetDistance *= Math.tan( scope.object.fov / 2 * Math.PI / 180.0 );

						// we use only clientHeight here so aspect ratio does not distort speed
						panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix );
						panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix );

					} else if ( scope.object.isOrthographicCamera ) {

						// orthographic
						panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix );
						panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix );

					} else {

						// camera neither orthographic nor perspective
						console.warn( &#x27;WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.&#x27; );
						scope.enablePan = false;

					}

				};

			}();
			function dollyOut( dollyScale ) {

				if ( scope.object.isPerspectiveCamera ) {

					scale /= dollyScale;

				} else if ( scope.object.isOrthographicCamera ) {

					scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) );
					scope.object.updateProjectionMatrix();
					zoomChanged = true;

				} else {

					console.warn( &#x27;WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.&#x27; );
					scope.enableZoom = false;

				}

			}

			function dollyIn( dollyScale ) {

				if ( scope.object.isPerspectiveCamera ) {

					scale *= dollyScale;

				} else if ( scope.object.isOrthographicCamera ) {

					scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) );
					scope.object.updateProjectionMatrix();
					zoomChanged = true;

				} else {

					console.warn( &#x27;WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.&#x27; );
					scope.enableZoom = false;

				}

			}

			//
			// event callbacks - update the object state
			//

			function handleMouseDownRotate( event ) {

				rotateStart.set( event.clientX, event.clientY );

			}

			function handleMouseDownDolly( event ) {

				dollyStart.set( event.clientX, event.clientY );

			}

			function handleMouseDownPan( event ) {

				panStart.set( event.clientX, event.clientY );

			}

			function handleMouseMoveRotate( event ) {

				rotateEnd.set( event.clientX, event.clientY );
				rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
				const element = scope.domElement;
				rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height

				rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
				rotateStart.copy( rotateEnd );
				scope.update();

			}

			function handleMouseMoveDolly( event ) {

				dollyEnd.set( event.clientX, event.clientY );
				dollyDelta.subVectors( dollyEnd, dollyStart );
				if ( dollyDelta.y &gt; 0 ) {

					dollyOut( getZoomScale() );

				} else if ( dollyDelta.y &lt; 0 ) {

					dollyIn( getZoomScale() );

				}

				dollyStart.copy( dollyEnd );
				scope.update();

			}

			function handleMouseMovePan( event ) {

				panEnd.set( event.clientX, event.clientY );
				panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );
				pan( panDelta.x, panDelta.y );
				panStart.copy( panEnd );
				scope.update();

			}

			function handleMouseWheel( event ) {

				if ( event.deltaY &lt; 0 ) {

					dollyIn( getZoomScale() );

				} else if ( event.deltaY &gt; 0 ) {

					dollyOut( getZoomScale() );

				}

				scope.update();

			}

			function handleKeyDown( event ) {

				let needsUpdate = false;
				switch ( event.code ) {

					case scope.keys.UP:
						if ( event.ctrlKey || event.metaKey || event.shiftKey ) {

							rotateUp( 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );

						} else {

							pan( 0, scope.keyPanSpeed );

						}

						needsUpdate = true;
						break;
					case scope.keys.BOTTOM:
						if ( event.ctrlKey || event.metaKey || event.shiftKey ) {

							rotateUp( - 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );

						} else {

							pan( 0, - scope.keyPanSpeed );

						}

						needsUpdate = true;
						break;
					case scope.keys.LEFT:
						if ( event.ctrlKey || event.metaKey || event.shiftKey ) {

							rotateLeft( 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );

						} else {

							pan( scope.keyPanSpeed, 0 );

						}

						needsUpdate = true;
						break;
					case scope.keys.RIGHT:
						if ( event.ctrlKey || event.metaKey || event.shiftKey ) {

							rotateLeft( - 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );

						} else {

							pan( - scope.keyPanSpeed, 0 );

						}

						needsUpdate = true;
						break;

				}

				if ( needsUpdate ) {

					// prevent the browser from scrolling on cursor keys
					event.preventDefault();
					scope.update();

				}

			}

			function handleTouchStartRotate() {

				if ( pointers.length === 1 ) {

					rotateStart.set( pointers[ 0 ].pageX, pointers[ 0 ].pageY );

				} else {

					const x = 0.5 * ( pointers[ 0 ].pageX + pointers[ 1 ].pageX );
					const y = 0.5 * ( pointers[ 0 ].pageY + pointers[ 1 ].pageY );
					rotateStart.set( x, y );

				}

			}

			function handleTouchStartPan() {

				if ( pointers.length === 1 ) {

					panStart.set( pointers[ 0 ].pageX, pointers[ 0 ].pageY );

				} else {

					const x = 0.5 * ( pointers[ 0 ].pageX + pointers[ 1 ].pageX );
					const y = 0.5 * ( pointers[ 0 ].pageY + pointers[ 1 ].pageY );
					panStart.set( x, y );

				}

			}

			function handleTouchStartDolly() {

				const dx = pointers[ 0 ].pageX - pointers[ 1 ].pageX;
				const dy = pointers[ 0 ].pageY - pointers[ 1 ].pageY;
				const distance = Math.sqrt( dx * dx + dy * dy );
				dollyStart.set( 0, distance );

			}

			function handleTouchStartDollyPan() {

				if ( scope.enableZoom ) handleTouchStartDolly();
				if ( scope.enablePan ) handleTouchStartPan();

			}

			function handleTouchStartDollyRotate() {

				if ( scope.enableZoom ) handleTouchStartDolly();
				if ( scope.enableRotate ) handleTouchStartRotate();

			}

			function handleTouchMoveRotate( event ) {

				if ( pointers.length == 1 ) {

					rotateEnd.set( event.pageX, event.pageY );

				} else {

					const position = getSecondPointerPosition( event );
					const x = 0.5 * ( event.pageX + position.x );
					const y = 0.5 * ( event.pageY + position.y );
					rotateEnd.set( x, y );

				}

				rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
				const element = scope.domElement;
				rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height

				rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
				rotateStart.copy( rotateEnd );

			}

			function handleTouchMovePan( event ) {

				if ( pointers.length === 1 ) {

					panEnd.set( event.pageX, event.pageY );

				} else {

					const position = getSecondPointerPosition( event );
					const x = 0.5 * ( event.pageX + position.x );
					const y = 0.5 * ( event.pageY + position.y );
					panEnd.set( x, y );

				}

				panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );
				pan( panDelta.x, panDelta.y );
				panStart.copy( panEnd );

			}

			function handleTouchMoveDolly( event ) {

				const position = getSecondPointerPosition( event );
				const dx = event.pageX - position.x;
				const dy = event.pageY - position.y;
				const distance = Math.sqrt( dx * dx + dy * dy );
				dollyEnd.set( 0, distance );
				dollyDelta.set( 0, Math.pow( dollyEnd.y / dollyStart.y, scope.zoomSpeed ) );
				dollyOut( dollyDelta.y );
				dollyStart.copy( dollyEnd );

			}

			function handleTouchMoveDollyPan( event ) {

				if ( scope.enableZoom ) handleTouchMoveDolly( event );
				if ( scope.enablePan ) handleTouchMovePan( event );

			}

			function handleTouchMoveDollyRotate( event ) {

				if ( scope.enableZoom ) handleTouchMoveDolly( event );
				if ( scope.enableRotate ) handleTouchMoveRotate( event );

			}

			//
			// event handlers - FSM: listen for events and reset state
			//

			function onPointerDown( event ) {

				if ( scope.enabled === false ) return;
				if ( pointers.length === 0 ) {

					scope.domElement.setPointerCapture( event.pointerId );
					scope.domElement.addEventListener( &#x27;pointermove&#x27;, onPointerMove );
					scope.domElement.addEventListener( &#x27;pointerup&#x27;, onPointerUp );

				}

				//

				addPointer( event );
				if ( event.pointerType === &#x27;touch&#x27; ) {

					onTouchStart( event );

				} else {

					onMouseDown( event );

				}

			}

			function onPointerMove( event ) {

				if ( scope.enabled === false ) return;
				if ( event.pointerType === &#x27;touch&#x27; ) {

					onTouchMove( event );

				} else {

					onMouseMove( event );

				}

			}

			function onPointerUp( event ) {

				removePointer( event );
				if ( pointers.length === 0 ) {

					scope.domElement.releasePointerCapture( event.pointerId );
					scope.domElement.removeEventListener( &#x27;pointermove&#x27;, onPointerMove );
					scope.domElement.removeEventListener( &#x27;pointerup&#x27;, onPointerUp );

				}

				scope.dispatchEvent( _endEvent );
				state = STATE.NONE;

			}

			function onPointerCancel( event ) {

				removePointer( event );

			}

			function onMouseDown( event ) {

				let mouseAction;
				switch ( event.button ) {

					case 0:
						mouseAction = scope.mouseButtons.LEFT;
						break;
					case 1:
						mouseAction = scope.mouseButtons.MIDDLE;
						break;
					case 2:
						mouseAction = scope.mouseButtons.RIGHT;
						break;
					default:
						mouseAction = - 1;

				}

				switch ( mouseAction ) {

					case THREE.MOUSE.DOLLY:
						if ( scope.enableZoom === false ) return;
						handleMouseDownDolly( event );
						state = STATE.DOLLY;
						break;
					case THREE.MOUSE.ROTATE:
						if ( event.ctrlKey || event.metaKey || event.shiftKey ) {

							if ( scope.enablePan === false ) return;
							handleMouseDownPan( event );
							state = STATE.PAN;

						} else {

							if ( scope.enableRotate === false ) return;
							handleMouseDownRotate( event );
							state = STATE.ROTATE;

						}

						break;
					case THREE.MOUSE.PAN:
						if ( event.ctrlKey || event.metaKey || event.shiftKey ) {

							if ( scope.enableRotate === false ) return;
							handleMouseDownRotate( event );
							state = STATE.ROTATE;

						} else {

							if ( scope.enablePan === false ) return;
							handleMouseDownPan( event );
							state = STATE.PAN;

						}

						break;
					default:
						state = STATE.NONE;

				}

				if ( state !== STATE.NONE ) {

					scope.dispatchEvent( _startEvent );

				}

			}

			function onMouseMove( event ) {

				switch ( state ) {

					case STATE.ROTATE:
						if ( scope.enableRotate === false ) return;
						handleMouseMoveRotate( event );
						break;
					case STATE.DOLLY:
						if ( scope.enableZoom === false ) return;
						handleMouseMoveDolly( event );
						break;
					case STATE.PAN:
						if ( scope.enablePan === false ) return;
						handleMouseMovePan( event );
						break;

				}

			}

			function onMouseWheel( event ) {

				if ( scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE ) return;
				event.preventDefault();
				scope.dispatchEvent( _startEvent );
				handleMouseWheel( event );
				scope.dispatchEvent( _endEvent );

			}

			function onKeyDown( event ) {

				if ( scope.enabled === false || scope.enablePan === false ) return;
				handleKeyDown( event );

			}

			function onTouchStart( event ) {

				trackPointer( event );
				switch ( pointers.length ) {

					case 1:
						switch ( scope.touches.ONE ) {

							case THREE.TOUCH.ROTATE:
								if ( scope.enableRotate === false ) return;
								handleTouchStartRotate();
								state = STATE.TOUCH_ROTATE;
								break;
							case THREE.TOUCH.PAN:
								if ( scope.enablePan === false ) return;
								handleTouchStartPan();
								state = STATE.TOUCH_PAN;
								break;
							default:
								state = STATE.NONE;

						}

						break;
					case 2:
						switch ( scope.touches.TWO ) {

							case THREE.TOUCH.DOLLY_PAN:
								if ( scope.enableZoom === false &amp;&amp; scope.enablePan === false ) return;
								handleTouchStartDollyPan();
								state = STATE.TOUCH_DOLLY_PAN;
								break;
							case THREE.TOUCH.DOLLY_ROTATE:
								if ( scope.enableZoom === false &amp;&amp; scope.enableRotate === false ) return;
								handleTouchStartDollyRotate();
								state = STATE.TOUCH_DOLLY_ROTATE;
								break;
							default:
								state = STATE.NONE;

						}

						break;
					default:
						state = STATE.NONE;

				}

				if ( state !== STATE.NONE ) {

					scope.dispatchEvent( _startEvent );

				}

			}

			function onTouchMove( event ) {

				trackPointer( event );
				switch ( state ) {

					case STATE.TOUCH_ROTATE:
						if ( scope.enableRotate === false ) return;
						handleTouchMoveRotate( event );
						scope.update();
						break;
					case STATE.TOUCH_PAN:
						if ( scope.enablePan === false ) return;
						handleTouchMovePan( event );
						scope.update();
						break;
					case STATE.TOUCH_DOLLY_PAN:
						if ( scope.enableZoom === false &amp;&amp; scope.enablePan === false ) return;
						handleTouchMoveDollyPan( event );
						scope.update();
						break;
					case STATE.TOUCH_DOLLY_ROTATE:
						if ( scope.enableZoom === false &amp;&amp; scope.enableRotate === false ) return;
						handleTouchMoveDollyRotate( event );
						scope.update();
						break;
					default:
						state = STATE.NONE;

				}

			}

			function onContextMenu( event ) {

				if ( scope.enabled === false ) return;
				event.preventDefault();

			}

			function addPointer( event ) {

				pointers.push( event );

			}

			function removePointer( event ) {

				delete pointerPositions[ event.pointerId ];
				for ( let i = 0; i &lt; pointers.length; i ++ ) {

					if ( pointers[ i ].pointerId == event.pointerId ) {

						pointers.splice( i, 1 );
						return;

					}

				}

			}

			function trackPointer( event ) {

				let position = pointerPositions[ event.pointerId ];
				if ( position === undefined ) {

					position = new THREE.Vector2();
					pointerPositions[ event.pointerId ] = position;

				}

				position.set( event.pageX, event.pageY );

			}

			function getSecondPointerPosition( event ) {

				const pointer = event.pointerId === pointers[ 0 ].pointerId ? pointers[ 1 ] : pointers[ 0 ];
				return pointerPositions[ pointer.pointerId ];

			}

			//

			scope.domElement.addEventListener( &#x27;contextmenu&#x27;, onContextMenu );
			scope.domElement.addEventListener( &#x27;pointerdown&#x27;, onPointerDown );
			scope.domElement.addEventListener( &#x27;pointercancel&#x27;, onPointerCancel );
			scope.domElement.addEventListener( &#x27;wheel&#x27;, onMouseWheel, {
				passive: false
			} );

			// force an update at start

			this.update();

		}

	}

	// This set of controls performs orbiting, dollying (zooming), and panning.
	// Unlike TrackballControls, it maintains the &quot;up&quot; direction object.up (+Y by default).
	// This is very similar to OrbitControls, another set of touch behavior
	//
	//    Orbit - right mouse, or left mouse + ctrl/meta/shiftKey / touch: two-finger rotate
	//    Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
	//    Pan - left mouse, or arrow keys / touch: one-finger move

	class MapControls extends OrbitControls {

		constructor( object, domElement ) {

			super( object, domElement );
			this.screenSpacePanning = false; // pan orthogonal to world-space direction camera.up

			this.mouseButtons.LEFT = THREE.MOUSE.PAN;
			this.mouseButtons.RIGHT = THREE.MOUSE.ROTATE;
			this.touches.ONE = THREE.TOUCH.PAN;
			this.touches.TWO = THREE.TOUCH.DOLLY_ROTATE;

		}

	}

	THREE.MapControls = MapControls;
	THREE.OrbitControls = OrbitControls;

} )();
</pre>
          </div>
        
        
        
      
    
  
  </div>
</div>
<script>
$(function(){
  $('a[rel*=facebox]').facebox({
    'loadingImage': 'https://www.yatex.org/gitbucket/assets/vendors/facebox/loading.gif?20240601154850',
    'closeImage': 'https://www.yatex.org/gitbucket/assets/vendors/facebox/closelabel.png?20240601154850'
  });

  $(document).on("click", ".js-fork-owner-select-target", function() {
    var account = $(this).text().replace("@", "");
    $("#account").val(account);
    $("#fork").submit();
  });
});
</script>




    </div>
    <script>
      $(function(){
        
        
          $(".sidebar-toggle").on('click', function(e){
            $.post('https://www.yatex.org/gitbucket/sidebar-collapse', { collapse: !$('body').hasClass('sidebar-collapse') });
          });
        
      });
    </script>
    
  </body>
</html>

<script>
$(window).on('load', function(){
  window.onhashchange = function(){
    updateHighlighting();
  }

  const pre = $('pre.prettyprint');
  function updateSourceLineNum() {
    $('.source-line-num').remove();
    const pos = pre.find('ol.linenums').position();
    if (pos) {
      $('<div class="source-line-num">').css({
        height  : pre.height(),
        width   : '48px',
        cursor  : 'pointer',
        position: 'absolute',
        top     : pos.top + 'px',
        left    : pos.left + 'px'
      }).click(function(e){
        let pos = $(this).data("pos");
        if (!pos) {
          pos = $('ol.linenums li').map(function(){ return { id: $(this).attr("id"), top: $(this).position().top} }).toArray();
          $(this).data("pos",pos);
        }
        let i = 0;
        for(i = 0; i < pos.length - 1; i++){
          if(pos[i + 1].top > e.pageY){
            break;
          }
        }
        const line    = pos[i].id.replace(/^L/,'');
        const hash    = location.hash;
        const baseUrl = location.toString().split("#")[0];
        if (e.shiftKey == true && hash.match(/#L\d+(-L\d+)?/)) {
          const fragments = hash.split('-');
          window.history.pushState('', '', baseUrl + fragments[0] + '-L' + line);
        } else {
          const p = $("#L" + line).attr('id', '');
          window.history.pushState('', '', baseUrl + '#L' + line);
          p.attr('id','L' + line);
        }
        $("#branchCtrlWrapper .btn .muted").text("tree:");
        $("#branchCtrlWrapper .btn .strong").text("7a630f0bef");
        getSelection().empty();
        updateHighlighting();
      }).appendTo(pre);
      updateHighlighting();
    } else {
      // Maybe code view is not initialized yet. Retry until succeed.
      setTimeout(updateSourceLineNum, 300);
    }
  }
  const repository = $('.blame-action').data('repository');
  $('.blame-action').click(function(e){
    if(history.pushState && $('pre.prettyprint.no-renderable').length){
      e.preventDefault();
      history.pushState(null, null, this.href);
      updateBlame();
    }
  });

  function updateBlame(){
    const m = /\/(blame|blob)(\/.*)$/.exec(location.href);
    const mode = m[1];
    $('.blame-action').toggleClass("active", mode=='blame').attr('href', repository + (m[1] == 'blame' ? '/blob' : '/blame') + m[2]);
    if(pre.parents("div.box-content-bottom").find(".blame").length){
      pre.parent().toggleClass("blame-container", mode == 'blame');
      updateSourceLineNum();
      return;
    }
    if(mode == 'blob'){
      updateSourceLineNum();
      return;
    }
    $(document.body).toggleClass('no-box-shadow', document.body.style.boxShadow === undefined);
    $('.blame-action').addClass("active");
    const base = $('<div class="blame">').css({height: pre.height()}).prependTo(pre.parents("div.box-content-bottom"));
    base.parent().addClass("blame-container");
    updateSourceLineNum();
    $.get($('.blame-action').data('url')).done(function(data){
      let blame = data.blame;
      let lastDiv;
      const now = new Date().getTime();
      const index = [];
      for(let i = 0; i < blame.length; i++){
        for(let j = 0; j < blame[i].lines.length; j++){
          index[blame[i].lines[j]] = blame[i];
        }
      }

      $('pre.prettyprint ol.linenums li').each(function(i, e){
        const p = $(e).position();
        const h = $(e).height();
        if(blame == index[i]){
          lastDiv.css("min-height",(p.top + h + 1) - lastDiv.position().top);
        } else {
          $(e).addClass('blame-sep')
          blame = index[i];
          const sha = $('<div class="blame-sha">')
             .append($('<a>').attr("href", data.root + '/commit/' + blame.id).text(blame.id.substr(0, 7)));
          if (blame.prev) {
             sha.append($('<br />'))
             .append($('<a class="muted-link">').text('prev').attr("href", data.root + '/blame/' + blame.prev + '/' + (blame.prevPath || data.path)));
          }
          lastDiv = $('<div class="blame-info">')
           .addClass('heat' + Math.min(10, Math.max(1, Math.ceil((now - blame.commited) / (24 * 3600 * 1000 * 70)))))
           .toggleClass('blame-last', blame.id == data.last)
           .data('line', (i + 1))
           .css({
             "top"        : p.top + 'px',
             "min-height" : h + 'px'
           })
           .append(sha)
           .append($(blame.avatar).addClass('avatar').css({"float": "left"}))
           .append($('<div class="blame-commit-title">').text(blame.message))
           .append($('<div class="muted">').html(blame.author + " authed " + blame.authed))
           .appendTo(base);
        }
      });
    });
    return false;
  };

  $(document).on('expanded.pushMenu collapsed.pushMenu', function(e){
    setTimeout(updateBlame, 300);
  });

  updateBlame();
});

let scrolling = false;

/**
 * Highlight lines which are specified by URL hash.
 */
function updateHighlighting() {
  const hash = location.hash;
  const isDark = false;
  if (hash.match(/#L\d+(-L\d+)?/)) {
    if (isDark) {
      $('li.highlight-dark').removeClass('highlight-dark');
    } else {
      $('li.highlight').removeClass('highlight');
    }
    const fragments = hash.substr(1).split('-');
    if (fragments.length == 1) {
      if (isDark) {
        $('#' + fragments[0]).addClass('highlight-dark');
      } else {
        $('#' + fragments[0]).addClass('highlight');
      }
      if(!scrolling){
        $(window).scrollTop($('#' + fragments[0]).offset().top);
      }
    } else if(fragments.length > 1){
      const start = parseInt(fragments[0].substr(1));
      const end   = parseInt(fragments[1].substr(1));
      for (let i = start; i <= end; i++) {
        if (isDark) {
          $('#L' + i).addClass('highlight-dark');
        } else {
          $('#L' + i).addClass('highlight');
        }
      }
      if (!scrolling) {
        $(window).scrollTop($('#' + fragments[0]).offset().top);
      }
    }
  }
  scrolling = true;
}
</script>
