| 1 |
<?xml version="1.0" encoding="UTF-8"?>
|
| 2 |
<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.0//EN" "https://www.web3d.org/specifications/x3d-3.0.dtd">
|
| 3 | <X3D profile='Immersive' version='3.0' xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' xsd:noNamespaceSchemaLocation='https://www.web3d.org/specifications/x3d-3.0.xsd'> |
| 4 | <head> |
| 5 | <meta name='title' content=' SliderFloatPrototype.x3d '/> |
| 6 | <meta name='description' content='A Slider prototype enabling mouse input where float output values are needed. Size, min/max values and color are defined by the author.'/> |
| 7 | <meta name='creator' content='Mike Hunsberger, Jane Wu'/> |
| 8 | <meta name='created' content='17 October 2001'/> |
| 9 | <meta name='modified' content='15 October 2023'/> |
| 10 | <meta name='subject' content='animation slider'/> |
| 11 | <meta name='identifier' content=' https://www.web3d.org/x3d/content/examples/Savage/Tools/Animation/SliderFloatPrototype.x3d '/> |
| 12 | <meta name='generator' content='X3D-Edit 4.0, https://www.web3d.org/x3d/tools/X3D-Edit'/> |
| 13 | <meta name='license' content='../../license.html'/> |
| 14 | </head> |
| 15 | <Scene> |
| 16 | <WorldInfo title='SliderFloatPrototype.x3d'/> |
| 17 | <ProtoDeclare name='SliderFloat' appinfo='Slider user-interface widget that produces floating-point output values'> |
| 18 | <ProtoInterface> |
| 19 |
<field name='layoutDirection' type='SFString' value='vertical' accessType='initializeOnly'
appinfo='Allowed values: vertical, horizontal'/> |
| 20 |
<field name='height' type='SFFloat' value='1.0' accessType='initializeOnly'
appinfo='default value 1.0'/> |
| 21 |
<field name='radius' type='SFFloat' value='0.1' accessType='initializeOnly'
appinfo='default value 0.1'/> |
| 22 |
<field name='barRadius' type='SFFloat' value='0.02' accessType='initializeOnly'
appinfo='default value 0.02'/> |
| 23 |
<field name='sliderBarColor' type='SFColor' value='.8 .4 .8' accessType='initializeOnly'
appinfo='default value .8 .4 .8'/> |
| 24 |
<field name='sliderBallColor' type='SFColor' value='.3 .4 .8' accessType='initializeOnly'
appinfo='default value .3 .4 .8'/> |
| 25 |
<field name='sliderEndColor' type='SFColor' value='.2 .3 .9' accessType='initializeOnly'
appinfo='default value .2 .3 .9'/> |
| 26 |
<field name='min' type='SFFloat' value='0.0' accessType='initializeOnly'
appinfo='default value 0.0'/> |
| 27 |
<field name='max' type='SFFloat' value='10.0' accessType='initializeOnly'
appinfo='default value 10.0'/> |
| 28 |
<field name='value' type='SFFloat' value='0.0' accessType='initializeOnly'
appinfo='default value 0.0'/> |
| 29 |
<field name='setMin' type='SFFloat' accessType='inputOnly'
appinfo='set minimum value for slider bar'/> |
| 30 |
<field name='setMax' type='SFFloat' accessType='inputOnly'
appinfo='set maximum value for slider bar'/> |
| 31 |
<field name='setValue' type='SFFloat' accessType='inputOnly'
appinfo='set value for slider bar'/> |
| 32 |
<field name='valueChanged' type='SFFloat' accessType='outputOnly'
appinfo='output value for slider bar'/> |
| 33 |
<field name='traceEnabled' type='SFBool' value='false' accessType='initializeOnly'
appinfo='enable/disable console output for troubleshooting'/> |
| 34 | </ProtoInterface> |
| 35 | <ProtoBody> |
| 36 | <Group> |
| 37 |
<!-- ROUTE information for LayoutDirectionTransform node:
[from LayoutDirectionScript.directionRotation to set_rotation
]
-->
<Transform DEF='LayoutDirectionTransform'> |
| 38 | <Transform DEF='SliderBarTransform'> |
| 39 | <Shape> |
| 40 | <Appearance> |
| 41 | <Material DEF='SliderBarMaterial'> |
| 42 | <IS> |
| 43 | <connect nodeField='diffuseColor' protoField='sliderBarColor'/> |
| 44 | <connect nodeField='emissiveColor' protoField='sliderBarColor'/> |
| 45 | </IS> |
| 46 | </Material> |
| 47 | </Appearance> |
| 48 | <Cylinder DEF='SliderBar'> |
| 49 | <IS> |
| 50 | <connect nodeField='height' protoField='height'/> |
| 51 | <connect nodeField='radius' protoField='barRadius'/> |
| 52 | </IS> |
| 53 | </Cylinder> |
| 54 | </Shape> |
| 55 | </Transform> |
| 56 |
<!-- ROUTE information for SliderBallTransform node:
[from SliderScript.ballPositionChanged to set_translation
]
-->
<Transform DEF='SliderBallTransform'> |
| 57 |
<!-- ROUTE information for SliderBallPlaneSensor node:
[from SliderScript.minBallPositionChanged to set_minPosition
]
[from SliderScript.maxBallPositionChanged to set_maxPosition
]
[from translation_changed to SliderScript.setBallPosition
]
-->
<PlaneSensor DEF='SliderBallPlaneSensor' description='select and drag to change values'/> |
| 58 | <Shape> |
| 59 | <Appearance> |
| 60 | <Material DEF='SliderBallMaterial'> |
| 61 | <IS> |
| 62 | <connect nodeField='diffuseColor' protoField='sliderBallColor'/> |
| 63 | </IS> |
| 64 | </Material> |
| 65 | </Appearance> |
| 66 | <Sphere DEF='SliderBall'> |
| 67 | <IS> |
| 68 | <connect nodeField='radius' protoField='radius'/> |
| 69 | </IS> |
| 70 | </Sphere> |
| 71 | </Shape> |
| 72 | </Transform> |
| 73 |
<!-- ROUTE information for BottomEndTransform node:
[from SliderScript.bottomEndPositionChanged to set_translation
]
-->
<Transform DEF='BottomEndTransform'> |
| 74 |
<!-- ROUTE information for BottomEndSensor node:
[from isActive to SliderScript.bottomEndTouched
]
-->
<TouchSensor DEF='BottomEndSensor' description='touch bottom end to decrement'/> |
| 75 | <Shape> |
| 76 | <Appearance> |
| 77 | <Material> |
| 78 | <IS> |
| 79 | <connect nodeField='diffuseColor' protoField='sliderEndColor'/> |
| 80 | </IS> |
| 81 | </Material> |
| 82 | </Appearance> |
| 83 | <Cylinder height='.05' radius='.1'/> |
| 84 | </Shape> |
| 85 | <Transform translation='0 -0.1 0'> |
| 86 |
<!-- Shape
TransparentEndShape is a DEF node that has 1 USE node: USE_1 -->
<Shape DEF='TransparentEndShape'> |
| 87 | <Appearance> |
| 88 | <Material transparency='1'/> |
| 89 | </Appearance> |
| 90 | <Box size='0.2 0.2 0.01'/> |
| 91 | </Shape> |
| 92 | </Transform> |
| 93 | </Transform> |
| 94 |
<!-- ROUTE information for TopEndTransform node:
[from SliderScript.topEndPositionChanged to set_translation
]
-->
<Transform DEF='TopEndTransform'> |
| 95 |
<!-- ROUTE information for TopEndSensor node:
[from isActive to SliderScript.topEndTouched
]
-->
<TouchSensor DEF='TopEndSensor' description='touch top end to increment'/> |
| 96 | <Shape> |
| 97 | <Appearance> |
| 98 | <Material> |
| 99 | <IS> |
| 100 | <connect nodeField='diffuseColor' protoField='sliderEndColor'/> |
| 101 | </IS> |
| 102 | </Material> |
| 103 | </Appearance> |
| 104 | <Cylinder height='.05' radius='.1'/> |
| 105 | </Shape> |
| 106 | <Transform translation='0 0.1 0'> |
| 107 | <Shape USE='TransparentEndShape'/> |
| 108 | </Transform> |
| 109 | </Transform> |
| 110 |
<!-- ROUTE information for SliderScript node:
[from SliderBallPlaneSensor.translation_changed to setBallPosition
]
[from BottomEndSensor.isActive to bottomEndTouched
]
[from TopEndSensor.isActive to topEndTouched
]
[from minBallPositionChanged to SliderBallPlaneSensor.set_minPosition
]
[from maxBallPositionChanged to SliderBallPlaneSensor.set_maxPosition
]
[from bottomEndPositionChanged to BottomEndTransform.set_translation
]
[from topEndPositionChanged to TopEndTransform.set_translation
]
[from ballPositionChanged to SliderBallTransform.set_translation
]
-->
<Script DEF='SliderScript'> |
| 111 | <!-- local variables --> |
| 112 | <field name='height' type='SFFloat' accessType='initializeOnly'/> |
| 113 | <field name='radius' type='SFFloat' accessType='initializeOnly'/> |
| 114 | <field name='min' type='SFFloat' accessType='initializeOnly'/> |
| 115 | <field name='max' type='SFFloat' accessType='initializeOnly'/> |
| 116 | <field name='value' type='SFFloat' accessType='initializeOnly'/> |
| 117 | <field name='lastBallPosition' type='SFVec3f' value='0 0 0' accessType='initializeOnly'/> |
| 118 | <field name='beginPosition' type='SFVec3f' value='0 0 0' accessType='initializeOnly'/> |
| 119 | <field name='endPosition' type='SFVec3f' value='0 1 0' accessType='initializeOnly'/> |
| 120 | <field name='incrementInterval' type='SFFloat' value='0.1' accessType='initializeOnly'/> |
| 121 | <field name='setMin' type='SFFloat' accessType='inputOnly'/> |
| 122 | <field name='setMax' type='SFFloat' accessType='inputOnly'/> |
| 123 | <field name='setValue' type='SFFloat' accessType='inputOnly'/> |
| 124 | <field name='valueChanged' type='SFFloat' accessType='outputOnly'/> |
| 125 | <field name='bottomEndTouched' type='SFBool' accessType='inputOnly'/> |
| 126 | <field name='topEndTouched' type='SFBool' accessType='inputOnly'/> |
| 127 | <field name='setBallPosition' type='SFVec3f' accessType='inputOnly'/> |
| 128 | <field name='bottomEndPositionChanged' type='SFVec3f' accessType='outputOnly'/> |
| 129 | <field name='topEndPositionChanged' type='SFVec3f' accessType='outputOnly'/> |
| 130 | <field name='ballPositionChanged' type='SFVec3f' accessType='outputOnly'/> |
| 131 | <field name='minBallPositionChanged' type='SFVec2f' accessType='outputOnly'/> |
| 132 | <field name='maxBallPositionChanged' type='SFVec2f' accessType='outputOnly'/> |
| 133 | <field name='partialIncrement' type='SFFloat' value='0.0' accessType='initializeOnly'/> |
| 134 | <field name='traceEnabled' type='SFBool' accessType='initializeOnly'/> |
| 135 | <IS> |
| 136 | <connect nodeField='height' protoField='height'/> |
| 137 | <connect nodeField='radius' protoField='radius'/> |
| 138 | <connect nodeField='min' protoField='min'/> |
| 139 | <connect nodeField='max' protoField='max'/> |
| 140 | <connect nodeField='value' protoField='value'/> |
| 141 | <connect nodeField='setMin' protoField='setMin'/> |
| 142 | <connect nodeField='setMax' protoField='setMax'/> |
| 143 | <connect nodeField='setValue' protoField='setValue'/> |
| 144 | <connect nodeField='valueChanged' protoField='valueChanged'/> |
| 145 | <connect nodeField='traceEnabled' protoField='traceEnabled'/> |
| 146 | </IS> |
<![CDATA[
ecmascript:
function initialize()
{
tracePrint('initialize() commenced...');
beginPosition = new SFVec3f(0, (height/2) * (-1) + radius, 0);
endPosition = new SFVec3f(0, (height/2) - radius, 0);
tracePrint('beginPosition=' + beginPosition.toString() + ', endPosition=' + endPosition.toString());
incrementInterval = (height - (2 * radius)) / (max - min);
tracePrint('incrementInterval=' + incrementInterval.toString());
bottomEndPositionChanged = new SFVec3f(0, (height/2) * (-1), 0);
topEndPositionChanged = new SFVec3f(0, (height/2), 0);
tracePrint('bottomEndPositionChanged=' + bottomEndPositionChanged.toString() + ', topEndPositionChanged=' + topEndPositionChanged.toString());
minBallPositionChanged = new SFVec2f(0, bottomEndPositionChanged.y + radius);
maxBallPositionChanged = new SFVec2f(0, topEndPositionChanged.y - radius);
tracePrint('minBallPositionChanged=' + minBallPositionChanged.toString() + ', maxBallPositionChanged=' + maxBallPositionChanged.toString());
ballPositionChanged = new SFVec3f(0, beginPosition.y + (incrementInterval * (value - min)), 0);
lastBallPosition = ballPositionChanged;
if (value < min) value = min;
if (value > max) value = max;
valueChanged = value;
tracePrint('value=' + value.toString());
tracePrint('...initialize() complete');
}
function setMin(inputValue, timeStamp)
{
min = inputValue;
if (value < min) value = min;
incrementInterval = (height - (2 * radius)) / (max - min);
tracePrint('incrementInterval=' + incrementInterval.toString());
ballPositionChanged = new SFVec3f(0, beginPosition.y + (incrementInterval * (value - min)), 0);
lastBallPosition = ballPositionChanged;
valueChanged = value;
tracePrint('min=' + min + ', valueChanged=' + valueChanged);
}
function setMax(inputValue, timeStamp)
{
max = inputValue;
if (value > max) value = max;
incrementInterval = (height - (2 * radius)) / (max - min);
tracePrint('incrementInterval=' + incrementInterval.toString());
ballPositionChanged = new SFVec3f(0, beginPosition.y + (incrementInterval * (value - min)), 0);
lastBallPosition = ballPositionChanged;
valueChanged = value;
tracePrint('max=' + max + ', valueChanged=' + valueChanged);
}
function setValue(inputValue, timeStamp)
{
if (inputValue <= min)
{
valueChanged = value = min;
ballPositionChanged = beginPosition;
lastBallPosition = ballPositionChanged;
}
else if (inputValue >= max)
{
valueChanged = value = max;
ballPositionChanged = endPosition;
lastBallPosition = ballPositionChanged;
}
else
{
if (inputValue > value) //getting bigger
{
ballPositionChanged = new SFVec3f(0, lastBallPosition.y + (incrementInterval * (inputValue - value)), 0);
lastBallPosition = ballPositionChanged;
}
else if (inputValue < value) //getting smaller
{
ballPositionChanged = new SFVec3f(0, lastBallPosition.y - (incrementInterval * (value - inputValue)), 0);
lastBallPosition = ballPositionChanged;
}
valueChanged = value = inputValue;
}
tracePrint('valueChanged=' + valueChanged);
}
function bottomEndTouched(inputValue, timeStamp)
{
tracePrint('bottomEndTouched(' + inputValue.toString() + ')');
if (inputValue == false) return; // ignore deselection
if (value <= Math.round(value))
value = Math.round(value);
else
value = Math.round(value) + 1;
partialIncrement = incrementInterval * (valueChanged - (value - 1));
if (value > min)
{
valueChanged = --value;
if (partialIncrement != incrementInterval)
{
ballPositionChanged = new SFVec3f(0, lastBallPosition.y - partialIncrement, 0);
partialIncrement = incrementInterval;
}
else ballPositionChanged = new SFVec3f(0, lastBallPosition.y - incrementInterval, 0);
lastBallPosition = ballPositionChanged;
}
}
function topEndTouched(inputValue, timeStamp)
{
tracePrint('topEndTouched(' + inputValue.toString() + ')');
if (inputValue == false) return; // ignore deselection
if (value < Math.round(value))
value = Math.round(value) - 1;
else value = Math.round(value);
partialIncrement = incrementInterval * (value + 1 - valueChanged);
if (value < max)
{
valueChanged = ++value;
if (partialIncrement != incrementInterval)
{
ballPositionChanged = new SFVec3f(0, lastBallPosition.y + partialIncrement, 0);
partialIncrement = incrementInterval;
}
else ballPositionChanged = new SFVec3f(0, lastBallPosition.y + incrementInterval, 0);
lastBallPosition = ballPositionChanged;
}
}
function setBallPosition(inputValue, timeStamp)
{
tracePrint('setBallPosition(' + inputValue.toString() + ')');
if (inputValue.y > lastBallPosition.y) // moving upwards
{
if (value >= max)
{
value = max;
lastBallPosition = endPosition;
}
else
{
value = (inputValue.y - beginPosition.y) * ((max - min) / (endPosition.y - beginPosition.y));
lastBallPosition = inputValue;
}
valueChanged = value;
ballPositionChanged = lastBallPosition;
}
else if (inputValue.y < lastBallPosition.y) // moving downwards
{
if (value <= min)
{
value = min;
lastBallPosition = beginPosition;
}
else
{
value = (inputValue.y - beginPosition.y) * ((max - min) / (endPosition.y - beginPosition.y));
lastBallPosition = inputValue;
}
valueChanged = value;
ballPositionChanged = lastBallPosition;
}
}
function tracePrint (text)
{
if (traceEnabled) Browser.println ('[SliderFloat SliderScript] ' + text);
}
]]>
|
|
| 148 | </Script> |
| 149 | < ROUTE fromNode='SliderBallPlaneSensor' fromField='translation_changed' toNode='SliderScript' toField='setBallPosition'/> |
| 150 | < ROUTE fromNode='BottomEndSensor' fromField='isActive' toNode='SliderScript' toField='bottomEndTouched'/> |
| 151 | < ROUTE fromNode='TopEndSensor' fromField='isActive' toNode='SliderScript' toField='topEndTouched'/> |
| 152 | < ROUTE fromNode='SliderScript' fromField='minBallPositionChanged' toNode='SliderBallPlaneSensor' toField='set_minPosition'/> |
| 153 | < ROUTE fromNode='SliderScript' fromField='maxBallPositionChanged' toNode='SliderBallPlaneSensor' toField='set_maxPosition'/> |
| 154 | < ROUTE fromNode='SliderScript' fromField='bottomEndPositionChanged' toNode='BottomEndTransform' toField='set_translation'/> |
| 155 | < ROUTE fromNode='SliderScript' fromField='topEndPositionChanged' toNode='TopEndTransform' toField='set_translation'/> |
| 156 | < ROUTE fromNode='SliderScript' fromField='ballPositionChanged' toNode='SliderBallTransform' toField='set_translation'/> |
| 157 | </Transform> |
| 158 |
<!-- ROUTE information for LayoutDirectionScript node:
[from directionRotation to LayoutDirectionTransform.set_rotation
]
-->
<Script DEF='LayoutDirectionScript'> |
| 159 | <field name='direction' type='SFString' accessType='initializeOnly'/> |
| 160 | <field name='directionRotation' type='SFRotation' accessType='outputOnly'/> |
| 161 | <field name='traceEnabled' type='SFBool' accessType='initializeOnly'/> |
| 162 | <IS> |
| 163 | <connect nodeField='direction' protoField='layoutDirection'/> |
| 164 | <connect nodeField='traceEnabled' protoField='traceEnabled'/> |
| 165 | </IS> |
<![CDATA[
ecmascript:
function initialize ()
{
if ((direction=='vertical') || (direction=='Vertical') || (direction=='VERTICAL'))
{
directionRotation = new SFRotation(0, 0, 1, 0);
}
else if ((direction=='horizontal') || (direction=='Horizontal') || (direction=='HORIZONTAL'))
{
directionRotation = new SFRotation(0, 0, 1, -1.57);
}
else
{
Browser.println ('[SliderFloat LayoutDirectionScript] unrecognized direction: ' + direction + ', using vertical');
directionRotation = new SFRotation(0, 0, 1, 0);
}
tracePrint ('direction=' + direction);
}
function tracePrint (text)
{
if (traceEnabled) Browser.println ('[SliderFloat LayoutDirectionScript] ' + text);
}
]]>
|
|
| 167 | </Script> |
| 168 | < ROUTE fromNode='LayoutDirectionScript' fromField='directionRotation' toNode='LayoutDirectionTransform' toField='set_rotation'/> |
| 169 | </Group> |
| 170 | </ProtoBody> |
| 171 | </ProtoDeclare> |
| 172 | <!-- ==================== --> |
| 173 | <Anchor description='SliderFloatExample' parameter='"target=_blank"' url=' "SliderFloatExample.x3d" "https://www.web3d.org/x3d/content/examples/Savage/Tools/Animation/SliderFloatExample.x3d" "SliderFloatExample.wrl" "https://www.web3d.org/x3d/content/examples/Savage/Tools/Animation/SliderFloatExample.wrl" '> |
| 174 | <Shape> |
| 175 | <Appearance> |
| 176 | <Material diffuseColor='0 1 1' emissiveColor='0 1 1'/> |
| 177 | </Appearance> |
| 178 | <Text string='"SliderFloatPrototype" "is a Prototype definition file." "" "To see an example scene" "select this text and view" "SliderFloatExample"'> |
| 179 | <FontStyle justify='"MIDDLE" "MIDDLE"' size='0.8'/> |
| 180 | </Text> |
| 181 | </Shape> |
| 182 | </Anchor> |
| 183 | </Scene> |
| 184 | </X3D> |
Event Graph ROUTE Table entries with 9 ROUTE connections total, showing X3D event-model relationships for this scene.
Each row shows an event cascade that may occur during a single timestamp interval between frame renderings, as part of the X3D execution model.
|
LayoutDirectionScript
Script directionRotation SFRotation |
LayoutDirectionTransform
Transform set_rotation SFRotation |
| line 173
Anchor |
description='SliderFloatExample' User-interaction hint for this node. |
<!--
Color-coding legend: X3D terminology
<X3dNode
DEF='idName' field='value'/>
matches XML terminology
<XmlElement
DEF='idName' attribute='value'/>
(Light-blue background: event-based behavior node or statement)
(Grey background inside box: inserted documentation)
(Magenta background: X3D Extensibility)
<ProtoDeclare name='ProtoName'>
<field
name='fieldName'/> </ProtoDeclare>
-->
<!--
For additional help information about X3D scenes, please see X3D Tooltips, X3D Resources, and X3D Scene Authoring Hints.
-->