Junkerposts
  a-farme-球に文字test29 

<!DOCTYPE html>
<html>
<head>
<title>A-Frame - 情報パネル (背景クリック無効化テスト)</title>
<script src="https://aframe.io/releases/1.7.0/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-look-at-component@0.8.0/dist/aframe-look-at-component.min.js"></script>
<script src="https://unpkg.com/aframe-troika-text/dist/aframe-troika-text.min.js"></script>

<script>
// --- カスタムコンポーネント定義 (変更なし) ---
AFRAME.registerComponent('camera-relative-controls', {
schema: { targetSpeed: { type: 'number', default: 5 }, acceleration: { type: 'number', default: 10 }, damping: { type: 'number', default: 8 }, brakingDeceleration: { type: 'number', default: 20 }, enabled: { type: 'boolean', default: true } },
init: function () { this.keys = {}; this.currentVelocity = new THREE.Vector3(); this.ZERO_VECTOR = new THREE.Vector3(); this.direction = new THREE.Vector3(); this.rightDirection = new THREE.Vector3(); this.moveDirection = new THREE.Vector3(); this.desiredVelocity = new THREE.Vector3(); this.cameraWorldQuaternion = new THREE.Quaternion(); this.cameraEl = this.el.querySelector('[camera]'); this.isReady = false; if (!this.cameraEl) { console.error('camera-relative-controls requires a child entity with the [camera] component.'); } this.onKeyDown = this.onKeyDown.bind(this); this.onKeyUp = this.onKeyUp.bind(this); window.addEventListener('keydown', this.onKeyDown); window.addEventListener('keyup', this.onKeyUp); },
remove: function () { window.removeEventListener('keydown', this.onKeyDown); window.removeEventListener('keyup', this.onKeyUp); },
tick: function (time, timeDelta) { if (!this.data.enabled) return; if (!this.isReady) { if (this.cameraEl && this.cameraEl.object3D && this.cameraEl.object3D.matrixWorld) { this.isReady = true; } else { if (!this.cameraEl) { this.cameraEl = this.el.querySelector('[camera]'); } return; } } if (!this.cameraEl || !this.cameraEl.object3D) { return; } const el = this.el; const data = this.data; const position = el.object3D.position; const dt = timeDelta / 1000; this.cameraEl.object3D.getWorldQuaternion(this.cameraWorldQuaternion); this.direction.set(0, 0, -1); this.direction.applyQuaternion(this.cameraWorldQuaternion); if (this.direction.lengthSq() > 0.0001) this.direction.normalize(); this.rightDirection.set(1, 0, 0); this.rightDirection.applyQuaternion(this.cameraWorldQuaternion); this.rightDirection.y = 0; if (this.rightDirection.lengthSq() > 0.0001) this.rightDirection.normalize(); this.moveDirection.set(0, 0, 0); if (this.keys['KeyW'] || this.keys['ArrowUp']) { this.moveDirection.add(this.direction); } if (this.keys['KeyS'] || this.keys['ArrowDown']) { this.moveDirection.sub(this.direction); } if (this.keys['KeyA'] || this.keys['ArrowLeft']) { this.moveDirection.sub(this.rightDirection); } if (this.keys['KeyD'] || this.keys['ArrowRight']) { this.moveDirection.add(this.rightDirection); } const isKeyPressed = this.moveDirection.lengthSq() > 0.0001; if (isKeyPressed) { this.moveDirection.normalize(); } let lerpFactor = data.damping; const isMoving = this.currentVelocity.lengthSq() > 0.01; if (isKeyPressed) { let isOpposing = false; if (isMoving) { const dot = this.currentVelocity.dot(this.moveDirection); if (dot < -0.1) { isOpposing = true; } } if (isOpposing) { this.desiredVelocity.copy(this.ZERO_VECTOR); lerpFactor = data.brakingDeceleration; } else { this.desiredVelocity.copy(this.moveDirection).multiplyScalar(data.targetSpeed); lerpFactor = data.acceleration; } } else { this.desiredVelocity.copy(this.ZERO_VECTOR); lerpFactor = data.damping; } const effectiveLerpFactor = 1.0 - Math.exp(-lerpFactor * dt); this.currentVelocity.lerp(this.desiredVelocity, effectiveLerpFactor); if (this.currentVelocity.lengthSq() < 0.0001) { this.currentVelocity.copy(this.ZERO_VECTOR); } if (this.currentVelocity.lengthSq() > 0) { const deltaPosition = this.currentVelocity.clone().multiplyScalar(dt); position.add(deltaPosition); } },
onKeyDown: function (event) { if (!this.data.enabled) { return; } if (['KeyW', 'ArrowUp', 'KeyS', 'ArrowDown', 'KeyA', 'ArrowLeft', 'KeyD', 'ArrowRight'].includes(event.code)) { this.keys[event.code] = true; } },
onKeyUp: function (event) { if (this.keys[event.code] !== undefined) { delete this.keys[event.code]; } }
});
// --- ここまでカスタムコンポーネント定義 ---
</script>

