A D3.js(v7) based geologic timeline&timeScale&timeSlider
Zoom:
Use the mouse wheel to control zoom, double-click to zoom in.Adjustment:
Hold down the left button to drag the timeline.Location:
Left click the timeline to move the handler quickly, or drag to move the handler.
Location:
Left click the geo stage to quick location.Zoom:
Use the mouse wheel to control zoom in or zoom out.
Drag
: Drag the slider to change the time.Click
: Click on the square to change the time range.
For node.js
#npm
npm install --save @zjugis/geo-timeline
#yarn
yarn add @zjugis/geo-timeline
For legacy environments, you can load @zjugis/geo-timeline’s UMD bundle from an npm-based CDN such as jsDelivr; a timeLine
global is exported:
<script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
<script src="//unpkg.com/@zjugis/geo-timeline@latest"></script>
<script>
fetch('./test/GTS_2020.json').then(async res => {
const intervals = await res.json()
new timeLine.GeoTimeLine("#geoTimeLineContainer", intervals)
new timeLine.GeoTimeScale("#geoTimeScaleContainer", intervals)
new timeLine.GeoTimeSlider("#geoTimeSliderContainer", intervals)
})
</script>
For node.js
import { GeoTimeLine, GeoTimeScale } from "@zjugis/geo-timeline";
fetch('./test/GTS_2020.json').then(async res => {
const intervals = await res.json()
// create geotimeline obj
const geoTimeLine = new GeoTimeLine("#geoTimeContainer", intervals, {
onChange: function(time, level) {
// do something
},
// determin interval by time
intervalSum: d => d.leaf ? d.start - d.end : 0
});
// It is recommended to set the time after changing the level
geoTimeLine.level = 2
geoTimeLine.time = 2000
// create geotimescale obj
const geoTimeScale = new GeoTimeScale("#geoTimeScale-simple", intervals, {
onChange: val => console.log(val),
// only show 2 levels once
simplify: true,
height: 70,
})
// set stage
geoTimeScale.stage = 'Cambrian'
// create geotimeslider obj
const geoTimeSlider = new GeoTimeSlider("#geoTimeSlider", intervals, {
// do something when time range is changed
onChange: val => console.log(val),
})
// set time range
geoTimeSlider.timeRange = [300, 100]
})
class GeoTimeLine {
/** text font */
readonly font: string;
/** interval data's max level */
readonly maxLevel: number;
/** svg object */
readonly svg: Selection<SVGSVGElement, unknown, HTMLElement, any>;
/** interval data */
readonly intervals: IntervalItem[];
/** hierarchical data generated by intervals */
readonly hierarchicalData: HierarchyNode<IntervalItem>;
/** the root hierarchical data */
readonly root: NodeItem;
/** user input options */
readonly options: GeoTimeLineOptions
/**
* Create a GeoTimeLine
* @param selector CSS selector string
* @param intervals geo time intervals array
* @param options GeoTimeLine options
*/
constructor(selector: string | BaseType, intervals: IntervalItem[], options?: GeoTimeLineOptions);
/** get or set time */
get time(): number;
set time(val: number);
/** get or set level */
get level(): number;
set level(val: number);
get ready(): boolean;
}
/**
* BaseType serves as an alias for the 'minimal' data type which can be selected
* without 'd3-selection' trying to use properties internally which would otherwise not
* be supported.
*/
type BaseType = Element | EnterElement | Document | Window | null;
interface GeoTimeLineOptions {
/** geo time intervals array */
intervals: IntervalItem[];
/** svg width, defaults to container's width */
width?: number;
/** svg height, defaults to 70 */
height?: number;
/** font size, defaults to 16px */
fontSize?: number;
/** font family, defaults to 'sans-serif' */
fontFamily?: string;
/** callback when handle's position or scale level changed */
onChange?: (time: number, level: number) => void;
/** dispatch when mouseup or zoom */
onAfterChange?: (time: number, level: number) => void;
/** defaults to {
top: 0, right: 0, bottom: 0, left: 0,
} */
margin?: {
top?: number;
bottom?: number;
left?: number;
right?: number;
}
/** defaults to {
top: 0, right: 0, bottom: 0, left: 0,
} */
padding?: {
top?: number;
bottom?: number;
left?: number;
right?: number;
}
/** initial time, defaults to 0 */
time?: number;
/** animation time, defaults to 450ms */
transition?: number;
/** interval transform setting, defaults to (d) => d.leaf ? 1 : 0 */
intervalSum?: (d: IntervalItem) => number;
/** min zoom level */
minZoom?: number;
/** max zoom level, defaults to 10 */
maxZoom?: number;
}
/** geo time data intervals schema **/
type IntervalItem = {
id: number;
name: string;
abbr?: string;
color: string;
textColor?: string;
end: number;
start: number;
level?: number;
parentId?: number;
leaf?: boolean;
}
class GeoTimeLine {
/** text font */
readonly font: string;
/** svg object */
readonly svg: Selection<SVGSVGElement, unknown, HTMLElement, any>;
/** interval data */
readonly intervals: IntervalItem[];
/** hierarchical data generated by intervals */
readonly hierarchicalData: HierarchyNode<IntervalItem>;
/** the root hierarchical data */
readonly root: NodeItem;
/** user input options */
readonly options: GeoTimeScaleOptions;
/**
* Create a GeoTimeScale
* @param selector CSS selector string
* @param intervals geo time intervals array
* @param options GeoTimeScale options
*/
constructor(selector: string | BaseType, intervals: IntervalItem[], options?: GeoTimeScaleOptions);
/** get or set animation transition time */
transition: number;
/** get or set focused stage
* @example
* geoTimeScale.stage = 'Cambrian'
*/
get stage(): string;
set stage(val: string);
get sequence(): NodeItem[];
get ready(): boolean;
}
interface GeoTimeScaleOptions {
/** geo time intervals array */
intervals: IntervalItem[];
/** svg width, defaults to container's width */
width?: number;
/** svg height, defaults to 400px */
height?: number;
/** font size, defaults to 12px */
fontSize?: number;
/** font family, defaults to 'sans-serif' */
fontFamily?: string;
/** callback when handle's position or scale level changed */
onChange?: (node: NodeItem) => void;
/** defaults to {
top: 0, right: 0, bottom: 0, left: 0,
} */
margin?: MarginOpts;
/** defaults to {
top: 0, right: 0, bottom: 0, left: 0,
} */
padding?: MarginOpts;
/** animation time, defaults to 450ms */
transition?: number;
/** interval transform setting, defaults to d => d.leaf ? d.start - d.end : 0 */
intervalSum?: (d: IntervalItem) => number;
/** simplify show 2 levels or not, defaults to false */
simplify?: boolean;
/** focused node's neighbor node width, defaults to 100px */
neighborWidth?: number;
/** tick length, defaults to 15px */
tickLength?: number;
}
class GeoTimeSlider {
/** text font */
readonly font: string;
/** svg object */
readonly svg: any;
/** interval data */
readonly intervals: IntervalItem[];
/** hierarchical data generated by intervals */
readonly hierarchicalData: HierarchyNode<IntervalItem>;
/** the root hierarchical data */
readonly root: SliderNodeItem;
/** user input options */
readonly options: Required<GeoTimeSliderOptions>;
/** get or set animation transition time */
transition: number;
readonly startEnd: number[];
/**
* Create a GeoTimeSlider
* @param {string | BaseType} selector CSS selector string
* @param {IntervalItem[]} intervals geo time intervals array
* @param {number} [options.width] svg width, defaults to container's width
* @param {number} [options.height = 400] svg height, defaults to 400px
* @param {number} [options.fontSize = 12] font size, defaults to 12px
* @param {string} [options.fontFamily = 'sans-serif'] font family, defaults to 'sans-serif'
* @param {Function} [options.onChange] callback when focused node change
* @param {Object} [options.margin] svg margin, defaults to { top: 0, right: 0, bottom: 0, left: 0 }
* @param {Object} [options.padding] svg padding, defaults to { top: 0, right: 0, bottom: 0, left: 0 }
* @param {number} [options.transition = 300] animation time, defaults to 300ms
* @param {Function} [options.intervalSum] interval transform setting, defaults to d => d.leaf ? d.start - d.end : 0
* @param {boolean} [options.simplify = true] simplify show 2 levels or not
* @param {number} [options.neighborWidth = 100] focused node's neighbor node width, defaults to 100px
* @param {number} [options.tickLength = 15] tick length, defaults to 15px
* @param {number} [options.tickHeight = 30] tick height, defaults to 30px
* @param {string} [options.unit = ''] tick value unit
*/
constructor(selector: string | BaseType, intervals: IntervalItem[], options?: GeoTimeSliderOptions);
/** get or set focused stage
* @example
* geoTimeScale.stage = 'Cambrian'
*/
get stage(): string | undefined;
set stage(val: string);
get sliderPosition(): number[];
get timeRange(): number[];
set timeRange(range: number[]);
get ready(): boolean;
}
interface GeoTimeSliderOptions {
/** svg width, defaults to container's width */
width?: number;
/** svg height, defaults to 400px */
height?: number;
/** font size, defaults to 12px */
fontSize?: number;
/** font family, defaults to 'sans-serif' */
fontFamily?: string;
/** callback when handle's position or scale level changed */
onChange?: (timeRange: number[]) => void;
/** defaults to {
top: 0, right: 0, bottom: 0, left: 0,
} */
margin?: MarginOpts;
/** defaults to {
top: 0, right: 0, bottom: 0, left: 0,
} */
padding?: MarginOpts;
/** animation time, defaults to 300ms */
transition?: number;
/** interval transform setting, defaults to d => d.leaf ? d.start - d.end : 0 */
intervalSum?: (d: IntervalItem) => number;
/** focused node's neighbor node width, defaults to 100px */
neighborWidth?: number;
/** tick length, defaults to 15px */
tickLength?: number;
/** tick height, defaults to 30px */
tickHeight?: number;
/** tick value unit */
unit?: string;
}
The interval item's schema like follow:
{
"id": 753,
"name": "Archean",
"level": 1,
"parentId": 0,
"color": "#F0047F",
"end": 2500,
"start": 4000
}
Run the command:
pnpm dev
And then Launch index.html with node server, if use VS Code, suggest the Live Server
extension.
Run test:
pnpm test