update fileformat

- don’t include images guides
- don’t store sketch data and app version in object
This commit is contained in:
casperlamboo 2018-02-14 14:52:16 +01:00
parent 12ba7f624f
commit da12939253
7 changed files with 111 additions and 82 deletions

View File

@ -58,7 +58,8 @@ window.addEventListener('keydown',(event) => {
// add model to store
import modelData from './models/circle_error.d3sketch';
import JSONToSketchData from './src/shape/JSONToSketchData.js';
JSONToSketchData(JSON.parse(modelData)).then(data => {
const { data, appVersion } = JSON.parse(modelData);
JSONToSketchData(data, appVersion).then(data => {
store.dispatch(actions.openSketch({ data }));
});

View File

@ -99,8 +99,8 @@ class App extends React.Component {
case 'D3SKETCH':
case 'JSON':
const url = URL.createObjectURL(file);
const data = await fetch(url).then(result => result.json());
const sketchData = await JSONToSketchData(data);
const { data, appVersion } = await fetch(url).then(result => result.json());
const sketchData = await JSONToSketchData(data, appVersion);
openSketch({ data: sketchData });
break;
case 'JPG':

View File

@ -37,7 +37,7 @@ class DoodlePreview extends React.Component {
sketchData: PropTypes.object, // TODO
docData: PropTypes.shape({
appVersion: PropTypes.string,
data: PropTypes.string
data: PropTypes.oneOf([PropTypes.string, PropTypes.object])
})
};
@ -48,7 +48,7 @@ class DoodlePreview extends React.Component {
async componentWillMount() {
let { docData, sketchData } = this.props;
if (docData) sketchData = await JSONToSketchData(this.props.docData);
if (docData) sketchData = await JSONToSketchData(docData.data, docData.appVersion);
const { canvas } = this.refs;

View File

@ -1,6 +1,6 @@
import * as contextTools from './contextTools.js';
export const VERSION = '0.17.4';
export const VERSION = '0.18.0';
export const SHAPE_CACHE_LIMIT = 50;
export const PIXEL_RATIO = 1.0;

View File

@ -5,47 +5,71 @@ import { recursivePromiseApply } from '../utils/async.js';
import { base64ToImage, base64ToVectorArray } from '../utils/binaryUtils.js';
import { LEGACY_HEIGHT_STEP } from '../constants/d3Constants.js';
export default async function JSONToSketchData({ data, appVersion }) {
let sketchData = JSON.parse(data, (key, value) => {
if (semver.lt(appVersion, '0.1.2')) {
if (key === 'imageData') {
export function recursiveMap(objects, reviver) {
const newObjects = {};
for (const i in objects) {
if (!objects.hasOwnProperty(i)) continue;
let object = objects[i];
if (typeof object === 'object') {
object = recursiveMap(object, reviver);
}
object = reviver(i, object) || object;
newObjects[i] = object;
}
return newObjects;
}
function revive(appVersion, key, value) {
if (semver.lt(appVersion, '0.1.2')) {
if (key === 'imageData') {
return base64ToImage(value);
}
}
if (value.metadata && value.metadata.type) {
switch (value.metadata.type) {
case 'Vector':
return new Vector().fromJSON(value);
case 'Matrix':
return new Matrix().fromJSON(value);
case 'VectorArray':
return base64ToVectorArray(value);
case 'Image':
return base64ToImage(value);
}
case 'Matrix4':
return new Matrix4().copy(value);
case 'Color':
return new Color(value.data).getHex();
default:
break;
}
if (value.metadata && value.metadata.type) {
switch (value.metadata.type) {
case 'Vector':
return new Vector().fromJSON(value);
case 'Matrix':
return new Matrix().fromJSON(value);
case 'VectorArray':
return base64ToVectorArray(value);
case 'Image':
return base64ToImage(value);
case 'Matrix4':
return new Matrix4().copy(value);
case 'Color':
return new Color(value.data).getHex();
default:
break;
}
return value;
}
// legacy, convert { r: Float, g: Float, b: Float } to hex
if (typeof value.r === 'number' && typeof value.g === 'number' && typeof value.b === 'number') {
return new Color(value.r, value.g, value.b).getHex();
}
return value;
});
}
// legacy, convert { r: Float, g: Float, b: Float } to hex
if (typeof value.r === 'number' && typeof value.g === 'number' && typeof value.b === 'number') {
return new Color(value.r, value.g, value.b).getHex();
}
return value;
}
export default async function JSONToSketchData(data, appVersion) {
let sketchData;
if (semver.gt(appVersion, '0.17.4')) {
sketchData = recursiveMap(data, (key, value) => revive(appVersion, key, value));
} else {
sketchData = JSON.parse(data.data, (key, value) => revive(appVersion, key, value));
}
sketchData = await recursivePromiseApply(sketchData);
if (semver.lt(appVersion, '0.4.0')) {

View File

@ -26,7 +26,8 @@ export default async function docToFile(db, doc, { image = false, sketch = false
throw new Error(`'${doc.name}' doesn't include sketch attachment`);
}
const data = await blobToJSON(doc._attachments.sketch.data);
response.data = await JSONToSketchData(data);
response.data = await JSONToSketchData(data, appVersion);
} else {
const data = { data: doc.data, appVersion };
response.data = await JSONToSketchData(data);

View File

@ -1,49 +1,55 @@
import { vectorArrayToBase64, imageToBase64 } from '../utils/binaryUtils.js';
import { VERSION } from '../constants/general.js';
function createShapeData(shape) {
shape = { ...shape };
delete shape.UID;
delete shape.space;
switch (shape.type) {
case 'POLYGON':
case 'BRUSH':
case 'FREE_HAND': {
shape.points = vectorArrayToBase64(shape.points);
break;
}
case 'COMPOUND_PATH': {
shape.points = vectorArrayToBase64(shape.points);
shape.holes = shape.holes.map(vectorArrayToBase64);
break;
}
case 'IMAGE_GUIDE': {
shape.imageData = imageToBase64(shape.imageData);
break;
}
default: {
break;
}
}
return shape;
}
export default function sketchDataToJSON({ objectsById, spaces }) {
const mapToShapes = id => objectsById[id];
const filter = (shape) => {
if (shape.type === 'IMAGE_GUIDE') return false;
return true;
};
const data = {
spaces: []
};
function createShapeData(id) {
const shape = { ...objectsById[id] };
delete shape.UID;
delete shape.space;
switch (shape.type) {
case 'POLYGON':
case 'BRUSH':
case 'FREE_HAND': {
shape.points = vectorArrayToBase64(shape.points);
break;
}
case 'COMPOUND_PATH': {
shape.points = vectorArrayToBase64(shape.points);
shape.holes = shape.holes.map(vectorArrayToBase64);
break;
}
case 'IMAGE_GUIDE': {
shape.imageData = imageToBase64(shape.imageData);
break;
}
default: {
break;
}
}
return shape;
}
for (const spaceId in spaces) {
const space = {
matrix: {
metadata: { type: 'Matrix4', library: 'three.js' },
elements: Array.from(spaces[spaceId].matrix.elements)
},
objects: spaces[spaceId].objectIds.map(createShapeData)
objects: spaces[spaceId].objectIds.map(mapToShapes).filter(filter).map(createShapeData)
};
if (spaceId === 'world') {
@ -53,8 +59,5 @@ export default function sketchDataToJSON({ objectsById, spaces }) {
}
}
return {
data: JSON.stringify(data),
appVersion: VERSION
};
return data;
}