</head>
<body>
<a-scene id="myScene" background="color: #000000">

<a-entity id="rig" position="0 0 5"
camera-relative-controls="targetSpeed: 250; acceleration: 3; damping: 5; brakingDeceleration: 1;">
<a-entity id="camera" camera="far: 20000;" look-controls position="0 1.6 0">
<a-entity cursor="rayOrigin: mouse; fuse: false;" raycaster="objects: .clickableSphere, .clickableButton; far: 3000;"
position="0 0 -1"
geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03;"
material="color: black; shader: flat; opacity: 0.7">
<a-animation begin="click" easing="ease-in" attribute="scale" fill="backwards" from="0.1 0.1 0.1" to="1 1 1" dur="150"></a-animation>
</a-entity>
</a-entity>
</a-entity>

<a-entity light="type: ambient; color: #444"></a-entity>
<a-entity light="type: directional; color: #FFF; intensity: 0.8" position="-1 1.5 1"></a-entity>
<a-entity light="type: directional; color: #AAA; intensity: 0.4" position="1 1 -1"></a-entity>

<a-entity id="infoPanel" visible="false" position="0 -1000 0" look-at="[camera]">
<a-plane id="panelBackground" width="2.5" height="1.2" color="#333" opacity="0.9" side="double"></a-plane>
<a-entity id="panelText"
troika-text="value: Placeholder; color: white; fontSize: 0.24; maxWidth: 2.3; align: center; anchorX: center; anchorY: middle; baseline: middle;"
position="0 0 0.05">
</a-entity>
<a-triangle id="prevButton" class="clickableButton"
position="-1.0 0 0.01" rotation="0 0 90" scale="0.2 0.2 0.2"
material="color: #CCC; shader: flat; opacity: 0.8;">
</a-triangle>
<a-triangle id="nextButton" class="clickableButton"
position="1.0 0 0.01" rotation="0 0 -90" scale="0.2 0.2 0.2"
material="color: #CCC; shader: flat; opacity: 0.8;">
</a-triangle>
</a-entity>

<script>
const sceneEl = document.getElementById('myScene');
const infoPanelEl = document.getElementById('infoPanel');
const panelTextEl = document.getElementById('panelText');
const cameraEl = document.getElementById('camera');
const prevButtonEl = document.getElementById('prevButton');
const nextButtonEl = document.getElementById('nextButton');

const numSpheres = 60;
const spread = 2000;
const targetWorldPosition = new THREE.Vector3();
const cameraWorldPosition = new THREE.Vector3();
const direction = new THREE.Vector3();
const panelPosition = new THREE.Vector3();

const PAGES = ['index', 'color', 'radius'];
const TOTAL_PAGES = PAGES.length;

// 球体生成 (変更なし)
for (let i = 0; i < numSpheres; i++) { /* ... */ const sphereEl = document.createElement('a-sphere'); const radius = Math.random() * 10.0 + 0.5; const x = (Math.random() - 0.5) * spread; const y = Math.random() * (spread / 2) + radius; const z = (Math.random() - 0.5) * spread; const color = `hsl(${Math.random() * 360}, 50%, 75%)`; const sphereIndex = i + 1; sphereEl.setAttribute('radius', radius); sphereEl.setAttribute('color', color); sphereEl.setAttribute('position', { x: x, y: y, z: z }); sphereEl.classList.add('clickableSphere'); sphereEl.dataset.sphereIndex = sphereIndex; sphereEl.dataset.color = color; sphereEl.dataset.radius = radius.toFixed(2); sphereEl.addEventListener('click', handleSphereClick); sceneEl.appendChild(sphereEl); }

// パネル表示更新関数 (変更なし)
function updatePanelDisplay() { if (!infoPanelEl.dataset.sphereIndex) return; const index = parseInt(infoPanelEl.dataset.sphereIndex || '0', 10); const color = infoPanelEl.dataset.color || 'N/A'; const radius = infoPanelEl.dataset.radius || 'N/A'; const pageIndex = parseInt(infoPanelEl.dataset.currentPageIndex || '0', 10); let displayText = ''; const pageType = PAGES[pageIndex]; if (pageType === 'index') { displayText = `球: ${index}`; } else if (pageType === 'color') { displayText = `色: ${color}`; } else if (pageType === 'radius') { displayText = `半径: ${radius}`; } const pageIndicator = `(${pageIndex + 1}/${TOTAL_PAGES})`; const finalDisplayText = `${pageIndicator}\n${displayText}`; panelTextEl.setAttribute('troika-text', 'value', finalDisplayText); }

// handleSphereClick (stopPropagation を含む)
function handleSphereClick(event) {
event.stopPropagation(); // イベント伝播停止

console.log("--- handleSphereClick triggered --- Target:", event.target.id || event.target.tagName);
const clickedSphere = event.target;
if (!clickedSphere.dataset.sphereIndex || !clickedSphere.dataset.color || !clickedSphere.dataset.radius) { console.error("Sphere data missing!"); return; }
console.log("Sphere data found:", clickedSphere.dataset);
infoPanelEl.dataset.sphereIndex = clickedSphere.dataset.sphereIndex;
infoPanelEl.dataset.color = clickedSphere.dataset.color;
infoPanelEl.dataset.radius = clickedSphere.dataset.radius;
infoPanelEl.dataset.currentPageIndex = '0';
console.log("Data stored in panel dataset.");
try { updatePanelDisplay(); console.log("updatePanelDisplay completed."); }
catch (e) { console.error("Error during updatePanelDisplay:", e); return; }
try { clickedSphere.object3D.getWorldPosition(targetWorldPosition); cameraEl.object3D.getWorldPosition(cameraWorldPosition); const sphereRadius = parseFloat(clickedSphere.dataset.radius || 0); const offsetDistance = sphereRadius + 0.5; direction.subVectors(cameraWorldPosition, targetWorldPosition).normalize(); panelPosition.copy(targetWorldPosition).addScaledVector(direction, offsetDistance); infoPanelEl.object3D.position.copy(panelPosition); console.log("Panel position calculated and applied."); }
catch(e) { console.error("Error during position calculation:", e); return; }
infoPanelEl.setAttribute('visible', true);
console.log("Panel visibility set to true. --- handleSphereClick end ---");
}

// {タンクリック時の処理 (stopPropagation を含む)
prevButtonEl.addEventListener('click', function (event) {
event.stopPropagation();
if (!infoPanelEl.getAttribute('visible')) return;
let pageIndex = parseInt(infoPanelEl.dataset.currentPageIndex || '0', 10);
pageIndex = (pageIndex - 1 + TOTAL_PAGES) % TOTAL_PAGES;
infoPanelEl.dataset.currentPageIndex = pageIndex.toString();
updatePanelDisplay();
console.log("Prev button clicked, page index:", pageIndex);
});

nextButtonEl.addEventListener('click', function (event) {
event.stopPropagation();
if (!infoPanelEl.getAttribute('visible')) return;
let pageIndex = parseInt(infoPanelEl.dataset.currentPageIndex || '0', 10);
pageIndex = (pageIndex + 1) % TOTAL_PAGES;
infoPanelEl.dataset.currentPageIndex = pageIndex.toString();
updatePanelDisplay();
console.log("Next button clicked, page index:", pageIndex);
});

// --- ★★★ 背景クリックでパネルを隠す処理を一時的に全体コメントアウト ★★★ ---
/*
sceneEl.addEventListener('click', function(event) {
if (!event.target.classList.contains('clickableSphere') &&
!event.target.classList.contains('clickableButton')) {
infoPanelEl.setAttribute('visible', false);
delete infoPanelEl.dataset.sphereIndex;
delete infoPanelEl.dataset.color;
delete infoPanelEl.dataset.radius;
delete infoPanelEl.dataset.currentPageIndex;
console.log("Panel hidden by background click.");
}
});
*/

</script>
</a-scene>
</body>
</html>


使用変数

-------( Function )
ameraWorldPosition
argetWorldPosition
at
attribute
background
begin
camera
cameraEl
class
clickedSphere
color
controls
currentPageIndex
currentVelocity
cursor
data
deltaPosition
desiredVelocity
direction
displayText
dot
dt
dur
easing
el
eraWorldQuaternion
event) { if -------( Function )
ffectiveLerpFactor
fill
finalDisplayText
from
geometry
handleSphereClick -------( Function )
height
i
id
index
infoPanelEl
isKeyPressed
isMoving
isOpposing
isReady
keys
lerpFactor
light
material
moveDirection
nextButtonEl
numSpheres
offsetDistance
onKeyDown
onKeyUp
opacity
pageIndex
pageIndicator
PAGES
pageType
panelPosition
panelTextEl
position
prevButtonEl
radius
raycaster
rightDirection
rotation
scale
sceneEl
side
sphereEl
sphereIndex
sphereRadius
spread
src
text
to
TOTAL_PAGES
updatePanelDisplay -------( Function )
visible
width
x
y
z
ZERO_VECTOR